国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Virtual DOM的簡(jiǎn)單實(shí)現(xiàn)

sf_wangchong / 521人閱讀

摘要:的實(shí)現(xiàn)了一套高效的算法來快速的比對(duì)更新樹。關(guān)于的實(shí)現(xiàn)原理將在后面的文章中提到。對(duì)于子節(jié)點(diǎn)的操作將被記錄在父節(jié)點(diǎn)的上。方法主要對(duì)具體的節(jié)點(diǎn)進(jìn)行修改。

之前在看vue的源碼時(shí)了解了vue關(guān)于Virtual DOM的一些想法,Virtual DOM可以幫助我們更高效的操作DOM。它通過實(shí)現(xiàn)一個(gè)vnode的js對(duì)象,vnode的對(duì)象與dom的node對(duì)象是一一對(duì)應(yīng)的,通過我們對(duì)vnode的操作可以實(shí)現(xiàn)對(duì)dom的操作,這樣就可以避免頻繁的dom操作帶來的效率問題。vue的Virtual DOM實(shí)現(xiàn)了一套高效的diff算法來快速的比對(duì)更新dom樹。

關(guān)于vue的Virtual DOM實(shí)現(xiàn)原理將在后面的文章中提到。為了方便理解和學(xué)習(xí),我寫了一個(gè)簡(jiǎn)單的Virtual DOM操作DOM樹的demo。這里是完整代碼以及DOM

VNode

首先,創(chuàng)建vnode的對(duì)象,vnode記錄相應(yīng)的DOM對(duì)象的一些屬性。

export default class VNode {

    constructor (tag, nodeType,key, props, text, children){
        this.tag = tag //element類型
        this.nodeType = nodeType //node類型,1為普通節(jié)點(diǎn),3為文本節(jié)點(diǎn),8為注釋
        this.key = key
        this.props = props //node的屬性
        this.text = text //文本節(jié)點(diǎn)的內(nèi)容
        this.children = children//子節(jié)點(diǎn)
    }
    //將vnode渲染成DOM節(jié)點(diǎn)的方法
    render(){
        var el
        if(this.nodeType===1){
            el = document.createElement(this.tag)
            for(let prop in this.props){
                setAttr(el,prop,this.props[prop])
            }
            if(this.children){
                this.children.forEach(function(ch,i){
                    el.appendChild(ch.render())
                })

            }
        } else if(this.nodeType===3){
            el = document.createTextNode(this.text)
        } else if(this.nodeType===8){
            el = document.createComment(this.text)
        }
        el.key = this.key
        return el

    }
}

function setAttr(node,key,value){
    if(key==="style"){
        for(let val in value){
            node.style[val] = value[val]
        }
    } else {
        node.setAttribute(key,value)
    }
}
Diff

diff主要是用來對(duì)比新舊vnode的區(qū)別,找出區(qū)別的元素并記錄在directives對(duì)象上,便于接下來可以通過directives的內(nèi)容對(duì)舊的vnode進(jìn)行替換,繪制新的DOM.

這是diff的入口方法,參數(shù)是舊的vnode和新的vnode,directives是用來記錄每個(gè)節(jié)點(diǎn)的改變情況的對(duì)象。

export default function diff(oldVNode, newVNode){
    directives = {}
    diffVNode(oldVNode,newVNode,directives)
    return directives

}

我們?cè)赿iff方法中調(diào)用diffVNode來對(duì)節(jié)點(diǎn)進(jìn)行逐一比較。首先,它會(huì)比較oldVNode和newVNode是否是相同的節(jié)點(diǎn)。如果相同,就對(duì)節(jié)點(diǎn)類型進(jìn)行判斷,來選擇比較的方法,對(duì)于文本和注釋節(jié)點(diǎn),只需要比較文本內(nèi)容是否相同即可,對(duì)于元素則要比較元素標(biāo)簽,元素的屬性以及子元素是否相同。

