Vue笨蛋学原理:真实DOM转换为虚拟DOM
程序员文章站
2024-02-02 11:17:10
...
为什么要使用虚拟DOM?
- 在js中操作DOM是一件很消耗性能的事
- 可能会造成回流和重绘
- 数据改变的时候虚拟DOM只对页面进行一次操作
- 使用虚拟DOM是为了提高性能
什么是虚拟DOM?
- 可以把虚拟DOM理解为一个用字符串表达的HTML标签
- 当然了,这个字符串是存放在对象数据类型里的
<div/> => {tag:'div'}
<div>我是内容</div> => {tag:'div',value:'我是内容'}
<div title="1" class="c"> => {tag:'div',data:{title:'1',class:'c'}}
<div> => {tag:'div',children:[{tag:'div'}]}
<div><div>
</div>
看一下Vue里的虚拟DOM
虚拟DOM是树数据结构
<div id="root">
<div>
<p>{{name}}-{{message}}</p>
</div>
<p>{{name}}</p>
<p>{{message}}</p>
</div>
真实DOM怎么来的
模板一直存在在内存里,因为这个模板是渲染的根本
只要模板里对应的插值语法替换为数据就可以渲染到页面上了
他俩结合就是真实的DOM
虚拟DOM和真实DOM的转换
- 其实和深拷贝差不多
- 深度遍历真实DOM,遇到节点就转换为虚拟DOM
- 遍历标签,复制而已
把这一组标签转换为虚拟DOM
<div id="root">
<div>
<div>hello1</div>
<div>hello2</div>
<div>hello3</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
</div>
创建一个类
class Vnode{
constructor((tag,data,value,type)) {
this.tag = tag.toLowerCase(); // 标签名
this.data = data; // 值
this.value = value; // 文本
this.type = type; // 元素类型
this.children = [] // 子节点
}
// 如果有追加节点,就用这个方法
appendChild(vnode) {
this.children.push(vnode)
}
}
- 下划线开头代表私有的,可读可写
- 美元符号开头代表只读
- 使用递归来遍历DOM元素,生成虚拟DOM
- Vue中的源码使用的栈结构,使用栈存储父元素来实现递归生成
function getVNode(node) { // 参数为真正的DOM
let nodeType = node.nodeType;
let _vnode = null;
// 对节点进行判断
if(nodeType === 1) { // 元素节点
let nodeName = noew.nodeName
let attrs = node.attributes // 属性,返回属性组成的为数组,我们就是把这个伪数组转换为对象
let _arrtObj = {}
// 循环 attrs
for(let i = 0; i < attrs.length; i++) {
// attrs[i]是一个属性节点,我们要的是nodeName这个属性
_arrtObj[attrs[i].nodeNarme] = attrs[i].nodeValue
}
_vnode = new Vnode(nodeName,_attrObj,undefined,nodeType)
let childNodes = npde.childNodes;
for(let i = 0; i < childNodes.length; i++) {
_vnode.appendChild(getVNode(childNodes[i])) // 递归
}
} else if (nodeType === 3) {
_Vnode = new Vnode(undefined,undefined,node.nodeValue,nodeType)
}
return _vnode
}
下一篇: 基于Element的进度条Loading