1. 先說結論
- key在Vue是DOM物件的標識;
- 進行串列展示時,默認key是index;
- 如果資料只做展示使用,使用index作為key是沒有任何問題的;
- 如果使用index作為key,而后續操作會破壞順序,一定會帶來效率問題,嚴重時會渲染出錯誤的DOM
關于key的作用及實作原理,下面一一道來,
2. key的作用
key就是一個標識,被使用在Vue中,再詳細一點,key被使用在Vue中的虛擬DOM中,并不會出現在真實DOM中,
2.1 舉一個例子
以串列的形式展示一組人員資訊,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>key的原理</title>
<!--引入vue-->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<div id="root">
<h2>人員串列</h2>
<ul>
<li v-for="(p,index) in persons">
{{p.name}}-{{p.age}}
</li>
</ul>
</div>
<body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
persons:[
{'id':'001', 'name':'張三','age':'18'},
{'id':'002', 'name':'李四','age':'19'},
{'id':'003', 'name':'王五','age':'20'}
]
}
})
</script>
</body>
</html>
這個html檔案在瀏覽器中打開如下圖所示,

而上述示例html檔案中并沒有使用到key,似乎也沒有問題,當然,單純地展示資料,不寫key是不會存在問題的,
現在我們為上述示例加上key,這里以每條資料的id為key
<li v-for="(p,index) in persons" :key="p.id">
{{p.name}}-{{p.age}}
</li>
加上key的展示結果和上圖結果一模一樣,

而如果我們在瀏覽器上查看元素,不會看到key的存在,

截至目前,我們可以得到兩個結論:1. 只做資料展示用,不寫key是沒有任何影響的;2.key不會出現在真實DOM中
實際上,即使不寫key,Vue在生成真實DOM時,也用到了key,默認是資料索引(index)
我們把key替換為index,展示的資料不會產生任何改變,
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}
</li>
2.2 修改一下上述示例
在展示人員資訊的基礎上顯示索引,并且添加一個按鈕,功能是在頭部添加人員資訊
對上述html檔案稍加修改,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>key的原理</title>
<!--引入vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<link rel="icon" href="../favicon.ico" type="image/x-icon" />
</head>
<div id="root">
<h2>人員串列</h2>
<button @click="add">添加一個老劉</button>
<ul>
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}-{{index}}
</li>
</ul>
</div>
<body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
persons:[
{'id':'001', 'name':'張三','age':'18'},
{'id':'002', 'name':'李四','age':'19'},
{'id':'003', 'name':'王五','age':'20'}
]
},
methods:{
add(){
const p = {'id':'004', 'name':'老劉','age':'40'}
this.persons.unshift(p)
}
}
})
</script>
</body>
</html>
我們可以看到,張三、李四、王五的索引分為別0,1,2

點擊按鈕,添加一個新人物,這個時候索引發生了變化,新添加的人物“老劉”變為了索引0,似乎對,也似乎不對

當然,單純地討論索引,這里一點問題也沒有,下面舉一個新例子,來說說“不對“在哪里
2.3 再修改一下示例
不展示索引了,改為輸入框,在每個人物后面的輸入框內寫上人物的姓,觀察新插入資料后原始資料的變化
稍微修改一下html
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}
<input type="text">
</li>
實際效果就是下圖這樣

到這里,似乎沒有什么不對,接下來就是見證奇跡的時刻
添加老劉,出現了問題,和我們預想的不一樣,

這是key為index的情況,如果修改為資料的唯一標識,則不會產生這樣的問題,
<li v-for="(p,index) in persons" :key="p.id">
{{p.name}}-{{p.age}}
<input type="text">
</li>
誒,這就是我們想要的,

串列內有輸入內容,后續操作會破壞原始順序,就會產生錯誤DOM
3. key的實作原理
要解釋key的實作原理,就要引入Vue一個十分重要的概念——【虛擬DOM】,
給出一組資料,Vue要把這些資料渲染到頁面上,首先要生成【虛擬DOM】,然后根據【虛擬DOM】去生成【真實的DOM】,如果資料發生了改變,Vue會生成【新的虛擬DOM】,注意,這個【新的虛擬DOM】并不會直接生成【新的真實DOM】,否則虛擬DOM一點用處也沒有了,Vue的操作是,拿根據新的資料生成的【新的虛擬DOM】與之前的【真實的DOM】去做比較,如果相同,直接延用即可(“拿來主義”);如果不同,則生成新的DOM物件,
在這個程序中key扮演了很重要的角色,
根據最后一個示例進行剖析,
1. key為index的情況,
根據資料生成【真實DOM】的流程如下:(注意,下圖的真實DOM中輸入框里的內容為生成頁面后手動添加)

然后,添加人物“老劉”,獲取到一組新資料

Vue拿新資料生成【新的虛擬DOM】

在生成真實DOM,就需要用新生成的虛擬DOM和原來的真實DOM作比較(一條一條分析)

對比第一條,key為0,找到舊DOM中key為0的資料,發現“老劉-40”和“張三-18”不同,渲染新的資料“老劉-40”到頁面上;再往后,發現同為輸入框,不必重新渲染,直接使用原來真實DOM的內容,第一條內容就出現了,而這個輸入框還攜帶有張三的姓,

對比第二條,key為1,找到舊DOM中key為1的資料,發現“張三-18”和“李四-19”不同,渲染新的資料“張三-18”到頁面上;再往后,發現同為輸入框,不必重新渲染,直接使用原來真實DOM的內容,第二條內容就出現了,而這個輸入框還攜帶有李四的姓,

之后同理,
回顧這個程序,key是作為虛擬DOM中物件的唯一標識,標識出了資料的“身份資訊”,Vue在虛擬DOM中會根據這個“身份標識”去對比內容,設計的初衷是為了節省資源開支,不必渲染重復的部分,在本示例中,不但帶來了效率問題,還渲染出了錯誤的DOM,后果非常嚴重,
2. key為id的情況,
直接進入添加“老劉”后的新舊DOM對比,

對比第一條,key為‘004’,發現在舊DOM中并不存在,直接生成“老劉-40”和新的輸入框,
對比第二條,key為‘001’,發現舊DOM中key為‘001’的資料相同,直接將“張三-18”和輸入框拿過來使用,
……
最后生成正確的DOM,節省了資源開支,
3. 總結
推薦使用資料的唯一標識作為key,比如id,身份證號,手機號等等,通常這些資料由后端提供,
后續操作不破壞原來資料順序的話,使用index作為key也沒有任何問題,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/310588.html
標籤:其他
上一篇:如何在python中只初始化一次資料庫連接,并在運行時重用它?
下一篇:vue學習(二)
