1. 程式人生 > 實用技巧 >vue-虛擬dom

vue-虛擬dom

虛擬dom

頻繁且複雜的dom操作通常是前端效能瓶頸的產生點,Vue提供了虛擬dom的解決辦法

虛擬的DOM的核心思想是:對複雜的文件DOM結構,提供一種方便的工具,進行最小化地DOM操作。這句話,也許過於抽象,卻基本概況了虛擬DOM的設計思想

(1) 提供一種方便的工具,使得開發效率得到保證
(2) 保證最小化的DOM操作,使得執行效率得到保證

也就是說,虛擬dom的框架/工具都是這麼做的:

  1. 根據虛擬dom樹最初渲染成真實dom
  2. 當資料變化,或者說是頁面需要重新渲染的時候,會重新生成一個新的完整的虛擬dom
  3. 拿新的虛擬dom來和舊的虛擬dom做對比(使用diff演算法)。得到需要更新的地方之後,更新內容

這樣的話,就能大量減少真實dom的操作,提高效能

什麼是虛擬dom?與key值的關係?
Virual DOM是用JS物件記錄一個dom節點的副本,當dom發生更改時候,先用虛擬dom進行diff,算出最小差異,然後再修改真實dom。

當用傳統的方式操作DOM的時候,瀏覽器會從構建DOM樹開始從頭到尾執行一遍流程,效率很低。而虛擬DOM是用javascript物件表示的,而操作javascript是很簡便高效的。虛擬DOM和真正的DOM有一層對映關係,很多需要操作DOM的地方都會去操作虛擬DOM,最後統一一次更新DOM。因而可以提高效能

虛擬DOM的Diff演算法

虛擬DOM中,在DOM的狀態發生變化時,虛擬DOM會進行Diff運算,來更新只需要被替換的DOM,而不是全部重繪。
在Diff演算法中,只平層的比較前後兩棵虛擬DOM樹的節點,沒有進行深度的遍歷。

1.如果節點型別改變,直接將舊節點解除安裝,替換為新節點,舊節點包括下面的子節點都將被解除安裝,如果新節點和舊節點僅僅是型別不同,但下面的所有子節點都一樣時,這樣做也是效率不高的一個地方。
2.節點型別不變,屬性或者屬性值改變,不會解除安裝節點,執行節點更新的操作。
3.文字改變,直接修改文字內容。
4.移動,增加,刪除子節點時:

如果想在中間插入節點F,簡單粗暴的做法是:解除安裝C,裝載F,解除安裝D,裝載C,解除安裝E,裝載D,裝載E。如下圖:

寫程式碼時,如果沒有給陣列或列舉型別定義一個key,就會採用上面的粗暴演算法。
如果為元素增加key後,Vue就能根據key,直接找到具體的位置進行操作,效率比較高。如下圖:

本尋著key值相同的即可複用的原則。

在v-for中提供key,一方面可以提高效能,一方面也會避免出錯

虛擬dom流程
<body>    
    <div id="content">
        <p>2</p>
        <ul class="list-group">
            
        </ul>
    </div>
    <!-- <div id="myp">1</div> -->
    <script src="./base/vue.js"></script>
    <script>
        //vue內部引入了虛擬dom概念 (js記憶體物件) 屬於記憶體資料,真實dom的一層對映
        //1.vue在記憶體中生成一顆虛擬dom樹
        var vDom = {
            tag:"div",
            attr:{
                id:"content"
            },
            children:[
                {tag:"p",content:"2"},
                {tag:"ul",attr:{className:'list-group'}}
            ]
        }
        //2.將記憶體中的虛擬dom樹將其初始化渲染,渲染成一顆真實dom樹
        //3.當我們修改vue例項中的data資料的時候
        this.arr.push("<li>11111</li><li>22222</li>")   
        //4.將之前的虛擬dom樹結合更新的資料生成一顆新的虛擬dom
        var newDom = {
            tag:"div",
            attr:{
                id:"content"
            },
            children:[
                {tag:"p",content:"2"},
                {tag:"ul",attr:{className:'list-group'},children:[
                    {tag:"li",content:"11111"},
                    {tag:"li",content:"22222"}
                ]}
            ]
        }
        //5.將此次生成的新的虛擬dom與上一次的虛擬dom結構進行比對,對比差異(diff演算法)
        //6.將對比的差異的部分進行重新的真實dom的渲染。
    </script>
</body>