Vue中的虛擬DOM、diff算法、key的作用詳解
一、虛擬DOM
從本質(zhì)上來說,虛擬DOM是一個(gè)JavaScript對象,通過對象的形式來描述真實(shí)的DOM結(jié)構(gòu)。
將頁面的狀態(tài)抽象為JS對象的形式,配合不同的渲染工具,使跨平臺(tái)渲染成為可能。通過事務(wù)處理機(jī)制,將多次DOM修改的結(jié)果一次性的更新到頁面上,從而有效的減少頁面渲染的次數(shù),減少修改DOM的重繪重排次數(shù),提高渲染性能。
虛擬DOM本身是js對象,是對DOM的抽象,是更加輕量級的對 DOM的描述。
虛擬DOM流程
創(chuàng)建虛擬 DOM:
當(dāng)組件被創(chuàng)建或更新時(shí),Vue 的渲染函數(shù)會(huì)返回一個(gè)新的虛擬 DOM 樹。
這個(gè)樹是一個(gè) JavaScript 對象,它描述了 真實(shí)DOM 的結(jié)構(gòu)、屬性和子元素。
// 真實(shí)dom <ul id="list"> <li class="item">哈哈</li> <li class="item">呵呵</li> <li class="item">嘿嘿</li> </ul>
Vue會(huì)把代碼轉(zhuǎn)換成一個(gè)對象(虛擬 DOM),通過對象的形式來描述真實(shí)的DOM結(jié)構(gòu)
轉(zhuǎn)換成虛擬 DOM對象, 類似于下面這種(偽代碼)
let oldVDOM = { // 舊虛擬DOM tagName: 'ul', // 標(biāo)簽名 props: { // 標(biāo)簽屬性 id: 'list' }, children: [ // 標(biāo)簽子節(jié)點(diǎn) { tagName: 'li', props: { class: 'item' }, text: '哈哈' }, { tagName: 'li', props: { class: 'item' }, text: '呵呵' }, { tagName: 'li', props: { class: 'item' }, text: '嘿嘿' }, ] }
比較虛擬 DOM:
這時(shí)候,我修改一個(gè)li標(biāo)簽
的文本:
<ul id="list"> <li class="item">哈哈</li> <li class="item">呵呵</li> <li class="item">哈哈哈</li> // 修改 </ul>
這時(shí)候生成的新虛擬DOM
為:
let newVDOM = { // 新虛擬DOM tagName: 'ul', // 標(biāo)簽名 props: { // 標(biāo)簽屬性 id: 'list' }, children: [ // 標(biāo)簽子節(jié)點(diǎn) { tagName: 'li', props: { class: 'item' }, text: '哈哈' }, { tagName: 'li', props: { class: 'item' }, text: '呵呵' }, { tagName: 'li', props: { class: 'item' }, text: '哈哈哈' }, ] }
- Vue會(huì)對比新舊虛擬DOM之間的差異,對比出是哪個(gè)虛擬節(jié)點(diǎn)更改了,找出這些差異。
- 這個(gè)比較過程會(huì)找出兩個(gè)樹之間的最小變化集,即哪些節(jié)點(diǎn)需要被添加、更新或刪除。
- 這個(gè)過程被稱為“diffing”或“差異算法”。Vue 的差異算法是高度優(yōu)化的,可以快速地計(jì)算出兩個(gè)樹之間的差異。
應(yīng)用更改:
一旦差異被計(jì)算出來:
- Vue 就會(huì)只更新這些有差異的節(jié)點(diǎn)應(yīng)用到實(shí)際的 DOM 上,而不用更新其他數(shù)據(jù)沒發(fā)生改變的節(jié)點(diǎn),實(shí)現(xiàn)精準(zhǔn)地更新真實(shí)DOM,進(jìn)而提高效率。
- 這個(gè)過程是批量的,意味著多個(gè)更改可以一次性地應(yīng)用到 DOM 上,從而減少了瀏覽器的重排和重繪次數(shù)。
- 這個(gè)過程被稱為 Patch 或“打補(bǔ)丁”
更新視圖:
當(dāng) DOM 更新完成后,瀏覽器就會(huì)重新渲染視圖,以反映組件的最新狀態(tài)。
虛擬DOM優(yōu)點(diǎn)
- 性能優(yōu)化:通過減少對實(shí)際 DOM 的操作次數(shù),虛擬 DOM 可以顯著提高性能。
- 跨平臺(tái):虛擬 DOM 使得 Vue.js 可以輕松地實(shí)現(xiàn)跨平臺(tái)應(yīng)用,例如使用 Web Workers 或 Weex 等技術(shù)來創(chuàng)建桌面應(yīng)用或移動(dòng)應(yīng)用。
- 易于測試和調(diào)試:由于虛擬 DOM 是 JavaScript 對象,因此它可以使用 JavaScript 的所有調(diào)試工具進(jìn)行測試和調(diào)試。此外,你還可以使用諸如 Jest 或 Mocha 等測試框架來編寫針對虛擬 DOM 的單元測試。
用虛擬DOM算法操作真實(shí)DOM,性能高于直接操作真實(shí)DOM
虛擬DOM
和虛擬DOM算法
是兩種概念:虛擬DOM算法 = 虛擬DOM + Diff算法
二、diff 算法 ??
上面的例子中,其實(shí)只有一個(gè)li標(biāo)簽
修改了文本,其他都是不變的,所以沒必要所有的節(jié)點(diǎn)都要更新,只更新這個(gè)li標(biāo)簽
就行,Diff算法就是查出這個(gè)li標(biāo)簽
的算法。
Diff算法是一種對比算法。對比兩者是舊虛擬DOM
和新虛擬DOM
,對比出是哪個(gè)虛擬節(jié)點(diǎn)更改了,找出這個(gè)虛擬節(jié)點(diǎn),并只更新這個(gè)虛擬節(jié)點(diǎn)所對應(yīng)的真實(shí)節(jié)點(diǎn),而不用更新其他數(shù)據(jù)沒發(fā)生改變的節(jié)點(diǎn),實(shí)現(xiàn)精準(zhǔn)地
更新真實(shí)DOM,進(jìn)而提高效率
。
- 使用虛擬DOM算法的損耗計(jì)算: 總損耗 = 虛擬DOM增刪改+(與Diff算法效率有關(guān))真實(shí)DOM差異增刪改+(較少的節(jié)點(diǎn))排版與重繪
- 直接操作真實(shí)DOM的損耗計(jì)算: 總損耗 = 真實(shí)DOM完全增刪改+(可能較多的節(jié)點(diǎn))排版與重繪
?? diff 算法是一種優(yōu)化手段:將新舊兩個(gè)虛擬 DOM 樹進(jìn)行差異對比,修補(bǔ)(更新)差異的過程叫做patch(打補(bǔ)丁),將更新補(bǔ)丁作用于真實(shí) DOM,以最小成本完成視圖更新。
- Diff 算法:當(dāng)組件的數(shù)據(jù)發(fā)生變化時(shí),Vue.js 會(huì)創(chuàng)建一個(gè)新的虛擬 DOM 樹來反映這些變化。然后,它會(huì)使用 diff 算法來比較舊的虛擬 DOM 樹和新的虛擬 DOM 樹之間的差異。這個(gè)比較過程會(huì)找出兩個(gè)樹之間的最小變化集,即哪些節(jié)點(diǎn)需要被添加、更新或刪除。
- Patch 過程(打補(bǔ)丁):在確定了需要更新的節(jié)點(diǎn)之后,Vue.js 會(huì)進(jìn)入 patch 過程。這個(gè)過程會(huì)將差異(或稱為“補(bǔ)丁”)應(yīng)用到實(shí)際的 DOM 上。通過只更新發(fā)生變化的節(jié)點(diǎn),Vue.js 可以避免不必要的 DOM 操作,從而提高性能。
- 最小成本視圖更新:通過只更新發(fā)生變化的節(jié)點(diǎn),Vue.js 能夠在不重新渲染整個(gè)頁面的情況下更新視圖。這大大降低了瀏覽器的重排和重繪次數(shù),從而提高了頁面的性能。
為什么 vue ,react 這些框架中都會(huì)有 diff 算法呢?
要知道渲染真實(shí) DOM 的開銷是很大的,比如有時(shí)候我們修改了某個(gè)數(shù)據(jù),如果直接渲染到真實(shí) DOM 上會(huì)引起整個(gè) DOM 樹的重繪和重排,有沒有可能我們只更新我們修改的那一小塊 DOM 而不要更新整個(gè) DOM 呢?diff 算法能夠幫助我們。
當(dāng)數(shù)據(jù)發(fā)生變化時(shí),vue是怎么更新節(jié)點(diǎn)的?
我們先根據(jù)真實(shí) DOM 生成一棵 virtual DOM
(虛擬DOM)樹,當(dāng) virtual DOM
某個(gè)節(jié)點(diǎn)的數(shù)據(jù)改變后會(huì)生成一個(gè)新的 Vnode
(虛擬節(jié)點(diǎn)),然后 Vnode
和 oldVnode
作對比,發(fā)現(xiàn)有不一樣的地方就直接修改在真實(shí)的 DOM 上,然后使 oldVnode
的值為Vnode
。
diff 的過程就是調(diào)用名為 patch 的函數(shù),比較新舊節(jié)點(diǎn),一邊比較一邊給真實(shí)的 DOM 打補(bǔ)丁。
diff算法流程
在Vue中,DIFF算法(也稱為差異算法或?qū)Ρ人惴ǎ┲饕糜诒容^新舊虛擬DOM(Virtual DOM)之間的差異,并基于這些差異來最小化地更新真實(shí)的DOM,從而提高頁面渲染的性能。
1. 虛擬虛擬DOM
Vue在渲染過程中,首先會(huì)創(chuàng)建一個(gè)虛擬的DOM樹(VNode),這個(gè)樹是對真實(shí)DOM的一個(gè)抽象表示。
當(dāng)數(shù)據(jù)發(fā)生變化時(shí),Vue會(huì)生成一個(gè)新的虛擬DOM樹,并與舊的虛擬DOM樹進(jìn)行比較。
2. 對比虛擬DOM
diff算法會(huì)比較新舊兩個(gè)虛擬DOM樹,找出它們之間的差異。這個(gè)比較過程是在同層級進(jìn)行的,不會(huì)跨層級比較。
比較過程中,Vue會(huì)采用一系列優(yōu)化策略,如雙指針、頭尾比較等,以提高效率。
- Vue會(huì)比較新舊虛擬DOM節(jié)點(diǎn)的類型和屬性,以及它們的子節(jié)點(diǎn)。
- 如果兩個(gè)節(jié)點(diǎn)相同(即類型和屬性都相同),則不需要進(jìn)行任何操作。
- 如果節(jié)點(diǎn)類型不同,或者屬性發(fā)生了變化,Vue會(huì)創(chuàng)建一個(gè)新的DOM節(jié)點(diǎn)來替換舊的節(jié)點(diǎn)。
- 對于子節(jié)點(diǎn)的比較,Vue會(huì)遞歸地應(yīng)用DIFF算法。
3. patch打補(bǔ)丁
一旦diff算法找出新舊虛擬DOM之間的差異,Vue會(huì)生成一個(gè)patch對象,這個(gè)對象記錄了需要執(zhí)行的DOM操作。
然后,Vue會(huì)遍歷這個(gè)patch對象,執(zhí)行相應(yīng)的DOM操作,更新真實(shí)的DOM。
diff算法優(yōu)化策略
1. 比較只會(huì)在同層級進(jìn)行, 不會(huì)跨層級比較
只會(huì)在同層級的節(jié)點(diǎn)之間進(jìn)行比較,不會(huì)跨層級比較。這大大減少了比較的次數(shù)和復(fù)雜度。
如果DOM節(jié)點(diǎn)出現(xiàn)了跨層級操作,Diff算法會(huì)簡單地視為刪除舊節(jié)點(diǎn)并創(chuàng)建新節(jié)點(diǎn),而不是嘗試去移動(dòng)節(jié)點(diǎn)。
<div> <p>123</p> </div>
<div> <span>456</span> </div>
上面的代碼會(huì)分別比較同一層的兩個(gè)div以及第二層的p和span,但是不會(huì)拿div和span作比較。
一張很形象的圖:(比較只會(huì)在同層級進(jìn)行, 不會(huì)跨層級比較)
概括起來就是對操作前后的dom樹同一層的節(jié)點(diǎn)進(jìn)行對比,一層一層對比,然后再插入真實(shí)的dom中,重新渲染
2. 深度優(yōu)先策略
diff算法在比較過程中采用深度優(yōu)先策略,深度優(yōu)先策略意味著算法會(huì)先盡可能深地搜索樹的分支,直到到達(dá)某個(gè)節(jié)點(diǎn)所在的最深位置,然后再回溯到上一層,繼續(xù)搜索其他分支。
當(dāng)比較兩個(gè)VNode時(shí),如果它們都有子節(jié)點(diǎn),那么diff算法會(huì)首先比較這兩個(gè)VNode的子節(jié)點(diǎn)。這個(gè)過程會(huì)遞歸地應(yīng)用深度優(yōu)先策略,先比較子節(jié)點(diǎn)的子節(jié)點(diǎn),直到到達(dá)樹的葉子節(jié)點(diǎn)。
3. 雙指針策略
雙指針策略是指在比較新舊VNode時(shí),同時(shí)設(shè)置兩個(gè)指針,一個(gè)指向舊VNode的頭部,另一個(gè)指向新VNode的頭部。這兩個(gè)指針會(huì)同時(shí)移動(dòng),以找出兩個(gè)VNode樹中的相同節(jié)點(diǎn)或差異。
- 移動(dòng)指針:在比較過程中,如果當(dāng)前節(jié)點(diǎn)相同(即類型和屬性都相同),則兩個(gè)指針都會(huì)向后移動(dòng),繼續(xù)比較它們的子節(jié)點(diǎn)。
- 節(jié)點(diǎn)復(fù)用:如果找到了相同的節(jié)點(diǎn),Vue會(huì)復(fù)用該節(jié)點(diǎn),而不是重新創(chuàng)建。這樣可以避免不必要的DOM操作,提高性能。
- 處理差異:當(dāng)兩個(gè)指針指向的節(jié)點(diǎn)不同時(shí),Vue會(huì)根據(jù)差異類型進(jìn)行相應(yīng)的處理,如添加新節(jié)點(diǎn)、刪除舊節(jié)點(diǎn)或更新節(jié)點(diǎn)。
4. 頭尾比較
頭尾比較策略是在雙指針策略的基礎(chǔ)上的一種優(yōu)化。它同時(shí)從新舊VNode的頭部和尾部開始比較,以快速找到相同且不需要移動(dòng)的節(jié)點(diǎn)。
從兩頭向中間比較:從新舊VNode的頭部和尾部同時(shí)開始比較,如果找到相同的節(jié)點(diǎn),則將這些節(jié)點(diǎn)標(biāo)記為已處理,并繼續(xù)向中間移動(dòng)指針。
快速定位相同節(jié)點(diǎn):由于頭尾比較策略同時(shí)從兩端開始,因此可以更快地定位到相同且不需要移動(dòng)的節(jié)點(diǎn)。這樣可以減少不必要的比較和DOM操作,提高性能。
處理剩余節(jié)點(diǎn):當(dāng)頭部和尾部的指針相遇或交叉時(shí),表示已經(jīng)處理完了所有相同的節(jié)點(diǎn)。此時(shí),如果新VNode中還有剩余節(jié)點(diǎn),Vue會(huì)將這些節(jié)點(diǎn)添加到真實(shí)DOM的末尾;如果舊VNode中還有剩余節(jié)點(diǎn),Vue會(huì)將這些節(jié)點(diǎn)從真實(shí)DOM中刪除。
5. 跳過靜態(tài)節(jié)點(diǎn)
Vue會(huì)對模板中的靜態(tài)內(nèi)容進(jìn)行優(yōu)化,以減少更新時(shí)的性能消耗。
例如,如果一個(gè)節(jié)點(diǎn)的內(nèi)容是靜態(tài)的(即不會(huì)隨數(shù)據(jù)變化而變化),Vue會(huì)將其標(biāo)記為靜態(tài)節(jié)點(diǎn),并在后續(xù)的DIFF過程中跳過這些節(jié)點(diǎn)的比較。
通過以上優(yōu)化策略,diff算法可以更加高效地找出新舊VNode之間的差異,并以最小化的代價(jià)更新真實(shí)的DOM。這些優(yōu)化策略使得Vue在處理大量DOM更新時(shí)能夠保持較高的性能。
6. 唯一標(biāo)識(shí)key
詳見下文
三、vue for 循環(huán)中 key 的作用
key是給每一個(gè)vnode的唯一id,可以根據(jù)key,更準(zhǔn)確、 更快的找到對應(yīng)的vnode節(jié)點(diǎn)。幫助Vue跟蹤每個(gè)節(jié)點(diǎn)的身份,以便在數(shù)據(jù)改變時(shí)能夠高效地更新虛擬DOM。
在新舊虛擬DOM的對比過程中看是否能找到相同的key:
1.有相同的key:(Vue就會(huì)認(rèn)為它們是同一個(gè)節(jié)點(diǎn))
- 若虛擬DOM中的內(nèi)容沒變,則直接復(fù)用之前的真實(shí)DOM
- 若虛擬DOM中的內(nèi)容變了,則生產(chǎn)新的真實(shí)DOM,并替換掉舊的真是DOM
2.沒有相同的key:(Vue就會(huì)認(rèn)為是新節(jié)點(diǎn))
- 根據(jù)數(shù)據(jù)創(chuàng)建新的真是DOM,隨后渲染到頁面
vue中列表循環(huán)需加:key="唯一標(biāo)識(shí)"
唯一標(biāo)識(shí)可以是 item
里面 id
等
因?yàn)関ue組件高度復(fù)用增加 Key 可以標(biāo)識(shí)組件的唯一性,那么 Key 是如何更高效的更新虛擬 DOM 的呢,我們看下面的例子:
<body> <div id="demo"> <p v-for="item in items" :key="item">{{item}}</p> </div> <script src="../../dist/vue.js"></script> <script> // 創(chuàng)建實(shí)例 const app = new Vue({ el: '#demo', data: { items: ['a', 'b', 'c', 'd', 'e'] }, mounted () { setTimeout(() => { this.items.splice(2, 0, 'f') // ['a', 'b', 'f', 'c', 'd', 'e'] }, 2000); }, }); </script> </body>
在不使用key的情況,vue會(huì)進(jìn)行這樣的操作:
分析下整體流程:
- 比較A,A,相同類型的節(jié)點(diǎn),進(jìn)行patch,但數(shù)據(jù)相同,不發(fā)生dom操作
- 比較B,B,相同類型的節(jié)點(diǎn),進(jìn)行patch,但數(shù)據(jù)相同,不發(fā)生dom操作
- 比較C,F(xiàn),相同類型的節(jié)點(diǎn),進(jìn)行patch,數(shù)據(jù)不同,發(fā)生dom操作
- 比較D,C,相同類型的節(jié)點(diǎn),進(jìn)行patch,數(shù)據(jù)不同,發(fā)生dom操作
- 比較E,D,相同類型的節(jié)點(diǎn),進(jìn)行patch,數(shù)據(jù)不同,發(fā)生dom操作
- 循環(huán)結(jié)束,將E插入到DOM中 一共發(fā)生了3次更新,1次插入操作
我們希望可以在B和C之間加一個(gè)F,diff 算法默認(rèn)執(zhí)行起來是這樣的:即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很沒有效率?
所以我們需要使用key來給每個(gè)節(jié)點(diǎn)做一個(gè)唯一標(biāo)識(shí),Diff算法就可以正確的識(shí)別此節(jié)點(diǎn),找到正確的位置區(qū)插入新的節(jié)點(diǎn)。
當(dāng)為v-for渲染的列表項(xiàng)設(shè)置唯一的key時(shí),Vue能夠準(zhǔn)確地識(shí)別每個(gè)列表項(xiàng)的身份。
當(dāng)列表數(shù)據(jù)發(fā)生變化時(shí),Vue會(huì)根據(jù)key來判斷哪些列表項(xiàng)是新添加的、哪些是被刪除的、哪些是需要更新的。 這有助于Vue進(jìn)行高效的DOM更新操作,只更新需要改變的部分,而不是重新渲染整個(gè)列表。
當(dāng)我們在使用v-for時(shí),需要給單元加上key:
- 如果不用key,Vue會(huì)采用就地復(fù)地原則:最小化element的移動(dòng),并且會(huì)嘗試盡最大程度在同適當(dāng)?shù)牡胤綄ο嗤愋偷膃lement,做patch或者reuse。
- 如果使用了key,Vue會(huì)根據(jù)keys的順序記錄element,曾經(jīng)擁有了key的element如果不再出現(xiàn)的話,會(huì)被直接remove或者destoryed
- 用+new Date()生成的時(shí)間戳作為key,手動(dòng)強(qiáng)制觸發(fā)重新渲染
- 當(dāng)擁有新值的rerender作為key時(shí),擁有了新key的Comp出現(xiàn)了,那么舊key Comp會(huì)被移除,新key Comp觸發(fā)渲染
四、Vue 2 與 Vue3 中的區(qū)別
在 Vue 2 中:
- 使用了虛擬 DOM 的技術(shù)來優(yōu)化 DOM 操作。當(dāng)數(shù)據(jù)變化時(shí),Vue 會(huì)生成一個(gè)新的虛擬 DOM 樹,并與舊的虛擬 DOM 樹進(jìn)行比較(這個(gè)過程通常稱為“diff”)。如果發(fā)現(xiàn)有差異,Vue 就會(huì)更新真實(shí)的 DOM。
- 在 Vue 2 的實(shí)現(xiàn)中,這種比較是遞歸進(jìn)行的,會(huì)遍歷整個(gè)虛擬 DOM 樹,即使只有很少的部分發(fā)生了變化。這種策略在某些情況下可能會(huì)導(dǎo)致較高的計(jì)算復(fù)雜度。
- ? 補(bǔ)充:雖然理論上要遍歷全樹,但實(shí)際通過同層比較和 key 優(yōu)化可以跳過部分子樹,并非完全無優(yōu)化。
在 Vue3 中:
區(qū)塊樹(Block Tree) 是Vue 3中引入的一種重要的優(yōu)化機(jī)制,它是Vue 3編譯器在解析模板時(shí)生成的一種樹狀結(jié)構(gòu),它基于模板中的代碼邏輯將模板劃分為多個(gè)區(qū)塊(Block)。
區(qū)塊樹的主要功能是在渲染時(shí)優(yōu)化DOM操作,它可以將模板中的靜態(tài)內(nèi)容和動(dòng)態(tài)內(nèi)容區(qū)分開,從而在更新時(shí)只關(guān)注那些實(shí)際發(fā)生變化的動(dòng)態(tài)內(nèi)容。 通過減少不必要的渲染開銷來提高性能。
- 模板解析:Vue 3編譯器首先會(huì)將模板解析成抽象語法樹(AST),然后遍歷AST,找出其中的連續(xù)節(jié)點(diǎn)塊(Block),并對這些節(jié)點(diǎn)塊進(jìn)行分析和整理,最終形成一個(gè)區(qū)塊樹。
- 靜態(tài)提升(Hoist Static) :在構(gòu)建區(qū)塊樹的過程中,Vue 3會(huì)將靜態(tài)節(jié)點(diǎn)(即不會(huì)改變的節(jié)點(diǎn))提升到渲染函數(shù)之外,從而減少了在每次渲染時(shí)都需要重新創(chuàng)建這些節(jié)點(diǎn)的開銷,徹底避免重復(fù) diff。
- 標(biāo)記動(dòng)態(tài)節(jié)點(diǎn)類型(PatchFlags ):對于動(dòng)態(tài)節(jié)點(diǎn),Vue 3會(huì)在區(qū)塊樹中標(biāo)記它們的變化類型(例如,屬性更新、子節(jié)點(diǎn)更新等)。
- 這些標(biāo)記可以在創(chuàng)建虛擬 DOM 節(jié)點(diǎn)時(shí)生成,并在后續(xù)的 diff 過程中使用。由于有了這些標(biāo)記,Vue 3 在進(jìn)行 diff 時(shí)就可以更有針對性地比較那些實(shí)際發(fā)生變化的節(jié)點(diǎn),根據(jù)這些標(biāo)記快速定位到需要更新的節(jié)點(diǎn),并只對這些節(jié)點(diǎn)進(jìn)行更新,而無需遍歷整個(gè)樹。這顯著減少了比較的范圍和計(jì)算量,從而提高了更新性能。
綜上:
- 將純靜態(tài)節(jié)點(diǎn)提升到渲染函數(shù)外部,避免重復(fù)創(chuàng)建和比較;
- 對動(dòng)態(tài)節(jié)點(diǎn)標(biāo)記 PatchFlags 標(biāo)識(shí)其變化類型(如文本/屬性/子節(jié)點(diǎn));
- 配合區(qū)塊樹結(jié)構(gòu)記錄動(dòng)態(tài)子節(jié)點(diǎn)位置。
- 在 diff 過程中,Vue 3 能夠跳過靜態(tài)節(jié)點(diǎn),并根據(jù) PatchFlags 僅對動(dòng)態(tài)節(jié)點(diǎn)的特定屬性進(jìn)行靶向比對,從而大幅降低計(jì)算復(fù)雜度。
舉例:
<!-- 模板 --> <div> <span>Static</span> <!-- 靜態(tài)提升(Hoist Static) --> <span :class="cls"></span> <!-- 標(biāo)記動(dòng)態(tài)節(jié)點(diǎn)類型(PatchFlags ) class --> <span>{{ text }}</span> <!-- 標(biāo)記動(dòng)態(tài)節(jié)點(diǎn)類型(PatchFlags ) text--> </div>
- Vue 2:比對 3 個(gè) 的所有屬性+子節(jié)點(diǎn)
- Vue 3:完全跳過第一個(gè)靜態(tài) span,僅比對第二個(gè) span 的 class 屬性和第三個(gè) span 的文本內(nèi)容
這種機(jī)制使得 Vue 3 在具有大量靜態(tài)內(nèi)容+局部動(dòng)態(tài)更新的場景下,性能優(yōu)勢尤為明顯。
不建議用index作為key
不建議 用 index
作為 key,和沒寫基本上沒區(qū)別,因?yàn)椴还苣銛?shù)組的順序怎么顛倒,index 都是 0, 1, 2 這樣排列,導(dǎo)致 Vue 會(huì)復(fù)用錯(cuò)誤的舊子節(jié)點(diǎn),做很多額外的工作,效率底。
- 用key會(huì)出問題:對數(shù)據(jù)進(jìn)行破壞順序的的操作(如:在數(shù)組前面或中間添加、刪除數(shù)據(jù))
- 用key不會(huì)出問題:沒有對數(shù)據(jù)進(jìn)行破壞順序的的操作(如:在數(shù)組最后面添加、刪除數(shù)據(jù))
建議key用唯一標(biāo)識(shí),如:id、手機(jī)號(hào)、學(xué)號(hào)等
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue3.0使用ref和reactive來創(chuàng)建響應(yīng)式數(shù)據(jù)
ref?和?reactive?是?Composition?API?中用來創(chuàng)建響應(yīng)式數(shù)據(jù)的兩個(gè)核心函數(shù),在本篇文章中,我們將詳細(xì)講解如何使用?ref?和?reactive?來創(chuàng)建響應(yīng)式數(shù)據(jù),并展示它們之間的區(qū)別和使用場景,需要的朋友可以參考下2024-11-11在Vue環(huán)境下利用worker運(yùn)行interval計(jì)時(shí)器的步驟
這篇文章主要介紹了在Vue環(huán)境下利用worker運(yùn)行interval計(jì)時(shí)器的步驟,本文分步驟給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08在Vue3中使用provide和inject進(jìn)行依賴注入的代碼詳解
在現(xiàn)代前端開發(fā)中,Vue.js已經(jīng)成為了非常流行的框架之一,它提供了極大的靈活性和可維護(hù)性,今天我們要探討的是Vue?3中的provide和inject功能,這是一種用于在組件樹中進(jìn)行依賴注入的方法,需要的朋友可以參考下2024-06-06vue-cli項(xiàng)目中img如何使用require動(dòng)態(tài)獲取圖片
這篇文章主要介紹了vue-cli項(xiàng)目中img如何使用require動(dòng)態(tài)獲取圖片,具有很好的參考價(jià)值,希望對大家有所幫助。2022-09-09Vue中在data里面調(diào)用method方法的實(shí)現(xiàn)
這篇文章主要介紹了Vue中在data里面調(diào)用method方法的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06vite創(chuàng)建vue3項(xiàng)目頁面引用public下js文件失敗解決辦法
Vue3相較于之前的版本有了不少變化,如引用全局Js文件,這篇文章主要給大家介紹了關(guān)于vite創(chuàng)建vue3項(xiàng)目頁面引用public下js文件失敗的解決辦法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11