1.什么是虚拟DOM,为什么要用虚拟DOM
众所周知,目前前端的两大主流框架vue/react都有一个概念,那就是虚拟DOM;那什么是虚拟DOM呢?
想要了解虚拟DOM首先应该了解浏览器引擎的渲染机制,让我们以webkit为例:
它的渲染大致分为五步:创建DOM tree –> 创建Style Rules -> 构建Render tree -> 布局Layout –> 绘制Painting;
正常情况浏览器是有几个DOM节点更新就会创建多少次DOM Tree,而理想状态是我们这几个DOM节点更新只需要创建一次DOM Tree,这样就会大大的减少浏览器的计算量,从而性能得到很大提升,而虚拟DOM就完美的解决了这个问题,而虚拟DOM其实就是一个js对象,操作js对象对于直接操作DOM更快,最终将js对象转变成DOM Tree,从而实现渲染
2.模拟虚拟DOM
首先我们看看真实的DOM节点:
<div id="real-container">
<p>Real DOM</p>
<div>cannot update</div>
<ul>
<li className="item">Item 1</li>
<li className="item">Item 2</li>
<li className="item">Item 3</li>
</ul>
</div>
用js来模拟它的结构:
const tree = Element('div', { id: 'virtual-container' }, [
Element('p', {}, ['Virtual DOM']),
Element('div', {}, ['before update']),
Element('ul', {}, [
Element('li', { class: 'item' }, ['Item 1']),
Element('li', { class: 'item' }, ['Item 2']),
Element('li', { class: 'item' }, ['Item 3']),
]),
]);
const root = tree.render();
document.getElementById('virtualDom').appendChild(root);
具体实现:
function Element(tagName, props, children) {
if (!(this instanceof Element)) {
return new Element(tagName, props, children);
}
this.tagName = tagName;
this.props = props || {};
this.children = children || [];
this.key = props ? props.key : undefined;
let count = 0;
this.children.forEach((child) => {
if (child instanceof Element) {
count += child.count;
}
count++;
});
this.count = count;
}
实现渲染:
Element.prototype.render = function() {
const el = document.createElement(this.tagName);
const props = this.props;
for (const propName in props) {
setAttr(el, propName, props[propName]);
}
this.children.forEach((child) => {
const childEl = (child instanceof Element) ? child.render() : document.createTextNode(child);
el.appendChild(childEl);
});
return el;
};