Virtual-DOM的理解
Opened this issue · 0 comments
jinjiaxing commented
什么是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,才是更核心的东西,我们后续再去研究它