成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

自己實現(xiàn)一個簡單的虛擬 DOM

luffyZh / 1399人閱讀

摘要:直到內(nèi)部的全部循環(huán)結(jié)束為止,才進入下一個元素,當循環(huán)結(jié)束時,內(nèi)部的節(jié)點都已經(jīng)生成好了。

自己實現(xiàn)虛擬 DOM 從 HTML 中提煉數(shù)據(jù)結(jié)構(gòu)

先來看下我們的 HTML

傅雷家書

讀家書,想付雷

從 HTML 中我們可以抽離出它的數(shù)據(jù)結(jié)構(gòu):

首先頁面中只需要一個根節(jié)點root,定義為:nodesDate數(shù)組

root內(nèi)有兩個子元素h1span,數(shù)組有兩項,每項為內(nèi)容為tagchildren

接下來內(nèi)部所有元素都是如此定義,直到遇到文本元素,將他定義為text

nodesDate = {
    tag:"div",
    children:[{
        tag:"h1",
        children:[{
            tag:"span",
            children:[{
                tag:"#text",
                text:"傅雷家書"
            }]
        }]
    },{
        tag:"span",
        children:[{
            tag:"#text",
            text:"讀家書,想傅雷"
        }]
    }]
}

用這種視野在看 HTML 的話,就不是單純的 HTML 了,而是一堆hash

從上面數(shù)據(jù)結(jié)構(gòu)中我們可以提煉出3個有用的屬性,分別是tag、children、text,那我們是不是可以定義一個方法,傳遞這三個參數(shù),就能滿足我們的需求呢?

構(gòu)造 HTML 方法

想一下我們拿到這三個參數(shù)后,要干什么呢?

當然是在頁面中生成 DOM 元素??!

對,這三個參數(shù)是我們各自私有屬性,通過這三個屬性能生成各自的 DOM,生成 DOM 的方法是不是公用的呢?

所以可以用用構(gòu)造函數(shù)模式創(chuàng)建我們要的方法,(PS:之前講過new操作符的背后的邏輯,不理解的可移步:使用 new 操作符內(nèi)部到底在做什么)

function vNode(tag,children,text){
    this.tag = tag
    this.children = children
    this.text = text
}

vNode.prototype.render = function(){
    //如 tag 為文本的話,創(chuàng)建一個文本節(jié)點
    if(this.tag === "#text"){
        return document.createTextNode(this.text)    // 返回文本
    }
    
    //tag 不是文本的話,創(chuàng)建一個 DOM 節(jié)點,并且遍歷 children,每次遍歷都是調(diào)用自身的 render 方法
    let element = document.createElement(this.tag)
    this.children.forEach((vChild)=> {
        element.appendChild(vChild.render())    //在遍歷 h1 時,沒有直接跳出,而是在其內(nèi)部不斷循環(huán)。直到 h1 內(nèi)部的 children 全部循環(huán)結(jié)束為止,才進入下一個元素 span,當 h1 循環(huán)結(jié)束時,h1 內(nèi)部的節(jié)點都已經(jīng)生成好了。
    })
    return element        //返回節(jié)點
}

function v(tag,children,text){
    //如果 chilren 為字符串,那么就把 children 賦值給 text,并把 children 初始化為 [],不然后面會報錯
    if(typeof children === "string"){
        text = children
        children = []
    }
    return new vNode(tag,children,text)
}

//格式參見 nodesData,vNode 的實例化
let vNodes = v("div",[
    v("h1",[
        v("span",[
            v("#text","傅雷家書")])
    ]),
    v("span",[
        v("#text","——傅敏")])
])

const root = document.querySelector(".root")    //獲取 root 節(jié)點
root.appendChild(vNodes.render())    //這里只運行一次,把最終的 DOM 添加進頁面中
實現(xiàn)增刪改

如果此時一個數(shù)據(jù)變動比如,按照以前的邏輯

root.innerText = ""
root.appendChild(vNodes.render())

如果數(shù)據(jù)非常大,用這種方法根本沒啥意義,每一次改動 DOM 樹都要重新渲染一遍,造成性能低下,有什么好的方法可以實現(xiàn)呢?

