當 Vue 使用 v-for 渲染的元素列表時,它默認使用“就地更新”的策略。如果數(shù)據(jù)項的順序被改變,Vue 將不會移動 DOM 元素來匹配數(shù)據(jù)項的順序,而是就地更新每個元素,并且確保它們在每個索引位置正確渲染。
這句話是什么意思呢,看一下圖你就會理解:

數(shù)據(jù)由[A,B,C,D]改變成了[A,E,C,D]的過程。

數(shù)據(jù)由[A,B,C,D]改變成了[E,A,B,C,D]的過程。
這個默認的模式是高效的,但是只適用于不依賴子組件狀態(tài)或臨時 DOM 狀態(tài) (例如:表單輸入值) 的列表渲染輸出。
為什么這么說呢,運行一下以下代碼你就會發(fā)現(xiàn)問題:
<div>
<input type="text" v-model="name">
<button @click="add">添加</button>
</div>
<div v-for="name in list">
<input :id="name" type="radio" name="name" :value="name" v-model="checkedNames">
<label :for="name">{{name}}</label>
</div>
<div>Checked names: {{ checkedNames }}</div>
data() {
return {
name: '',
list: ['張三', '李四', '王五'],
checkedNames: []
}
},
methods: {
add() {
this.list.unshift(this.name);
}
}

先選中“張三”

添加“十一”
從上面我們發(fā)現(xiàn),開始選中的張三,當添加一個十一后,雖然選中的值顯示張三,但頁面展示卻選中了十一,這顯然是錯誤的,這就是就地更新造成的錯誤。
當我們給代碼加上key時,問題就解決了(添加時保證name的唯一性)。
<div>
<input type="text" v-model="name">
<button @click="add">添加</button>
</div>
<div v-for="name in list" :key="name">
<input :id="name" type="radio" name="name" :value="name" v-model="checkedNames">
<label :for="name">{{name}}</label>
</div>
<div>Checked names: {{ checkedNames }}</div>

image.png
key的作用主要用在 Vue 的虛擬 DOM 算法,給 Vue 一個提示,以便能跟蹤每個節(jié)點的身份,從而重用和重新排序現(xiàn)有元素,移除 key 不存在的元素(并且根據(jù)源碼可以看出,在比較新老節(jié)點首尾節(jié)點交叉進行sameVnode比對都不相同時,有key后續(xù)的比對會更快,通過map可以快速定位,不需要去遍歷老節(jié)點sameVnode尋找)。

數(shù)據(jù)由[A,B,C,D]改變成了[E,A,B,C,D]的過程。

數(shù)據(jù)由[A,B,C,D]改變成了[A,E,C,D]的過程。
如有不正確的地方,歡迎指正。