
虚拟DOM
主要了解一下虚拟DOM,他为什么存在以及解决了什么问题,通过什么方式解决的。
什么是虚拟 DOM 以及他的作用
- 什么是 DOM
在 MDN 的文档中,DOM 的定义是:
文档对象模型 (DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。
其中还有一个重要的概念:
DOM是web页面的完全的面向对象表述,它能够使用如 JavaScript等脚本语言进行修改。
这可以理解为:DOM 对象本身也是一个 js 对象,我们可以通过 js 对 DOM 进行操作。
- 为什么操作 DOM 会慢
我们每一次使用 js 操作 DOM,或者 DOM 每一次细微的改变,都会引发页面的重绘(paint)和重排(layout);
当页面进行大量的频繁的 DOM 操作的时候,重绘和重排的也就被频繁触发,从而导致变慢。
- 什么是虚拟 DOM
既然 DOM 树可以用 js 对象表示,那么反过来,我们也可以用 js 对象表示的树结构来构建一棵真正的 DOM 树。
虚拟 DOM 就是用 js 创建出来的 DOM。
- 为什么虚拟 DOM 可以提高性能表现
频繁地操作 DOM 的触发页面多次渲染,影响性能。
但是使用虚拟 DOM,我们只需要通过对比新的 DOM 树和旧的 DOM 树的不同之处,然后针对差异修改 js 对象,最后把 js 对象所生成的 DOM 树插入到页面中,重新渲染页面,更新视图。
这样虚拟 DOM 就通过触发一次重绘,完成页面的更新,对比于 DOM 的多次重绘,性能表现明显地提高了。
如何实现虚拟 DOM
使用 js 创建一个虚拟 DOM 节点:
class VNode {
constructor(tag,children,text){
this.tag = tag
this.children = children
this.text = text
}
render(){
if(this.tag === '#text'){
return document.createTextNode(this.text)
}
let el = document.createElement(this.tag)
this.children.map((vchild) =>{
el.appendChild(vchild.render())
})
return el
}
}
function createNode(tag,children,text){
if(typeof children === 'string'){
text = children
children = []
}
return new VNode(tag,children,text)
}
let vNodes = createNode('div', [
createNode('p', [
createNode('span', [ createNode('#text', 'xiedaimala.com') ] )
]
),
createNode('span', [
createNode('#text', 'jirengu.com')
])
]
)
console.log(vNodes.render()) // 返回了一个 DOM 节点
将节点挂载到页面某个元素上:
<div id="app"></div>
<script>
let root = document.querySelector('#app)
root.appendChild(vNodes.render())
</script>更新虚拟 DOM (diff):
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', 'xiedaimala.com') ] )
]
),
v('span', [
v('#text', 'jirengu.com')
])
]
)
let vNodes2 = v('div', [
v('p', [
v('span', [
v('#text', 'xiedaimala.com')
] )
]
),
v('span', [
v('#text', 'jirengu.coms'),
v('#text', 'ruoyu')
])
]
)
let root = document.querySelector('#app')
patchElement(root, vNodes1)
参考:
如何理解虚拟DOM?
MDN
虚拟DOM
本文围绕虚拟DOM展开,介绍了其相关知识。先阐述了操作DOM慢的原因是频繁操作会引发页面重绘和重排,而虚拟DOM是用js创建的DOM,通过对比新旧DOM树差异,触发一次重绘完成页面更新,提高了性能,还提及了实现虚拟DOM的方法。


被折叠的 条评论
为什么被折叠?



