element/Antd vue 表格性能问题,表格数据多导致页面卡顿问题解决思路与方法

工作中,使用了 Antd vue 中的 a-table 组件,当表格数据过多时导致页面卡顿,并且表格多选也会出现卡顿,测试提出了性能bug。。。

table 没有设计成分页那种加载数据的形式,而是用滚动加载的方式不停地加载数据,我也是醉了。。。

在百度了一圈后,发现解决该问题主要是用虚拟滚动的思路。引发页面卡顿的原因主要是由于数据量太大导致渲染的 dom 较多,然后页面就卡顿了。。。

下面使用 element 中的 el-table 实现一下虚拟滚动来解决这个问题,Antd vue 中的写法也类似,a-table 的结构相似。

在这里插入图片描述

1 先搞页面结构

<template><div><divclass="gl-cell-card-box"><el-tableref="tableRef"style="width:418px"bordermax-height="448":data="sliceTable":row-key="row => row.id"@select="handleSelect"@select-all="handleSelectAll"><el-table-columntype="selection"width="40"></el-table-column><el-table-columnprop="name"label="姓名"width="120"></el-table-column><el-table-columnprop="age"label="年龄"width="120"></el-table-column><el-table-columnprop="address"label="住址"></el-table-column></el-table></div></div></template>

2 定义一些变量

data(){return{// 表格所有数据
        tableData:[],// 开始索引
        startIndex:0,// 选中的数据
        selectedRows:[],// 空元素,用于撑开table的高度
        vEle:undefined,// 是否全选
        isSelectedAll:false,};},

3 定义方法

// 计算属性
computed:{// 这个是截取表格中的部分数据,放到了 table 组件中来显示sliceTable(){returnthis.tableData.slice(this.startIndex,this.startIndex+9);},}
created(){// 创建一个空元素,这个空元素用来撑开 table 的高度,模拟所有数据的高度this.vEle= document.createElement("div");this.loadData();}mounted(){// 绑定滚动事件this.$refs.tableRef.$el.querySelector(".el-table__body-wrapper").addEventListener("scroll",this.tableScroll,{
        passive:true});},
methods:{// 加载数据loadData(){let start_i=this.tableData.length;for(let i= start_i; i< start_i+20; i++){this.tableData.push({
                id: i,
                name:"zhangsan"+ i,
                age:12,
                address:"china"});}this.$nextTick(()=>{// 设置成绝对定位,这个元素需要我们去控制滚动this.$refs.tableRef.$el.querySelector(".el-table__body").style.position="absolute";// 计算表格所有数据所占内容的高度this.vEle.style.height=this.tableData.length*48+"px";// 把这个节点加到表格中去,用它来撑开表格的高度this.$refs.tableRef.$el.querySelector(".el-table__body-wrapper").appendChild(this.vEle);// 重新设置曾经被选中的数据this.selectedRows.forEach(row=>{this.$refs.tableRef.toggleRowSelection(row,true);});});},/**
     * @description: 手动勾选时的事件
     * @param {*} selection - 选中的所有数据
     * @param {*} row - 当前选中的数据
     * @return {*}
     */handleSelect(selection, row){this.selectedRows= selection;},/**
     * @description: 全选事件
     * @param {*} selection
     * @return {*}
     */handleSelectAll(selection){this.isSelectedAll=!this.isSelectedAll;if(this.isSelectedAll){this.selectedRows=this.tableData;}else{this.selectedRows=[];this.$refs.tableRef.clearSelection();}},/**
     * @description: table 滚动事件
     * @param {*}
     * @return {*}
     */tableScroll(){let bodyWrapperEle=this.$refs.tableRef.$el.querySelector(".el-table__body-wrapper");// 滚动的高度let scrollTop= bodyWrapperEle.scrollTop;// 下一次开始的索引this.startIndex= Math.floor(scrollTop/48);// 滚动操作
        bodyWrapperEle.querySelector(".el-table__body").style.transform=`translateY(${this.startIndex*48}px)`;// 滚动操作后,上面的一些 tr 没有了,所以需要重新设置曾经被选中的数据this.selectedRows.forEach(row=>{this.$refs.tableRef.toggleRowSelection(row,true);});// 滚动到底,加载新数据if(bodyWrapperEle.scrollHeight<= scrollTop+ bodyWrapperEle.clientHeight){if(this.tableData.length==100){this.$message.warning("没有更多了");return;}this.loadData();}}}

参考文献

[1] vue针对滚动元素内部大量元素,但只有部分元素可见,对dom懒渲染,节省内存的优化
[2] antv表格大量数据卡顿问题(局部渲染数据)