虚拟dom原理:用js对象来描述页面
作为计算机工程师,框架是实际开发中都会用到的。理解框架原理,对更好地使用它和定位问题是很有帮助的事情。本文实现了一个简单的vdom渲染过程,来帮助理解vdom原理。
vdom对象
vdom也叫虚拟dom,是用来描述页面的js对象。
在原生开发中,我们用HTML语言来描述web页面,它是由元素构成
的。元素可拥有属性和文本内容
。例如,下面的html代码:
<ul>
<li class="item" style="color:red;" onclick="alert(0)">a</li>
<li>b</li>
</ul>
它是一个ul元素
,有两个li子元素
。其中,li元素它有三个属性
:class 、样式style和事件click,同时还有文本
内容a、b。
这些元素信息,我们用一种数据结构来表示,如下:
{
tag: 'ul',
children: [{
tag: 'li',
props: {
class:['item'],
style: {
color:"red"
},
on:{
click: function() {
alert(0);
}
}
},
children: [{
text:'a'
}]
},
{
tag: 'li',
children: [{
text:'b'
}]
}]
}
vue.js和react框架就是用这样的vdom对象来描述页面的。根据vdom描述的元素信息,创建真实dom的过程
,就是vdom的渲染。
vdom渲染
在浏览器内部,HTML页面是一个DOM树的结构。我们可以用Document
api 创建新的元素,并挂载到DOM树。
首先,根据不同的节点类型,创建元素节点或文本节点,并设置元素节点的属性。
function render(vdom) {
if (vdom?.tag) {
// 创建元素节点
const dom = document.createElement(vdom.tag);
// 设置属性
for(let prop in vdom.props){
setAttribute(dom, prop, vdom.props[prop]);
}
return dom;
}else if(vdom?.text){
// 创建文本节点
return document.createTextNode(vdom.text);
}
};
function setAttribute(dom, prop, value) {
switch(prop){
case 'class':
if(value instanceof Array){
dom.setAttribute('class', [].concat(value).join(' '));
}
break;
case 'style':
if(typeof value == 'object'){
Object.assign(dom.style, value);
}
break;
case 'on':
if(typeof value == 'object'){
for(let event in value){
dom.addEventListener(event.toLowerCase(), value[event]);
}
}
break;
default:
dom.setAttribute(prop, value);
}
}
然后,处理节点的层级关系:如果元素节点有子节点则递归处理,并把创建好的节点挂载到父节点,构成完整的DOM树。
function render(vdom, parent){
if (vdom?.tag) {
const dom = document.createElement(vdom.tag);
for (const prop in vdom.props) {
setAttribute(dom, prop, vdom.props[prop]);
}
for (const child of vdom.children) {
render(child,dom);
}
return mount(parent,dom);
}else if(vdom?.text){
return mount(parent,document.createTextNode(vdom));
}
};
function mount(parent, elm){
return parent ? parent.appendChild(elm) : elm;
}
到这里,我们就完成了一个vdom渲染的过程。
测试代码
<body>
<div id="root"></div>
</body>
<script>
document.addEventListener("DOMContentLoaded", (event) => {
render(ulVdom, document.getElementById("root"));
}
</script>
总结
vdom是一个用来描述页面的js对象。根据vdom描述的元素信息来创建真实dom的过程,就是vdom的渲染。首先,根据不同的节点类型,创建元素节点或文本节点,并设置元素节点的属性。然后,处理节点的层级关系:如果元素节点有子节点则递归处理,并把创建好的节点挂载到父节点,构成完整的DOM树。
参考资料
菜鸟教程-HTML
mdn-element