function diffVNode(oldVNode,newVNode){

    if(newVNode && isSameTypeNode(oldVNode,newVNode)){
        if(newVNode.nodeType===3 || newVNode.nodeType===8){
            if(oldVNode.text !== newVNode.text){
                addDirectives(newVNode.key,{type:TEXT, content: newVNode.text})
            }
        } else if(newVNode.nodeType===1){
            if(oldVNode.tag === newVNode.tag && oldVNode.key == newVNode.key){
                var propPatches = diffProps(oldVNode.props, newVNode.props)
                if(Object.keys(propPatches).length>0){
                    addDirectives(newVNode.key,{type:PROP, content: propPatches})
                }
                if(oldVNode.children || newVNode.children)
                    diffChildren(oldVNode.children,newVNode.children,newVNode.key)
            }
        }
    }
    return directives
}

這是比較節(jié)點(diǎn)屬性的方法,對(duì)于有變化的屬性我們將變化的部分記在patches這個(gè)數(shù)組里。

function diffProps(oldProps,newProps){
    let patches={}
    if(oldProps){
        Object.keys(oldProps).forEach((prop)=>{
            if(prop === "style" && newProps[prop]){
                let newStyle = newProps[prop]
                let isSame = true
                Object.keys(oldProps[prop]).forEach((item)=>{
                    if(prop[item] !== newStyle[item]){
                        isSame = false
                    }
                })
                if(isSame){
                    Object.keys(newStyle).forEach((item)=>{
                        if(!prop.hasOwnProperty(item)){
                            isSame = false
                        }
                    })
                }
                if(!isSame)
                    patches[prop] = newProps[prop]
            }
            if(newProps[prop] !== oldProps[prop]){
                patches[prop] = newProps[prop]
            }
        })
    }
    if(newProps){
       Object.keys(newProps).forEach((prop)=>{
        if(!oldProps.hasOwnProperty(prop)){
            patches[prop] = newProps[prop]
        }
    })
   }
   
    return patches
} 

下面是比較子節(jié)點(diǎn)的方法,子節(jié)點(diǎn)的更新分為增加子節(jié)點(diǎn),刪除子節(jié)點(diǎn)和移動(dòng)子節(jié)點(diǎn)三種操作。對(duì)于子節(jié)點(diǎn)的操作將被記錄在父節(jié)點(diǎn)的directives上。

function diffChildren(oldChildren,newChildren,parentKey){
    oldChildren = oldChildren || []
    newChildren = newChildren || []
    let movedItem = []
    let oldKeyIndexObject = parseNodeList(oldChildren)
    let newKeyIndexObject = parseNodeList(newChildren)
    for(let key in newKeyIndexObject){
        if(!oldKeyIndexObject.hasOwnProperty(key)){
            addDirectives(parentKey,{type:INSERT,index:newKeyIndexObject[key],node:newChildren[newKeyIndexObject[key]]})
        }
    }
    for(let key in oldKeyIndexObject){
        if(newKeyIndexObject.hasOwnProperty(key)){
            if(oldKeyIndexObject[key] !== newKeyIndexObject[key]){
                let moveObj = {"oldIndex":oldKeyIndexObject[key],"newIndex":newKeyIndexObject[key]}
                movedItem[newKeyIndexObject[key]] = oldKeyIndexObject[key]
            }
            diffVNode(oldChildren[oldKeyIndexObject[key]],newChildren[newKeyIndexObject[key]])
        } else {
            addDirectives(key,{type:REMOVE,index:oldKeyIndexObject[key]})
        }
    }
    if(movedItem.length>0){
        addDirectives(parentKey,{type:MOVE, moved:movedItem})
    }
    
}

在經(jīng)過Diff方法后,我們將得到我們傳入的oldNode與newNode的比較結(jié)果,并記錄在Directives對(duì)象中。

Patch

Patch主要做的是通過我們之前的比較得到的Directives對(duì)象來修改Dom樹。在Patch方法中如果該節(jié)點(diǎn)涉及到更新,將會(huì)調(diào)用applyPatch方法。

export default function patch(node,directives){
    if(node){
        var orderList = []
        for(let child of node.childNodes){

            patch(child,directives)
        }
        if(directives[node.key]){
            applyPatch(node,directives[node.key])
        }
    }

}

applyPatch方法主要對(duì)具體的Dom節(jié)點(diǎn)進(jìn)行修改。根據(jù)directives的不同類型,調(diào)用不同的方法進(jìn)行更新。

function applyPatch(node, directives){
    
    for(let directive of directives){
        switch (directive.type){
            case TEXT:
                setContent(node,directive.content)
                break
            case PROP:
                setProps(node,directive.content)
                break
            case REMOVE:
                removeNode(node)
                break
            case INSERT:
                insertNode(node,directive.node,directive.index)
            default:
                break
        }
        
    }
}   

