1.为什么需要虚拟DOM
JS操作DOM速度很慢,但是内存的速度很快
如何把DOM结构用JS对象表示出来,再用JS对象一次性修改DOM,成为了开发者的目标。
2.什么是虚拟DOM
表示DOM的JS对象
通过velement方法将当前js对象转换成DOM节点
比如这种
var vdom = VElement('div', {
'id': 'container'
}, [
VElement('h1', {
style: 'color:red'
}, ['simple virtual dom']),
VElement('p', ['hello world']),
VElement('ul', [VElement('li', ['item #1']), VElement('li', ['item #2'])]),
]);
虚拟DOM基本步骤
1.页面初始加载解析DOM树,将DOM解析为JS对象
[最终还需要将其映射成真实DOM,渲染到页面]
2.DOM结构要发生变化,生成一个新的JS对象
3.DIFF比较,比较同级对象
4.将不同之处写入到patch对象中
5.渲染到页面
下面是将JS对象转换为DOM的小案例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="container">
</div>
</body>
<script type="text/javascript" src="jq.js">
</script>
<script type="text/javascript">
var VElement = function(tagName, props, children) {
//保证只能通过如下方式调用:new VElement
if (!(this instanceof VElement)) {
return new VElement(tagName, props, children);
}
//可以通过只传递tagName和children参数
if (Array.isArray(props)) {
children = props;
props = {};
}
//设置虚拟dom的相关属性
this.tagName = tagName;
this.props = props || {};
this.children = children || [];
this.key = props ? props.key : void 666;
var count = 0;
$.each(this.children, function(child, i) {
if (child instanceof VElement) {
count += child.count;
} else {
children[i] = '' + child;
}
count++;
});
this.count = count;
}
VElement.prototype.render = function() {
//创建标签
var el = document.createElement(this.tagName);
//设置标签的属性
var props = this.props;
for (var propName in props) {
var propValue = props[propName]
el.setAttribute(propName, propValue)
}
//依次创建子节点的标签
$.each(this.children, function(index, child) {
//如果子节点仍然为velement,则递归的创建子节点,否则直接创建文本类型节点
var childEl = (child instanceof VElement) ? child.render() : document.createTextNode(child);
el.appendChild(childEl);
});
return el;
}
var vdom = VElement('div', {
'id': 'container'
}, [
VElement('h1', {
style: 'color:red'
}, ['simple virtual dom']),
VElement('p', ['hello world']),
VElement('ul', [VElement('li', ['item #1']), VElement('li', ['item #2'])]),
]);
var dom = vdom.render()
$("#container").replaceWith(dom);
</script>
</html>