vdom(虚拟DOM)

vdom就是用JS模拟DOM结构,DOM变化的对比放在JS层来坐,提高重绘性能

 

首先先来看下DOM节点body的属性,下图可以看出属性非常大,所以DOM的操作是“昂贵”的,js的运行效率高,将dom的对比放在js层提高效率,我们要尽量减少DOM的操作,项目越复杂,DOM操作影响越严重

 

如何用JS模拟DOM结构,如下

  • 111
//js模拟 { tag:'ul', attrs: { id: 'test' } children: [ { tag: 'li', attrs: { //为什么用className来表达class,因为class是js保留字,不可以使用 className: 'item' }, children: [ '111' ] } ] }

 

vdom的库有snabbdom,核心函数有patch,使用如图

vdom(虚拟DOM)_第1张图片

vdom的核心是diff算法,就是找出DOM必需更新的节点来更新,其他的不变(类似于Git两个js文件代码的对比),实现patch(container,  vnode)大概如下(内容很复杂,这个只是一个最简单的了解):

//patch(container, vnode)
function createElement(vnode) {
    var tag = vnode.tag
    var attrs = vnode.attrs || {}
    var children = vnode.children || []
    if (!tag) {
        return null
    }
    var elem = document.createElement(tag)
    var attrName
    for (attrName in attrs) {
        if (attrs.hasOwnProperty(attrName)) {
            elem.setAttribute(attrName, attrs[attrName])
        }
    }
    children.forEach(function (childVnode) {
        //递归调用创建子元素
        elem.appendChild(createElement(childVnode))
    })
    return elem
}

实现patch(vnode,  newVnode)简单大概如下(内容很复杂,这个只是一个最简单的了解):

//vnode
{
    tag:'ul',
    attrs: {
        id: 'test'
    }
    children: [
        {
            tag: 'li',
            attrs: {
                //为什么用className来表达class,因为class是js保留字,不可以使用 
                className: 'item'     
            },
            children: [
                '111'
            ]
        }
    ]
}

//newVnode

{
    tag:'ul',
    attrs: {
        id: 'test'
    }
    children: [
        {
            tag: 'li',
            attrs: {
                //为什么用className来表达class,因为class是js保留字,不可以使用 
                className: 'item'     
            },
            children: [
                '111'
            ]
        },
        {
            tag: 'li',
            attrs: {
                //为什么用className来表达class,因为class是js保留字,不可以使用 
                className: 'item'     
            },
            children: [
                '222'
            ]
        }
    ]
}


//patch(vnode, newVnode)

function update(vnode, newVnode) {
    var children = vnode.children
    var newChildren = newVnode.children
    children.forEach(function (child, index) {
        var newChild = newChildren[index]
        if(newChild == null){
            return
        }
        if (child.tag == newChild.tag) {  //如果当前节点一样,则递归调用对比子节点
            update(child, newChild)
        }else{
            replaceNode(child, newChild)    //如果节点不一样,直接替换当前节点
        }
    })
}

 

你可能感兴趣的:(js)