來看個例子
這裡呢,有個ul標籤
在內部,li標籤通過v-for渲染 data當中的persons陣列
<script>
var vm = new Vue({
el: '.app',
data: {
name: 'wavesbright',
persons:[
{id:1,name:'張三',age:18},
{id:2,name:"李四",age:19},
{id:3,name:"王五",age:20},
],
},
});
</script>
得到了三個節點(3個li)
<div class="app">
<h1>遍歷陣列</h1>
<ul>
<li v-for="(item,index) in persons" :key="index">
{{item.name}} - {{item.age}}
</li>
</ul>
</div>
我現在提一個需求
click方法只呼叫一次哈,多了不好分析,這裡使用的是事件修飾符
<div class="app">
<h1>遍歷陣列</h1>
<!-- 新增一個人,叫老劉 -->
<button @click.once="addPerson">新增</button>
<ul>
<li v-for="(item,index) in persons" :key="index">
{{item.name}} - {{item.age}}
</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '.app',
data: {
name: 'wavesbright',
persons:[
{id:1,name:'張三',age:18},
{id:2,name:"李四",age:19},
{id:3,name:"王五",age:20},
],
},
methods: {
// 新增成員 == 老劉
addPerson(){
// 這是老劉
var laoliu = {id:4,name:'老劉',age:'xx'}
// 在陣列頂部新增成員
this.persons.unshift(laoliu)
}
},
});
</script>
感覺沒什麼問題呀,為什麼會講這個呢
警告,錯誤沒有,頁面顯示正常,也沒有報錯
有問題嗎,有,這裡面有個很嚴重的問題
再來測試下
沒問題啊,咋地?來,我給你演示下
測試
再測試
哦~那我們現在可以總結一個情況
這裡使用流程圖講解
1、一切的一切都是你寫了這段程式碼
2、vue是不是會拿著你的資料生成 虛擬DOM?(並不是一開始就把資料給你變為頁面DOM的,是有流程的)
3、真實DOM上是沒有這個key的,虛擬DOM上必須要有(沒有,vue不能高效工作)
4、上圖這個是已經生成真實DOM了,我們現在還處於虛擬DOM生成的過程中(假設現在頁面還沒有生成這三個li標籤)。現在,在記憶體當中是不是有這三個虛擬DOM了(3個li標籤)
5、將虛擬DOM轉換為真實DOM
6、請問,使用者是在哪裡操作的資料?虛擬DOM還是真實DOM,使用者輸入的資料,殘留在誰身上了?虛擬還是真實DOM?(使用者操作的全是真實DOM)
這個時候初始化流程就結束了
1、新的資料出現了,老劉出現了,老劉是排在所有人的前面
2、隨後,會根據新的資料,生成新虛擬DOM(因為資料發生改變了)
這個時候,老劉的key就是0了,因為你使用index作為索引,老劉排在最前面(因為我們插在最前面)
重點來了:,在目前的整個流程當中,生成了兩份虛擬DOM,vue不會根據上面這個修改後的虛擬DOM進行真實DOM的建立,而是會將兩個虛擬DOM進行一個對比演演算法,這就是該演演算法的由來
對比的時候,依賴著這個key,怎麼對比的呢?請讓我用文字來為你形容
我們出現這個錯誤的原因是執行了這個奇葩的需求,但是通過這個需求,我們能對key進行更加深入的理解
通過上面的分析,這裡思路就很清晰了
分為如下幾步回答