關於ant-design-vue的table內嵌輸入框性能問題

關於ant-design-vue的table組件內嵌輸入框性能問題

總所周知,ant-design-vue是唐金洲老師憑藉一己之力擼出來的一套基本ant-design的vue版本UI組件庫,後來才歸入了ant-design官方門下。不得不說,單憑一己之力能實現這麼一套框架實在令人敬仰,但隨之而來的問題也就顯現了。

antd官方推薦編寫語言

antd的官方推薦編寫語言是react,其背後有着專業的前端團隊以及社區維護。而vue版本的antd,則是由個人開發,由螞蟻金服提供技術支持的,可見其完善程度遠不如react版的antd。

框架性能問題

博主作爲antd-vue版入門的菜鳥選手,在入手時體驗到了其非常完善的API及對應解釋文檔感到非常的高興(對比elementUIvantUI),同時非常驚歎pro項目中非常規範的代碼風格及寫法。
但是,當博主使用其form組件構建出一個非常複雜的表單時(類似店小祕的發佈產品頁),前期的開發可謂是順風順水,但是當開發完畢交付測試時,博主發現了在其fom-item項中的input輸入框輸入時會顯得卡頓,使用google流量器做performance做性能測試的時候,發現其輸入時延達到了60多ms。
google瀏覽器中做性能測試的測試圖
可以非常明顯的看到,vue在我進行輸入的時候,進行了多次的render刷新渲染操作,導致了input框輸入時發生的卡頓現象。故博主折返回官方文檔上查閱,果不其然,發現了form表單組件有一個selfUpdate的API(用於使form-item項的更新不會波及到其他item項)。
官方文檔中對於selfUpdate的解釋說明
博主使用了這個屬性綁定到整個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的用法解釋說明
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-modelv-ifv-show,也即是可能在視圖上更新的時候,也會觸發table組件的刷新,原因不明,希望有懂的大神指點迷津,感激不盡!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章