Vue笨蛋学原理:真实DOM转换为虚拟DOM

为什么要使用虚拟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
}

猜你喜欢

转载自blog.csdn.net/m0_47883103/article/details/108640156