function patchElement(parent, newVNodes, oldVNodes, index = 0) {
    //如果沒有傳遞老的 VNodes,默認就是新的
    if(!oldVNodes) {
        parent.appendChild(newVNodes.render())
      } else if(!newVNodes) {
        parent.removeChild(parent.childNodes[index])
      } else if(newVNodes.tag !== oldVNodes.tag || newVNodes.text !== oldVNodse.text) {    
          //如果元素不一樣或者文本不一樣,走這邊
          //當有走這邊時,newVNodes 是和 oldVNodes 不同的那個值,這里的 parent 是當前元素或文本的 parent
          //replaceChild(sp1,sp2),是將 sp2 換成 sp1
        parent.replaceChild(newVNodes.render(), parent.childNodes[index])
      } else {
        for(let i = 0; i < newVNodes.children.length || i < oldVNodes.children.length; i++) {
        //取值永遠是 newVNodes.length,除非不傳 newVNodes
        //這里 index 只有當 i 變化時,下一次才是 index 才等于 i 的值
        //當 i = 0 時,這次的 parent.childNode[index],是下一次的 parent,所以這里要用 index
        //當循環(huán)走完,發(fā)現(xiàn)元素或者文本不一樣時,才走第三個邏輯
              patchElement(parent.childNodes[index], newVNodes.children[i], oldVNodes.children[i], i)
        }
      }
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/96998.html

相關(guān)文章

  • 虛擬DOM

    摘要:什么是虛擬舉例說明如果網(wǎng)頁中有一個表格,表頭是姓名,年級,分數(shù)。即我們用虛擬的結(jié)構(gòu)替換需要處理的結(jié)構(gòu),對虛擬的進行操作之后再進行渲染,就成為了真實的數(shù)據(jù)。當狀態(tài)變更的時候用修改后的新渲染的的對象和舊的虛擬對象作對比,記錄著兩棵樹的差異。 虛擬DOM 可以看看這個文章如何理解虛擬DOM? - 戴嘉華的回答 - 知乎 https://www.zhihu.com/questio... 深度剖...

    yanwei 評論0 收藏0
  • 虛擬DOM

    摘要:什么是虛擬舉例說明如果網(wǎng)頁中有一個表格,表頭是姓名,年級,分數(shù)。即我們用虛擬的結(jié)構(gòu)替換需要處理的結(jié)構(gòu),對虛擬的進行操作之后再進行渲染,就成為了真實的數(shù)據(jù)。當狀態(tài)變更的時候用修改后的新渲染的的對象和舊的虛擬對象作對比,記錄著兩棵樹的差異。 虛擬DOM 可以看看這個文章如何理解虛擬DOM? - 戴嘉華的回答 - 知乎 https://www.zhihu.com/questio... 深度剖...

    alin 評論0 收藏0
  • 從零開始實現(xiàn)一個React(一):JSX和虛擬DOM

    摘要:前言是前端最受歡迎的框架之一,解讀其源碼的文章非常多,但是我想從另一個角度去解讀從零開始實現(xiàn)一個,從層面實現(xiàn)的大部分功能,在這個過程中去探索為什么有虛擬為什么這樣設(shè)計等問題。 前言 React是前端最受歡迎的框架之一,解讀其源碼的文章非常多,但是我想從另一個角度去解讀React:從零開始實現(xiàn)一個React,從API層面實現(xiàn)React的大部分功能,在這個過程中去探索為什么有虛擬DOM、d...

    曹金海 評論0 收藏0
  • 如何編寫自己虛擬DOM

    摘要:要構(gòu)建自己的虛擬,需要知道兩件事?,F(xiàn)在來看看如何處理上面描述的所有情況。代碼如下節(jié)點的替換首先,需要編寫一個函數(shù)來比較兩個節(jié)點舊節(jié)點和新節(jié)點,并告訴節(jié)點是否真的發(fā)生了變化??偨Y(jié)現(xiàn)在我們已經(jīng)編寫了虛擬實現(xiàn)及了解它的工作原理。 showImg(https://segmentfault.com/img/bVbmPue?w=2000&h=684); 要構(gòu)建自己的虛擬DOM,需要知道兩件事。你甚...

    mushang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<