key的特殊屬性主要用在Vue的虛擬DOM算法,在新舊nodes對比時辨識VNodes,若是不使用key,Vue會使用一種最大限度減小動態元素而且儘量的嘗試修復/再利用相同類型元素的算法。使用key,它會基於key的變化從新排列元素順序,而且會移除key不存在的元素。有相同父元素的子元素必須有獨特的key。重複的key會形成渲染錯誤。 總之就是一句話,key屬性可以提高性能(主要做用於數據更新時)。vue
最多見的用例是結合 v-for:node
<ul>
<li v-for="item in items" :key="item.id">...</li>
</ul>
複製代碼
它也能夠用於強制替換元素/組件而不是重複使用它。當你遇到以下場景時它可能會頗有用:git
<transition>
<span :key="text">{{ text }}</span>
</transition>
複製代碼
當 text 發生改變時, 會隨時被更新,所以會觸發過渡。github
使用v-for更新已渲染的元素列表時,默認用就地複用策略;列表數據修改的時候,他會根據key值去判斷某個值是否修改,若是修改,則從新渲染這一項,不然複用以前的元素; 咱們在使用的使用常常會使用index(即數組的下標)來做爲key,但其實這是不推薦的一種使用方法;算法
舉個例子:數組
const list = [
{
id: 1,
name: 'test1',
},
{
id: 2,
name: 'test2',
},
{
id: 3,
name: 'test3',
},
]
複製代碼
<div v-for="(item, index) in list" :key="index+'s'" >{{item.name}}</div>
複製代碼
上面這種是咱們作項目中經常使用到的一種場景,由於不加key,vue如今直接報錯,因此我使用index做爲key;下面列舉兩種常見的數據更新狀況bash
1.在最後一條數據後再加一條數據性能
const list = [
{
id: 1,
name: 'test1',
},
{
id: 2,
name: 'test2',
},
{
id: 3,
name: 'test3',
},
{
id: 4,
name: '我是在最後添加的一條數據',
},
]
複製代碼
此時前三條數據直接複用以前的,新渲染最後一條數據,此時用index做爲key,沒有任何問題;ui
2.在中間插入一條數據spa
const list = [
{
id: 1,
name: 'test1',
},
{
id: 4,
name: '我是插隊的那條數據',
}
{
id: 2,
name: 'test2',
},
{
id: 3,
name: 'test3',
},
]
複製代碼
此時更新渲染數據,經過index定義的key去進行先後數據的對比,發現
以前的數據 以後的數據
key: 0 index: 0 name: test1 key: 0 index: 0 name: test1
key: 1 index: 1 name: test2 key: 1 index: 1 name: 我是插隊的那條數據
key: 2 index: 2 name: test3 key: 2 index: 2 name: test2
key: 3 index: 3 name: test3
複製代碼
經過上面清晰的對比,發現除了第一個數據能夠複用以前的以外,另外三條數據都須要從新渲染;
是否是很驚奇,我明明只是插入了一條數據,怎麼三條數據都要從新渲染?而我想要的只是新增的那一條數據新渲染出來就好了
最好的辦法是使用數組中不會變化的那一項做爲key值,對應到項目中,即每條數據都有一個惟一的id,來標識這條數據的惟一性;使用id做爲key值,咱們再來對比一下向中間插入一條數據,此時會怎麼去渲染。
以前的數據 以後的數據
key: 1 id: 1 index: 0 name: test1 key: 1 id: 1 index: 0 name: test1
key: 2 id: 2 index: 1 name: test2 key: 4 id: 4 index: 1 name: 我是插隊的那條數據
key: 3 id: 3 index: 2 name: test3 key: 2 id: 2 index: 2 name: test2
key: 3 id: 3 index: 3 name: test3
複製代碼
如今對比發現只有一條數據變化了,就是id爲4的那條數據,所以只要新渲染這一條數據就能夠了,其餘都是就複用以前的
其實,真正的緣由並非vue怎麼怎麼,而是由於Virtual DOM 使用Diff算法實現的緣由
下面大體從虛擬DOM的Diff算法實現的角度去解釋一下
vue的虛擬DOM的Diff算法大體相同,其核心是基於兩個簡單的假設:
兩個相同的組件產生相似的DOM結構,不一樣的組件產生不一樣的DOM結構。 同一層級的一組節點,他們能夠經過惟一的id進行區分。基於以上這兩點假設,使得虛擬DOM的Diff算法的複雜度從O(n^3)降到了O(n)。
例子:
當某一層有不少相同的節點時,也就是列表節點時,Diff算法的更新過程默認狀況下也是遵循以上原則。 好比一下這個狀況:
咱們但願能夠在B和C之間加一個F,Diff算法默認執行起來是這樣的:
即把C更新成F,D更新成C,E更新成D,最後再插入E,是否是很沒有效率?
因此咱們須要使用key來給每一個節點作一個惟一標識,Diff算法就能夠正確的識別此節點,找到正確的位置區插入新的節點。
因此一句話,key的做用主要是爲了高效的更新虛擬DOM。另外vue中在使用相同標籤名元素的過渡切換時,也會使用到key屬性,其目的也是爲了讓vue能夠區分它們,不然vue只會替換其內部屬性而不會觸發過渡效果。
參考: