前言
针对表格展示数据,用户提出要求前端在表格下面有一展示多少条数据的选项,如果要求一次性展示10000条数据,如果直接染会造成页面的卡顿,渲染速度下降,内容展示慢,如果有操作,操作会卡顿
下面总结常见的几种大数据渲染方案
虚拟列表渲染
用虚拟列表的手段,即先对设置的可见区域内的数据进行演染,然后计算出鼠标滚动距离大约是滚动了多少项,通过动态的设置距离顶部的top值达到可见区域动态染数据不会卡顿的效果
<template><!-- 虚拟列表容器 --><div
class="virtualListWrap"
ref="virtualListWrap":style="{ height: itemHeight * count + 'px' }"
@scroll="handleScroll"><!-- 占位元素,高度为所有数据的总高度 --><div
class="placeholderDom":style="{ height: allListData.length * itemHeight + 'px' }"></div><!-- 实际显示的内容区域 --><div class="contentList":style="{ top: topVal }"><!-- 循环渲染可见的数据项 --><div
v-for="(item, index) in showListData":key="index"class="itemClass":style="{ height: itemHeight + 'px' }">{{ item.name }}</div></div><!-- 加载提示 --><div class="loadingBox" v-show="loading"><i class="el-icon-loading"></i> <span>loading...</span></div></div></template><script setup>import{ ref, computed, onMounted }from'vue';import axios from"axios";const allListData =ref([]);// 存储所有数据的数组const itemHeight =40;// 每个列表项的高度(像素)const count =10;// 一次显示的数据项数量const start =ref(0);// 当前可见区域的起始索引const end =ref(10);// 当前可见区域的结束索引const topVal =ref('0px');// 内容区域的顶部偏移量const loading =ref(false);// 控制加载提示的显示const virtualListWrap =ref(null);// 计算当前应该显示的数据const showListData =computed(()=>{return allListData.value.slice(start.value, end.value);});// 组件挂载后加载数据onMounted(async()=>{
loading.value =true;const res =await axios.get("http://124.223.69.156:3300/bigData");
allListData.value = res.data.data;
loading.value =false;});// 处理滚动事件consthandleScroll=()=>{// 获取滚动条位置const scrollTop = virtualListWrap.value.scrollTop;// 计算新的起始索引
start.value = Math.floor(scrollTop / itemHeight);// 计算新的结束索引
end.value = start.value + count;// 更新内容区域的顶部偏移量
topVal.value = scrollTop +'px';};</script><style scoped lang="less">// 虚拟列表容器盒子.virtualListWrap {
box-sizing: border-box;width: 240px;border: solid 1px #000000;// 开启滚动条
overflow-y: auto;// 开启相对定位position: relative;.contentList {width:100%;height: auto;// 搭配使用绝对定位position: absolute;top:0;left:0;.itemClass {
box-sizing: border-box;width:100%;height: 40px;
line-height: 40px;
text-align: center;}// 奇偶行改一个颜色.itemClass:nth-child(even){background: #c7edcc;}.itemClass:nth-child(odd){background: pink;}}.loadingBox {position: absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;
background-color:rgba(255,255,255,0.64);color: green;display: flex;
justify-content: center;
align-items: center;}}</style>
分堆渲染
通过将数据分成小块,只有当前可视区域的数据会被加载,这样避免了由于一次性加载大量数据而引发的性能瓶颈,从而减少了初始渲染时间,让用户可以快速看到界面。其次,分堆渲染有效降低了内存占用,因为系统只需保持当前可视部分的数据在内存中,尤其在处理大规模数据时,这种策略能显著提升应用的流畅度,防止因内存不足导致的崩溃或卡顿现象。此外,用户体验得到了极大的改善,用户在滚动或翻页时,新数据可以无缝加载,避免了传统分页方式中需要等待新页面加载的尴尬,让用户的操作更加自然和顺畅。
把大数据一维数组通过while循环变成二维数组,然后借助
requestanimationframe
API对二维数组里面的每一堆进行分堆染达到染数据不卡顿的效果
<template><div v-if="activeName === 'first'"><el-button
style="margin-bottom: 12px"
size="small"
type="primary":loading="loading"
@click="plan">点击请求加载</el-button
><el-table
height="300":data="arr"
border
style="width: 80%":header-cell-style="{height:'24px',lineHeight:'24px',color:'#606266',background:'#F5F5F5',fontWeight:'bold',}"
><el-table-column type="index" label="序"></el-table-column><el-table-column prop="id" label="ID"></el-table-column><el-table-column prop="name" label="名字"></el-table-column><el-table-column prop="value" label="对应值"></el-table-column></el-table></div></template><script>import{ ref }from'vue';import axios from"axios";const arr =ref([]);const loading =ref(false);constaverageFn=(arr)=>{let i =0;let res =[];while(i < arr.length){
res.push(arr.slice(i, i +10));
i = i +10;}return res;};constplan=async()=>{
loading.value =true;const res =await axios.get('http://124.223.69.156:3300/bigData');
loading.value =false;const resArr =averageFn(res.data.data);constuseArr=(page)=>{if(page > resArr.length -1){return;}requestAnimationFrame(()=>{
arr.value =[...arr.value,...resArr[page]];
page = page +1;useArr(page);});};useArr(0);};</script><style lang="less" scoped>.bigDataBox {
box-sizing: border-box;
padding-right: 240px;}</style>
触底加载
无缝的交互方式让他们感觉更加自然,能够持续浏览内容。其次,触底加载能够有效管理数据的加载量,系统只在用户即将到达页面底部时才渲染新的数据,提高了加载速度
<template><!-- 触底加载 --><div class="box"><el-table
v-el-table-infinite-scroll="load"
height="480":data="tableData"
border
style="width: 80%"
v-loading="loading"
element-loading-text="稍后..."
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.5)":header-cell-style="{height:'24px',lineHeight:'24px',color:'#606266',background:'#F5F5F5',fontWeight:'bold',}"
><el-table-column type="index" label="序"></el-table-column><el-table-column prop="id" label="ID"></el-table-column><el-table-column prop="name" label="名字"></el-table-column><el-table-column prop="value" label="对应值"></el-table-column></el-table></div></template>KKKKKKKKKKKKKKKKKK<script setup>import{ ref, onMounted }from'vue';import axios from"axios";
KKKKKKKKKKKKKKKKfunction averageFn(arr){let i =0;let result =[];while(i < arr.length){
result.push(arr.slice(i, i +10));// 一次截取10个用于分堆KKKKKKKKKKKKKK
i = i +10;// 这10个截取完,再准备截取下10个}return result;}KKKKKKKKKKKKconst allTableData =ref([]);const tableData =ref([]);const loading =ref(false);// 第一步,请求大量数据时候,转成二维数组,分堆分组分KKKKKKKKKK块存储onMounted(async()=>{
loading.value =true;const res =await axios.get("http://124.223.69.156:3300/bigData");
KKKKKKKKallTableData.value =averageFn(res.data.data);// 也可以存一份原始值,留作备用,都行的// const originalAllTableData = allTableData.value;
loading.value =false;load();KKKKKK});constload=async()=>{// console.log("自动多次执行之,首次执行会根据高度去计算要执行几次合适");//KKKK 第四步,触底加载相当于把二维数组的每一项取出来用,用完时return停止即可if(allTableData.value.length ==0){
console.log("没数据啦");return;}// 第二步,加载的时候,把二维数组的第一项取出来,拼接到要展示的表格数据中去let arr = allTableData.value[0];
tableData.value = tableData.value.concat(arr);// console.log(tableData.value);// 第三步,拼接展示以后,再把二维数组的第一项的数据删除即可
allTableData.value.shift();};</script>
本篇文章到这里就结束了,如果对你有所帮助就点个赞吧 会持续更新技术文章
版权归原作者 ZhaiMou 所有, 如有侵权,请联系我们删除。