关于ant-design-vue的table组件内嵌输入框性能问题
总所周知,ant-design-vue是唐金洲老师凭借一己之力撸出来的一套基本ant-design的vue版本UI组件库,后来才归入了ant-design官方门下。不得不说,单凭一己之力能实现这么一套框架实在令人敬仰,但随之而来的问题也就显现了。
antd官方推荐编写语言
antd的官方推荐编写语言是react,其背后有着专业的前端团队以及社区维护。而vue版本的antd,则是由个人开发,由蚂蚁金服提供技术支持的,可见其完善程度远不如react版的antd。
框架性能问题
博主作为antd-vue版入门的菜鸟选手,在入手时体验到了其非常完善的API及对应解释文档感到非常的高兴(对比elementUI跟vantUI),同时非常惊叹pro项目中非常规范的代码风格及写法。
但是,当博主使用其form组件构建出一个非常复杂的表单时(类似店小秘的发布产品页),前期的开发可谓是顺风顺水,但是当开发完毕交付测试时,博主发现了在其fom-item项中的input输入框输入时会显得卡顿,使用google流量器做performance做性能测试的时候,发现其输入时延达到了60多ms。
可以非常明显的看到,vue在我进行输入的时候,进行了多次的render刷新渲染操作,导致了input框输入时发生的卡顿现象。故博主折返回官方文档上查阅,果不其然,发现了form表单组件有一个selfUpdate的API(用于使form-item项的更新不会波及到其他item项)。
博主使用了这个属性绑定到整个form后,果不其然,form-item中的input框输入立马变得非常流畅,但紧接着,博主又发现了table中的input输入仍然非常卡顿。
针对table组件进行分析
在对form成功地解决其form-item输入框卡顿问题后,紧接着又发现了table组件中的input框也存在同样的问题,且selfUpdate似乎对内嵌在form-item中的table组件不起作用,故博主又折返官方文档查阅一波table组件API(遇事不决查文档)。
这一次,博主并没有发现可以用于让table中row本身update的API,但注意到了另一个API,table组件下的customRow。
customRow返回一个Function,其中包含了record, index属性,有人会问了,这个API跟分析性能问题有什么关系呢?答案是肯定的,有!因为博主也是碰巧在试的时候发现了,这个API的Function,会在table进行render渲染的时候触发,那这个就非常关键的,我就能通过这个API来测试到底是什么操作,导致了整个table重新render渲染。博主编写的customRow函数如下:
// 在table中绑定事件
<a-table :customRow="customRow"/>
// 在事件中简单地console
customRow(record, index) {
console.log(record, index)
return false
}
果不其然,通过这个API,博主果然发现了在table内嵌的input框输入的时候,假设table有8行,那么你每个键盘输入按键的操作,都会导致table每一个重新render刷新渲染。如下图:
这里只是基于你表格只有8行的情况,可想而知当table行数达到100行,那不卡死才怪咧…
如何解决?
找到了问题的根源,是不是就意味着能找到解决方案了?天真的博主当然是这么想的,所以博主创建了一个新的vue页面开始寻起了导致table更新的原因,因为官方示例没有卡顿的现象,那博主也同样偷懒的复制了官方示例给的代码,但是眼尖的发现了一个问题。
// value是输入的值
// key是table-column的key值相当于v-for中绑定的key
// column则是table的列名
handleChange(value, key, column) {
const newData = [...this.data];
const target = newData.filter(item => key === item.key)[0];
if (target) {
target[column] = value;
this.data = newData;
}
}
这个是官方示例给的table组件中input框change事件的处理,可以看出,官方对input的值的改变后,是重新定义了一个newData,在处理后重新将其赋给了this.data(table用于渲染的dataSource),这个时候博主就在想,会不会是这个操作导致了次input输入都导致了table数据源的重新赋值而导致其重新循环render刷新渲染?
很快得博主嗖嗖嗖地改起了代码,带着自信的微笑并文雅得扫了一下帅气的油头。
handleChangeSizeTable(value, key, column) {
const reg = /^-?[0-9]*(\.[0-9]*)?$/
const newData = [...this.sizeData]
const target = newData.filter(item => key === item.key)[0]
if ((!isNaN(value) && reg.test(value)) || value === '' || value === '-') {
if (target) {
// 修改原本的重新赋值sizeData操作,只改变其中变化的内容
this.sizeData.forEach(item => {
if (target.key == item.key) {
item[column] = value
}
})
console.log(target)
this.generateDescTable() // 生成desc的table表格
}
}
}
博主后边添加的reg规则可以不看,可以看出现在只是修改this.sizeData中的某一项,随即保存发现input框的输入又流畅得飞起,芜湖起飞!
结束了吗?
天真的博主当然以为结束了,但是紧接着点击了某些checkBox时,控制台又输出了一堆record跟index,博主知道table又暗中得render刷新了一下,这又是为什么???
一脸懵逼的博主百思不得其姐,只能靠试来寻求解决方案。终于,找到原因是由于checkBox绑定了v-model,其model值在变化的时候表格即会更新,故博主将其去掉,换成了form-item中的v-decorator(不懂的请自行到官网了解),果不其然真的不会重新render渲染了。然后,悲催的博主又发现问题。。。似乎是v-model、v-if、v-show等指令所绑定的变量值发生变化导致页面发生改变的时候,table就会跟着render刷新渲染(好**恶心啊)
复杂的表单原本就是通过各个变量来控制表单中某个选项的显示隐藏,这个居然还会导致table刷新。。。吐辽吐辽
结语
尽管这个问题目前还没有解决,但博主还是有话想说。
造成table组件render刷新,目前有三个指令v-model、v-if、v-show,也即是可能在视图上更新的时候,也会触发table组件的刷新,原因不明,希望有懂的大神指点迷津,感激不尽!