為什麼應該在 v-for 中使用 :key?
input中的 key
引用vue官方文件的原話:
vue會盡可能高效地渲染元素,通常會複用已有元素而不是從頭開始渲染。
這樣容易導致一些問題。因為類似 <input>, <select>, <textarea>這樣的元素都有一個internal state儲存著元素的值,而在元素複用時,這個值是會得到保留的。
我們來看一個登陸方式切換的例子:
<div v-if="isUser">
<label>Login with account</label>
<input type="text" placeholder="Enter your account">
</div >
<div v-else>
<label>Login with email</label>
<input type="text" placeholder="Enter your email">
</div>
<button @click="isUser=!isUser">click to toggle</button>
我們會發現,在點選按鈕切換登入方式的時候,輸入框中已有的內容不會被清除,這是因為input的 internal state保留著元素的值。
如果我們希望切換的時候不保留這個值呢?我們可以給兩個 input新增不同的 :key。因為 vue 是將 key作為唯一標識從而來識別複用的元素的,如果兩個元素的 key不同,那麼就相當於告訴 vue“這兩個元素是完全獨立的,不要複用它們”。
v-for中的 key
同樣的,使用 v-for更新已渲染的元素列表時,預設用 就地複用策略。列表資料修改的時候,vue 會根據 key去判斷某個值是否修改 —— 如果修改,則重新渲染這一項,否則複用之前的元素。在 v-for中使用 key是一個最佳實踐,但是我們需要注意使用的是什麼 key。
假如我們想要在如下陣列 [A,B,C,D,E]的 B 和 C 之間插入 F:
index id Array.elem
0 1 A
1 2 B
2 3 C
3 4 D
4 5 E
如果是使用 index作為 key:
-
在末尾插入 F 的話沒有問題,因為這個時候不影響前面元素的 index,每個元素的 index 不變,而 vue 可以依據這些 index 對元素進行復用;但是現在是在中間插入 F,一旦插入成功,那麼 CDE 的 index 都會改變,這時候 CDE 都需要重新渲染一次。而 AB 的 index 是不變的,所以 AB 可以得到複用。
如果是使用 id作為 key:
-
這裡就要注意了,這個 id是唯一的,也是固定不變的(也可以採用元素本身的值作為這個唯一的 id),不管插入還是刪除,元素該是哪個 id還是哪個 id,這意味著以這樣的 id作為key時,所有舊元素都可以得到複用。所以這種情況下,我們只需要渲染新插入的 F 元素即可。
資源搜尋網站大全 http://www.szhdn.com
Virtual DOM 的 Diff演算法
下面大致從虛擬DOM的Diff演算法實現的角度去解釋一下。
vue 和react的虛擬 DOM 的 Diff演算法大致相同,其核心是基於兩個簡單的假設:
- 兩個相同的元件產生類似的DOM結構,不同的元件產生不同的DOM結構。
- 同一層級的一組節點,他們可以通過唯一的id進行區分。基於以上這兩點假設,使得虛擬DOM的Diff演算法的複雜度從O(n^3)降到了O(n)。
引用react’s diff algorithm中的例子:
當某一層有很多相同的節點時,也就是列表節點時,Diff 演算法的更新過程預設情況下也是遵循以上原則。 比如一下這個情況:
我們希望可以在 B 和 C 之間加一個 F,Diff 演算法預設執行起來是這樣的:
即把 C 更新成 F,D 更新成 C,E 更新成 D,最後再插入 E,這樣顯然很沒有效率。
所以我們需要使用 key 來給每個節點做一個唯一標識,Diff 演算法就可以正確的識別此節點,找到正確的位置區插入新的節點。
所以 key 的作用主要是為了高效的更新虛擬 DOM。