欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

幫助我們高效操作的Virtual?DOM簡(jiǎn)單實(shí)現(xiàn)

 更新時(shí)間:2023年06月27日 08:39:28   作者:AshleyLv  
這篇文章主要為大家介紹了幫助我們高效操作Virtual?DOM簡(jiǎn)單實(shí)現(xiàn)及原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

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

關(guān)于vue的Virtual DOM實(shí)現(xiàn)原理將在后面的文章中提到。為了方便理解和學(xué)習(xí),我寫了一個(gè)簡(jiǎn)單的Virtual DOM操作DOM樹(shù)的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主要是用來(lái)對(duì)比新舊vnode的區(qū)別,找出區(qū)別的元素并記錄在directives對(duì)象上,便于接下來(lái)可以通過(guò)directives的內(nèi)容對(duì)舊的vnode進(jìn)行替換,繪制新的DOM.

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

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

我們?cè)赿iff方法中調(diào)用diffVNode來(lái)對(duì)節(jié)點(diǎn)進(jìn)行逐一比較。首先,它會(huì)比較oldVNode和newVNode是否是相同的節(jié)點(diǎn)。如果相同,就對(duì)節(jié)點(diǎn)類型進(jìn)行判斷,來(lái)選擇比較的方法,對(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)過(guò)Diff方法后,我們將得到我們傳入的oldNode與newNode的比較結(jié)果,并記錄在Directives對(duì)象中。

Patch

Patch主要做的是通過(guò)我們之前的比較得到的Directives對(duì)象來(lái)修改Dom樹(shù)。在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
        }
    }
}

具體的更新方法是通過(guò)js來(lái)操作DOM節(jié)點(diǎn)進(jìn)行操作。

完整代碼

以上就是Virtual DOM簡(jiǎn)單實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Virtual DOM簡(jiǎn)單實(shí)現(xiàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue報(bào)錯(cuò)error:0308010C:digital?envelope?routines::unsupported的解決方法

    Vue報(bào)錯(cuò)error:0308010C:digital?envelope?routines::unsupported

    這篇文章主要給大家介紹了關(guān)于Vue報(bào)錯(cuò)error:0308010C:digital?envelope?routines::unsupported的解決方法,文中通過(guò)圖文將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • vue+element表格導(dǎo)出為Excel文件

    vue+element表格導(dǎo)出為Excel文件

    這篇文章主要為大家詳細(xì)介紹了vue+element表格導(dǎo)出為Excel文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • Vue3如何配置多級(jí)代理

    Vue3如何配置多級(jí)代理

    這篇文章主要介紹了Vue3如何配置多級(jí)代理問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • npm安裝vue腳手架報(bào)錯(cuò)警告npm WARN deprecated

    npm安裝vue腳手架報(bào)錯(cuò)警告npm WARN deprecated

    安裝vue腳手架報(bào)錯(cuò)可能具體原因比較多,可以根據(jù)報(bào)錯(cuò)信息進(jìn)行排查,本文主要介紹了npm安裝vue腳手架報(bào)錯(cuò)警告npm WARN deprecated,感興趣的可以了解一下
    2023-11-11
  • 淺析Vue如何巧用computed計(jì)算屬性

    淺析Vue如何巧用computed計(jì)算屬性

    在日常使用Vue開(kāi)發(fā)項(xiàng)目的時(shí)候,計(jì)算屬性computed是一個(gè)非常常用的特性,本文就來(lái)分享一些使用Vue的computed計(jì)算屬性時(shí)的一些小技巧,希望能夠幫助到大家
    2023-06-06
  • vue 之 css module的使用方法

    vue 之 css module的使用方法

    這篇文章主要介紹了vue 之 css module的使用方法,css module目的為所有類名重新生成類名,有效避開(kāi)了css權(quán)重和類名重復(fù)的問(wèn)題,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-12-12
  • nuxt 服務(wù)器渲染動(dòng)態(tài)設(shè)置 title和seo關(guān)鍵字的操作

    nuxt 服務(wù)器渲染動(dòng)態(tài)設(shè)置 title和seo關(guān)鍵字的操作

    這篇文章主要介紹了nuxt 服務(wù)器渲染動(dòng)態(tài)設(shè)置 title和seo關(guān)鍵字的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • Vue2和Vue3中如何使用WebSocker封裝詳解

    Vue2和Vue3中如何使用WebSocker封裝詳解

    如果項(xiàng)目中多個(gè)組件都使用到WebSocket請(qǐng)求,那么我們需要對(duì)WebSocket進(jìn)行封裝,方便我們使用,下面這篇文章主要給大家介紹了關(guān)于Vue2和Vue3中如何使用WebSocker封裝的相關(guān)資料,需要的朋友可以參考下
    2024-07-07
  • vue 自定義組件 v-model雙向綁定、 父子組件同步通信的多種寫法

    vue 自定義組件 v-model雙向綁定、 父子組件同步通信的多種寫法

    父子組件通信,都是單項(xiàng)的,很多時(shí)候需要雙向通信。這篇文章主要介紹了vue 自定義組件 v-model雙向綁定、 父子組件同步通信,需要的朋友可以參考下
    2017-11-11
  • Vue中ref的用法及演示

    Vue中ref的用法及演示

    這篇文章主要介紹了Vue中ref的用法及演示,ref被用來(lái)給元素或子組件注冊(cè)引用信息。引用信息會(huì)被注冊(cè)在父組件上的$refs對(duì)象上,下面來(lái)看看文章的詳細(xì)內(nèi)容,需要的朋友可以參考一下
    2021-11-11

最新評(píng)論