老项目优化之:如何给Avue库的Crud表格组件开启虚拟滚动?写在前面 公司有个老项目用的是Vue2 + avue组件库
写在前面
公司有个老项目用的是Vue2 + avue组件库,里面大量的表格使用avue的crud组件,在遇到每页200到500的大量数据时,全选,分页就会卡卡卡卡个不停,领导也早早提了优化需求,一直在待办里躺着。
时不时有用户反馈表格卡,再不时表格反映慢,用户对于表格的吐槽不绝于耳。
终于在项目不那么紧张的时间段里,这个老问题再次沉渣又泛起,在我心中激起阵阵涟漪, 久久不能平复,是时候展示真正的技术了。
看我如何:
十步灭一bug,千里不留行。
开始正文
表格卡顿,又是二次封装的复杂表格,从源码角度优化是一个方案,直接在现有二次封装组件上添加虚拟滚动之类的优化另一个方案;鉴于目测avue组件的复杂性,果断选择走第二条路。
百度必应各种搜索之后确定一个适合Vue2的库:el-table-virtual-scroll。
选定的依据:
- 支持
Vue2; - 虚拟滚动可以显著提高表格
性能; - 虚拟滚动组件
全选;
选定那就开搞吧,看看vue2老牌avue和el-table-virtual-scroll之间能擦出怎样的火花呢?
el-table-virtual-scroll基本用法
安装
npm i el-table-virtual-scroll
使用
<virtual-scroll
:data="list"
:item-size="62"
key-prop="id"
@change="(renderData) => virtualList = renderData">
<avue-crud
:option="option"
:table-loading="loading"
:data="virtualList"
:page="page"
:pageTotal="pageTotal"
v-model="form"
ref="crud"
...
/>
</virtual-scroll>
...
import VirtualScroll from 'el-table-virtual-scroll'
export default {
component: {
VirtualScroll
},
data () {
list: [
{
id: 1,
text: 'content'
},
// ...... 省略n条
{
id: 2000,
text: 'content2'
}
],
virtualList: []
}
}
可以看到代码比较简单,通过virtual-scroll接管el-table的全部data数据,然后通过change事件更新当前需要渲染的数据。
很快啊,遇到了第一个问题
表格没有数据展示,先是推测change事件没有执行,再发现控制台有报错,大概意思是说没找到el-table组件, 我不禁要疑惑了,难道二次封装过的el-table不支持??
随后向上看了几眼el-table-virtual-scroll源码,让我发现了一个宝藏方法getElTable,对比文档,发现这个方法正是针对我们这些被封装过的el-table场景,真实太好了。
为作者点赞哈❤️❤️❤️
当然把这个方法加上看看效果:
getElTable(){
return this.$refs.crud.$refs.table;
},
正当我满心欢喜,以为找到了病根的时候,不出意外的意外就发生了,还是报找不到el-table实例。
这就尴尬了,在getElTable里打印this.$refs.crud.$refs.table时,发现输出undefined,难受了,是不是avue筛选项太多了导致getElTable执行的时候表格还没渲染?
怎么办??就这样放弃了?
继续漫无目的地在el-table-virtual-scroll源码淘宝,发现几个可能有用的方法,initData、update、updateData,那在表格数据初始化的时候调一下这三个方法:
this.data = res.data.list;
this.$refs.virtualScroll.initData();
//this.$refs.virtualScroll.doUpdate()
//this.$refs.virtualScroll.updateData(this.data)
成了,就这么成了?好奇到底是哪个方法成了呢,一个一个尝试发现是initData方法发挥了效果,查看源码发现initData里调用了getElTable,此时拿到el-table也是顺理成章的事了。
开心,以后马上就能结束战斗的时候,遇到了本次优化中最大一个问题?
多选,怎么做?按el-table-virtual-scroll的例子选择框需要这样实现:
<virtual-column type="selection" width="60"></virtual-column>
...
<script>
import VirtualScroll from 'el-table-virtual-scroll'
import { VirtualColumn } from 'el-table-virtual-scroll'
export default {
components: { VirtualScroll, VirtualColumn },
...
这里用到另一个组件virtual-column, 也就是el-table-virtual-scroll需要接管el-table的多选,这也能理解,毕竟表格开启虚拟滚动只渲染了一部分数据,表格自己全选的话只能选择几个。
问题是avue的columns都是options配置式,虽然支持插槽,试了selection插槽并没有效果。
咋办?前进还是后退这是个问题?
不行,改avue源码吧,脑海里产出这样一个念头,那就死马当活马医好了,先看看源码再说:
找到selection配置项的地方,从外面传入一个selectionComponent='virtual-column',当然直接这样写并没有成功,随后在脑海里复盘组件渲染机制,找到了一个可疑点:virtual-column是局部引入的,avue在渲染时应该拿不到局部引入的组件,改成全局引入试试:
Vue.component("virtual-scroll", VirtualScroll);
Vue.component("virtual-column", VirtualColumn);
完美!!!运行成功。
至此皆大欢喜,顺利运行,滚动很流畅,全选也很快...

尾声
事了拂衣去,深藏功与名。
最后还遇到一个问题:
重新搜索后,已选项里还包括上一次的选择结果,这也很简单,在搜索时清空选项就可以: this.$refs.virtualScroll.
clearSelection();
谨以此文纪念那些经历一波三折最后被解决掉的BUG。
转载自:https://juejin.cn/post/7400582230802759720