吐槽!iview的table組件


 

為什么要吐槽iview的table組件呢?

首先iview的table的使用體驗十分的不友好,每次修改數據都會重刷整個表格,性能極差,因為重刷表格會導致自動失焦等問題!

vue不是有diff算法嗎?重刷表格數據沒有發生變化部分是不會重新渲染的,性能為什么會差呢?

是的,diff算法是可以優化vnode的渲染問題,但是前提是key,tag等屬性沒有發生變化的情況,可是萬惡的iview table既然私自修改了key的值,導致diff的優化失效。

如何解決這個問題?

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)為什么要拷貝一份呢?

解:為了防止table組件內部直接通過params.row直接修改數據源,直接修改數據源容易導致bug難追溯,數據容易錯亂等情況,增加維護成本!

       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算法失效(導致表格重新渲染的元凶)

            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; },

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM