最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

引言

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

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

VNode

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

export default class VNode {
    constructor (tag, nodeType,key, props, text, children){
        this.tag = tag //element類型
        this.nodeType = nodeType //node類型,1為普通節(jié)點,3為文本節(jié)點,8為注釋
        this.key = key
        this.props = props //node的屬性
        this.text = text //文本節(jié)點的內容
        this.children = children//子節(jié)點
    }
    //將vnode渲染成DOM節(jié)點的方法
    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主要是用來對比新舊vnode的區(qū)別,找出區(qū)別的元素并記錄在directives對象上,便于接下來可以通過directives的內容對舊的vnode進行替換,繪制新的DOM.

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

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

我們在diff方法中調用diffVNode來對節(jié)點進行逐一比較。首先,它會比較oldVNode和newVNode是否是相同的節(jié)點。如果相同,就對節(jié)點類型進行判斷,來選擇比較的方法,對于文本和注釋節(jié)點,只需要比較文本內容是否相同即可,對于元素則要比較元素標簽,元素的屬性以及子元素是否相同。

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é)點屬性的方法,對于有變化的屬性我們將變化的部分記在patches這個數(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é)點的方法,子節(jié)點的更新分為增加子節(jié)點,刪除子節(jié)點和移動子節(jié)點三種操作。對于子節(jié)點的操作將被記錄在父節(jié)點的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})
    }
}

在經過Diff方法后,我們將得到我們傳入的oldNode與newNode的比較結果,并記錄在Directives對象中。

Patch

Patch主要做的是通過我們之前的比較得到的Directives對象來修改Dom樹。在Patch方法中如果該節(jié)點涉及到更新,將會調用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方法主要對具體的Dom節(jié)點進行修改。

根據(jù)directives的不同類型,調用不同的方法進行更新。

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é)點進行操作。

完整代碼

以上就是Virtual DOM簡單實現(xiàn)的詳細內容,更多關于Virtual DOM簡單實現(xiàn)的資料請關注腳本之家其它相關文章!

相關文章

  • Vue?非常實用的自定義指令分享

    Vue?非常實用的自定義指令分享

    這篇文章主要介紹了Vue?非常實用的自定義指令分享,Vue自定義指令有全局注冊和局部注冊兩種方式,在?Vue,除了核心功能默認內置的指令?(?v-model?和?v-show?),Vue?也允許注冊自定義指令,下文小編給大家分享那些常用到的Vue自定義指令
    2022-02-02
  • 解決element-ui中Popconfirm氣泡確認框的事件不生效問題

    解決element-ui中Popconfirm氣泡確認框的事件不生效問題

    這篇文章主要介紹了解決element-ui中Popconfirm氣泡確認框的事件不生效問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Vue(element ui)中操作row參數(shù)的使用方式

    Vue(element ui)中操作row參數(shù)的使用方式

    這篇文章主要介紹了Vue(element ui)中操作row參數(shù)的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Vue打包后訪問靜態(tài)資源路徑問題

    Vue打包后訪問靜態(tài)資源路徑問題

    在本篇文章里小編給各位整理的是關于Vue打包后訪問靜態(tài)資源路徑問題相關知識點,需要的朋友們學習下。
    2019-11-11
  • vue中集成省市區(qū)街四級地址組件的實現(xiàn)過程

    vue中集成省市區(qū)街四級地址組件的實現(xiàn)過程

    我們在開發(fā)中常會遇到選擇地址的需求,有時候只需要選擇省就可以,有時候則需要選擇到市、縣,以至于鄉(xiāng)鎮(zhèn),甚至哪個村都有可能,下面這篇文章主要給大家介紹了關于vue中集成省市區(qū)街四級地址組件的相關資料,需要的朋友可以參考下
    2022-12-12
  • 詳解如何使用vue實現(xiàn)可視化界面設計

    詳解如何使用vue實現(xiàn)可視化界面設計

    Vue是一款流行的前端開發(fā)框架,它的響應式數(shù)據(jù)綁定和組件化特性使得它成為了可視化界面設計的一個理想選擇,本文將介紹如何使用Vue實現(xiàn)可視化界面設計,并且演示一個基于Vue的可視化界面設計案例,需要的朋友可以參考下
    2023-12-12
  • vuex 多模塊時 模塊內部的mutation和action的調用方式

    vuex 多模塊時 模塊內部的mutation和action的調用方式

    這篇文章主要介紹了vuex 多模塊時 模塊內部的mutation和action的調用方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • vue的生命周期鉤子與父子組件的生命周期詳解

    vue的生命周期鉤子與父子組件的生命周期詳解

    Vue的生命周期就是vue實例從創(chuàng)建到銷毀的全過程,也就是new Vue() 開始就是vue生命周期的開始。Vue 實例有?個完整的?命周期,也就是從開始創(chuàng)建、初始化數(shù)據(jù)、編譯模版、掛載Dom -> 渲染、更新 -> 渲染、卸載 等?系列過程,稱這是Vue的?命周期
    2022-08-08
  • el-tab設置默認激活的標簽頁實現(xiàn)步驟

    el-tab設置默認激活的標簽頁實現(xiàn)步驟

    這篇文章主要給大家介紹了關于el-tab設置默認激活的標簽頁實現(xiàn)步驟,文中通過代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • vue-cli常用設置總結

    vue-cli常用設置總結

    本文給大家總結了vue-cli常用設置,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2018-02-02

最新評論

尼玛县| 南开区| 札达县| 通海县| 安乡县| 云龙县| 东宁县| 齐齐哈尔市| 贞丰县| 台东市| 广东省| 即墨市| 大英县| 阿图什市| 玛曲县| 苏尼特左旗| 满洲里市| 将乐县| 卢氏县| 炎陵县| 杨浦区| 呼玛县| 乌鲁木齐县| 承德县| 准格尔旗| 绥化市| 白城市| 香港 | 日照市| 滦南县| 泸定县| 宁夏| 盖州市| 晋宁县| 临江市| 金川县| 建平县| 东台市| 百色市| 甘孜县| 白玉县|