为何要吐槽iview的table组件呢?vue
首先iview的table的使用体验十分的不友好,每次修改数据都会重刷整个表格,性能极差,由于重刷表格会致使自动失焦等问题!node
vue不是有diff算法吗?重刷表格数据没有发生变化部分是不会从新渲染的,性能为何会差呢?算法
是的,diff算法是能够优化vnode的渲染问题,可是前提是key,tag等属性没有发生变化的状况,但是万恶的iview table既然私自修改了key的值,致使diff的优化失效。iview
如何解决这个问题?async
table组件data属性接收的数据源与实际操做的数据分离,例如:如下例子的tempData与data。性能
<Table border :columns="columns" :data="tempData"></Table> export default { data:{ tempData:[], columns:[ { title:'商品价格(元)', width:120, align: 'center', render:(h,params)=>{ let data = this.data[params.index]; // 实际更改的是this.data的数据,由于tempData没有改变,因此table不会从新渲染 return <i-input maxlength={8} number value={data.value} on-on-blur={(e)=>{data.value=e.target.value} />; } }, ], data:[] }, watch:{ data(val){ this.tempData = util.deepCopy(val); }, } }
table组件的内容主题table-body组件,table-body的data属性接收的是rebildData优化
<div :class="[prefixCls + '-body']" :style="bodyStyle" ref="body" @scroll="handleBodyScroll" v-show="!((!!localeNoDataText && (!data || data.length === 0)) || (!!localeNoFilteredDataText && (!rebuildData || rebuildData.length === 0)))"> <table-body ref="tbody" :prefix-cls="prefixCls" :styleObject="tableStyle" :columns="cloneColumns" :data="rebuildData" :columns-width="columnsWidth" :obj-data="objData"></table-body> </div>
table组件内部实现深度监听了data属性,当data的任意属性发生变化就会从新生成rebuildData。(深度拷贝一份原有的data)为何要拷贝一份呢?ui
解:为了防止table组件内部直接经过params.row直接修改数据源,直接修改数据源容易致使bug难追溯,数据容易错乱等状况,增长维护成本!this
watch: { data: { handler () { const oldDataLen = this.rebuildData.length; this.objData = this.makeObjData(); this.rebuildData = this.makeDataWithSortAndFilter(); this.handleResize(); if (!oldDataLen) { this.fixedHeader(); } // here will trigger before clickCurrentRow, so use async setTimeout(() => { this.cloneData = deepCopy(this.data); }, 0); }, deep: true }, ..... }
生成新的data数据,并重置每一项数据的_rowKey属性(该属性被table-tr组件看成key来使用),_rowKey是全局递增的,每一次table从新render,_rowKey都会不断递增,致使diff算法失效(致使表格从新渲染的元凶)spa
makeDataWithSortAndFilter () { let data = this.makeDataWithSort(); this.cloneColumns.forEach(col => data = this.filterData(data, col)); return data; }, makeDataWithSort () { let data = this.makeData(); let sortType = 'normal'; let sortIndex = -1; let isCustom = false; for (let i = 0; i < this.cloneColumns.length; i++) { if (this.cloneColumns[i]._sortType !== 'normal') { sortType = this.cloneColumns[i]._sortType; sortIndex = i; isCustom = this.cloneColumns[i].sortable === 'custom'; break; } } if (sortType !== 'normal' && !isCustom) data = this.sortData(data, sortType, sortIndex); return data; },
// 生成新的data makeData () { let data = deepCopy(this.data); data.forEach((row, index) => { row._index = index; row._rowKey = rowKey++; //rowKey 全局的一个变量 初始值 rowKey=0 }); return data; },