VNode和虛擬DOM


v-for中的key是什么作用?

在使用v-for進行列表渲染時,我們通常會給元素或者組件綁定一個key屬性。
這個key屬性有什么作用呢?我們先來看一下官方的解釋:

  • key屬性主要用在Vue的虛擬DOM算法,在新舊nodes對比時辨識VNodes
  • 如果不使用key,Vue會使用一種最大限度減少動態元素並且盡可能的嘗試就地修改/復用相同類型元素的算法;
  • 使用key時,它會基於key的變化重新排列元素順序,並且會移除/銷毀key不存在的元素;

官方的解釋對於初學者來說並不好理解,比如下面的問題:

  • 什么是新舊nodes,什么是VNode?
  • 沒有key的時候,如何嘗試修改和復用的?
  • 有key的時候,如何基於key重新排列的?

認識VNode

我們先來解釋一下VNode的概念:

  • 因為目前我們還沒有比較完整的學習組件的概念,所以目前我們先理解HTML元素創建出來的VNode;
  • VNode的全稱是Virtual Node,也就是虛擬節點;
  • 事實上,無論是組件還是元素,它們最終在Vue中表示出來的都是一個個VNode(一個個節點);
  • VNode的本質是一個JavaScript的對象;

 

 

 

 

 

虛擬DOM(VDOM 是多個vnode形成的樹結構)

如果我們不只是一個簡單的div,而是有一大堆的元素,那么它們應該會形成一個VNode Tree:

 

 

 

 

 虛擬DOM的好處:做跨平台,可以做服務端渲染、移動端渲染等。

 插入F的案例

 我們先來看一個案例:這個案例是當我點擊按鈕時會在中間插入一個f;

我們可以確定的是,這次更新對於ul和button是不需要進行更新,需要更新的是我們li的列表:

  • 在Vue中,對於相同父元素的子元素節點並不會重新渲染整個列表;
  • 因為對於列表中a、b、c、d它們都是沒有變化的;
  • 在操作真實DOM的時候,我們只需要在中間插入一個f的li即可;

那么Vue中對於列表的更新究竟是如何操作的呢?

  • Vue事實上會對於有key和沒有key會調用兩個不同的方法;
  • 有key,那么就使用patchKeyedChildren方法;
  • 沒有key,那么久使用patchUnkeyedChildren方法;

Vue源碼對於key的判斷

沒有key的操作(源碼)

沒有key的過程如下

我們會發現上面的diff算法效率並不高:

  • c和d來說它們事實上並不需要有任何的改動;
  • 但是因為我們的c被f所使用了,所有后續所有的內容都要一次進行改動,並且最后進行新增;

 有key執行操作(源碼)

 

有key的diff算法如下(一)   

第一步的操作是從頭開始進行遍歷、比較:

  • a和b是一致的會繼續進行比較;
  • c和f因為key不一致,所以就會break跳出循環;

 

 

第二步的操作是從尾部開始進行遍歷、比較:

 

 第三步是如果舊節點遍歷完畢,但是依然有新的節點,那么就新增節點:

 

 第四步是如果新的節點遍歷完畢,但是依然有舊的節點,那么就移除舊節點:

 

 

 第五步是最特色的情況,中間還有很多未知的或者亂序的節點:

 

所以我們可以發現,Vue在進行diff算法的時候,會盡量利用我們的key來進行優化操作:

  • 在沒有key的時候我們的效率是非常低效的;
  • 在進行插入或者重置順序的時候,保持相同的key可以讓diff算法更加的高效;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM