Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Virtual-DOM的理解 #17

Open
jinjiaxing opened this issue Apr 20, 2019 · 0 comments
Open

Virtual-DOM的理解 #17

jinjiaxing opened this issue Apr 20, 2019 · 0 comments

Comments

@jinjiaxing
Copy link
Owner

什么是DOM?

在说Virtual-DOM之前,我们来先说下什么是DOM,DOM从字面上来理解是文档对象模型。

W3C对DOM的定义是:“一个与系统平台和编程语言无关的接口,程序和脚本可以通过这个接口动态地访问和修改文档内容、结构和样式。”

而从上面的定义总结来看,DOM是接口,这个接口可以操作文档。

而文档呢就是Document,在HTML中的Document,可以简单理解成一个节点树,而我们要将这个节点树映射成对象,而对象中自然就存在属性和方法了,其中这些方法就让我们可以操作文档(好像说的还是有点绕)

什么是Virtual-DOM?

Virtual-DOM翻译过来就是虚拟DOM,而它其实可以简单理解为,通过JS去创建的表示DOM的对象,并且未加载到真实页面中

  • virtual-dom = js对象
  • 未渲染到页面中

有人说用virtual-dom比真实dom快,其实这是相对的,virtual-dom很多时候都不是最优的操作,但它具有普适性,在效率、可维护性之间达平衡

在网上看到一段代码,比较简洁的描述了如何去创建一个virtual-dom:

//建立一个VNode的对象
class VNode {
    constructor(tag, children, text) {
        this.tag = tag
        this.text = text
        this.children = children
    }

    render() {
        if (this.tag === '#text') {
            return document.createTextNode(this.text)
        }
        let el = document.createElement(this.tag)
        this.children.forEach(vChild => {
            el.appendChild(vChild.render())
        })
        return el
    }
}

function v(tag, children, text) {
    if (typeof children === 'string') {
        text = children
        children = []
    }
    return new VNode(tag, children, text)
}

/*
let nodesData = {
  tag: 'div',
  children: [
{
  tag: 'p',
  children: [
    {
      tag: 'span',
      children: [
        {
          tag: '#text',
          text: 'baidu'
        }
      ]
    }
  ]
},
{
  tag: 'span',
    children: [
      {
        tag: '#text',
        text: 'alibaba'
      }
    ]
}
]
}

 */

let vNodes = v('div', [
    v('p', [
        v('span', [v('#text', 'baidu')])
    ]
    ),
    v('span', [
        v('#text', 'alibaba')
    ])
]);
console.log(vNodes.render())//建立真实DOM

// 对比DOM树变更
function patchElement(parent, newVNode, oldVNode, index = 0) {
    if (!oldVNode) {
        parent.appendChild(newVNode.render())
    } else if (!newVNode) {
        parent.removeChild(parent.childNodes[index])
    } else if (newVNode.tag !== oldVNode.tag || newVNode.text !== oldVNode.text) {
        parent.replaceChild(newVNode.render(), parent.childNodes[index])
    } else {
        for (let i = 0; i < newVNode.children.length || i < oldVNode.children.length; i++) {
            patchElement(parent.childNodes[index], newVNode.children[i], oldVNode.children[i], i)
        }
    }
}


let vNodes1 = v('div', [
    v('p', [
        v('span', [v('#text', 'baidu')])
    ]
    ),
    v('span', [
        v('#text', 'ali')
    ])
]
)//虚拟DOM1

let vNodes2 = v('div', [
    v('p', [
        v('span', [
            v('#text', 'jd')
        ])
    ]
    ),
    v('span', [
        v('#text', 'baidu'),
        v('#text', 'map')
    ])
]
)//虚拟DOM2
const root = document.querySelector('#root')
patchElement(root, vNodes1) //对比更新

我们从上面的代码可以清晰的看到 vdom的简单流程

vue2引入的vdom是基于snabbdom进行的修改而来,对于snabbdom的源码解析,我们可以看这里

react的diff算法,在16版本之前,与vue2应该大同小异
而在react16之后的fiber,采用了不同的方式

上面只是简单的介绍了下virtual-dom的概念而已,而对于具体到底是如何进行vdom之间的diff,才是更核心的东西,我们后续再去研究它

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant