iT邦幫忙

2022 iThome 鐵人賽

DAY 4
0
自我挑戰組

程式小白的 vue.js 學習筆記系列 第 4

Day 4 : v-for & 用 index 作為 key 會引發的問題

  • 分享至 

  • xImage
  •  

v-for : 呈現多筆資料於畫面上

v-for可以將資料多筆渲染,形式為 :

自訂名稱 in 特定物件。ex : item in products。
這裡將 index (索引值)暫時作為 key。 (後面會說到為何不要這樣做)

<ul>
    <li v-for='(item,key) in products':key="key">{{ key+1 }}.{{item.name}} / {{item.price}}元</li>
</ul>

物件迴圈

<ul>
    <li v-for='(item,index) in products' :key="index">{{ key+1 }}.{{item.name}} / {{item.price}}元</li>
  </ul>

純數值迴圈

<ul>
    <li v-for="i in 5">{{ i }}</li>
  </ul>

v-for 與 key

有相同父元素的子元素必須有獨特的 key,重複的 key 會造成渲染錯誤。
也就是說 v-for 的 key 必須是唯一值,如此當我們重新渲染 v-for 列表時,才能夠準確地更新節點。

而這裡的 item.name 就是獨特的,因此可以將它作為key,並用 v-bind 綁定屬性。

v-for 一定會和 key 綁在一起。 (原因後面會提到)

 <ul>
    <li v-for="(item, key) in products" :key="item.name">
      {{ key }} - {{ item.name}} / {{ item.price }} 元
      <input type="text">
    </li>
  </ul>

用 index 作為 key 會引發的問題

在開發過程中,當我們遇到 table 或 ul li 列表時,有時候會利用 index 來做為 key 。(默默被戳中)

當 vue 在更新 v-for 渲染的元素時,是默認使用 「就地更新」 的策略,而非移動 DOM。

那這個 「就地更新」 是什麼意思呢? 來舉個例子 :

這是個list,假如我們現在要新增一個 4 在最後面 :

vue 會自動比對舊節點與新節點的內容,而在這個例子中,因為前三項並沒有任何變化,所以這裡只會很單純的新增了一個 「4」 的項目。

那如果我們試著把 4 放到最前面呢?
因為就地更新不會移動 Dom 元素的順序,只會更新內容而已。此時 DOM 元素依然存在。

但原來的項目三的 DOM 已經不夠用了,所以會再新增一個 DOM :

此時 data 和 key 的對應關係已經被改變,因此也會被重新渲染
如果資料很少的話倒是沒什麼差,不過一旦資料多起來,就會對效能造成影響。

為什麼 v-for 一定要配 key 呢?

因為 v-for 默認使用 「就地更新」 的策略,vue 會根據這個 key 的值 去判斷這個值是否需要被修改。如果需要被修改的話,就重新渲染,如果不用的話,就不動。

如果我們的 v-for 沒有搭配 key 使用,vue 就無法判斷哪個值不用被修改,因此所有資料都會被重新渲染,這樣的行為會造成效能的浪費。

如果有綁 key 的話,vue 會自動比對,如果我們只需要修改某條資料,他就只會去重新渲染那條資訊,進而達成效能的優化。

拿唯一值 ( id ) 作為 key

那如果我們希望既要效能好,又能達到一樣目的的話要怎麼辦呢?
正確的做法是 : 拿唯一值(id)作為key
因為 id 是唯一值,因此在 就地更新 時,就會按照 id 來比對,
只要有一樣的 id,就可以避免重複渲染 DOM,進而達成優化效能的效果。

結論 : 所謂就地更新的意思就是 : 只更新需要更新的節點,盡量用原地修改的方式來更新資料。

提醒 :
如果你沒有對資料進行逆序操作 (比如打亂順序,或是倒轉順序),僅僅是用來展示的渲染,這樣的話使用 index 作為key 就沒有問題。


參考文章:
不只懂 Vue 語法:為何 v-for 的 key 必須是唯一值?v-for 與 v-if 能否同時使用?
关于使用index作为key的问题
vue的就地更新策略__前端__Vue.js


上一篇
Day 3 : Vue 的 data 為什麼要使用 return 呢?
下一篇
Day5 : v-if & v-for 不能在一起的原因
系列文
程式小白的 vue.js 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言