具體的更新方法是通過js來操作DOM節(jié)點(diǎn)進(jìn)行操作。
完整代碼

推薦一個(gè)找vue,angular組件的輪子工廠

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/92517.html

相關(guān)文章

  • 一起理解 Virtual DOM

    摘要:具體而言,就是每次數(shù)據(jù)發(fā)生變化,就重新執(zhí)行一次整體渲染。而給出了解決方案,就是。由于只關(guān)注,通過閱讀兩個(gè)庫的源碼,對(duì)于的定位有了更深一步的理解。第二個(gè)而且,技術(shù)本身不是目的,能夠更好地解決問題才是王道嘛。 前言 React 好像已經(jīng)火了很久很久,以致于我們對(duì)于 Virtual DOM 這個(gè)詞都已經(jīng)很熟悉了,網(wǎng)上也有非常多的介紹 React、Virtual DOM 的文章。但是直到前不久...

    Tangpj 評(píng)論0 收藏0
  • 從零開始,手寫一個(gè)簡(jiǎn)易Virtual DOM

    摘要:本文為筆者通過實(shí)際操作,實(shí)現(xiàn)了一個(gè)非常簡(jiǎn)單的,加深對(duì)現(xiàn)今主流前端框架中的理解。用對(duì)象表示樹是用對(duì)象表示,并存儲(chǔ)在內(nèi)存中的。如果類型不一致,那么屬性一定是被更新的。如果有不相等的屬性,則認(rèn)為發(fā)生改變,需要處理的變化。 眾所周知,對(duì)前端而言,直接操作 DOM 是一件及其耗費(fèi)性能的事情,以 React 和 Vue 為代表的眾多框架普遍采用 Virtual DOM 來解決如今愈發(fā)復(fù)雜 Web ...

    forrest23 評(píng)論0 收藏0
  • 你不知道Virtual DOM(二):Virtual Dom更新

    摘要:變化的只有種更新和刪除。頁面的元素的數(shù)量隨著而變。四總結(jié)本文詳細(xì)介紹如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的算法,再根據(jù)計(jì)算出的差異去更新真實(shí)的。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 目前最流行的兩大前端框架,React 和 Vue,都不約而同的借助 Virtual DOM 技術(shù)提高頁面的渲染...

    testbird 評(píng)論0 收藏0
  • 你不知道Virtual DOM(一):Virtual Dom介紹

    摘要:不同的框架對(duì)這三個(gè)屬性的命名會(huì)有點(diǎn)差別,但表達(dá)的意思是一致的。它們分別是標(biāo)簽名屬性和子元素對(duì)象。我們先來看下頁面的更新一般會(huì)經(jīng)過幾個(gè)階段。元素有可能是數(shù)組的形式,需要將數(shù)組解構(gòu)一層。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 目前最流行的兩大前端框架,React和Vue,都不約...

    lavor 評(píng)論0 收藏0
  • 構(gòu)建一個(gè)使用 Virtual-DOM 前端模版引擎

    摘要:目錄前言問題的提出模板引擎和結(jié)合的實(shí)現(xiàn)編譯原理相關(guān)模版引擎的詞法分析語法分析與抽象語法樹代碼生成完整的結(jié)語前言本文嘗試構(gòu)建一個(gè)前端模板引擎,并且把這個(gè)引擎和進(jìn)行結(jié)合。于是就構(gòu)思了一個(gè)方案,在前端模板引擎上做手腳。 作者:戴嘉華 轉(zhuǎn)載請(qǐng)注明出處并保留原文鏈接( https://github.com/livoras/blog/issues/14 )和作者信息。 目錄 前言 問題的提出...

    imccl 評(píng)論0 收藏0
  • 你不知道Virtual DOM(四):key作用

    摘要:最后里面沒有第四個(gè)元素了,才會(huì)把蘋果從移除。四總結(jié)本文基于上一個(gè)版本的代碼,加入了對(duì)唯一標(biāo)識(shí)的支持,很好的提高了更新數(shù)組元素的效率。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 目前最流行的兩大前端框架,React和Vue,都不約而同的借助Virtual DOM技術(shù)提高頁面的渲染...

    DirtyMind 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<