学习vue原理笔记 vdom(二)

虚拟DOM和diff算法

虚拟DOM是实现vue,react的重要基石,而diff算法是虚拟DOM中最重要,最核心的地方。

为什么我们需要虚拟DOM?
因为dom操作是非常消耗性能的,以前我们使用jquery手动修改dom,而vue是数据驱动视图,若一次操作中有多次的修改dom,虚拟DOM不会立即执行更新,而是会找出这基础与之前的差异,再选择性的进行更新,这种操作极大地提升了性能,其次js操作是特别快的,那他到底是怎么将dom转换成js的?我们可以看一下下面的例子。

<div id="div1" class="container">
	<p style="font-size:20px;">一段文字</p>
	<ul>
		<li>li文字内容</li>
	</ul>
</div>

在vuejs中,可以将上面翻译成如下内容

{
	tag:'div',
	props:{
		className:'div1',
		id:'div1'
	},
	children:[{
		tag:'p',
		props:{style:'font-size:20px;'},
		children:"一段文字'
	},{
		tag:"ul',
		children:[{
			tag:"li',
			children:[{
				tag:"li',
				children:'li文字内容'
			}]
		}]
	}]
}

由上面这种写法对比,我们大概可以理解为,当前元素名称,props放当前元素后面带的属性,children当直接为内容时,就直接放字符串,如果有子元素就放数组,里面每一项有重复当前操作。

snabbdom

虚拟dom是借鉴snabbdom进行开发的,我们可以通过snabbdom来学习。
首先我们要了解一下snabbdom里面的vnode,他在接下来的操作用用到的特别多,我们先定义一个vnode(虚拟node,虚拟节点)。

var vnode = h('div#container.two.classes',
	{on:{click:clickFunName}},
	[
	h('span',{style:{font-size:20px;}},'span里面的文本内容'),
	h('a',{props:{href:'./aaa'}},'a里面的文本')
	]);

由上面我们可以看到,vnode是由一个h函数顶一个,他第一个参数像是我们之前的tag加上他的id,class,第二个参数是他的一些样式,点击事件等等,第三个参数是他做的子元素,这就和我们之前讲的虚拟dom的vnode结构很像,毕竟虚拟DOM是借鉴他进行开发的。
这个我们就可以理解为,由js模拟的DOM元素,所以他叫vdom,将dom转化为vnode以后,在对新旧的vnode进行对比,得出最小的更新范围,注意如果父节点改变,则不再继续往下走中,直接取新的这一块进行覆盖(极大地提升了性能,否则将陷陷入更大的计算中)。

diff算法

diff即对比,他可以是js对象进行对比,可以是熟进行对比,例如vdom,diff。
这里假设我们需要对比两颗都有1000个节点的树,按照普通对比,首先遍历第一棵树,他就有1000种结果,第二颗数也是1000种结果,此时他们进行对比排序,如第一棵树第一个节点对比第一棵树最后一个节点,按照算法,他就一共存在1000的三次方,即1000000000种结果,此时计算量就太大了,所以后面大神们就做出了如下规定

1、只比较同一层级,不跨级比较
2、tag不相同,就直接删掉,进行重建,不在往下计算。
3、如果tag和key都相同,则认为是同一个节点,不在进行深度比较。

patch函数

如果我们内容里面没有key,就默认是undefined===undefined,他就只判断sel

vnode1.key === vnode2.key && vnode1.sel === vnode2.sel

方法:sameVnode(oldVnode,vnode)//相同的vnode
1、const hook = vnode.data?.hook;
//执行prepatch hook,生命周期的一个钩子。
2、hook?.prepatch?.(oldVnode,vnode);
//设置vnode.elem
const elm = vnode.elm = oldVnode.elm!;
3、取出oldchildren和新的children.
4、如果oldVnode === vndoe return;
5、hook相关内容
6.1、如果新的text是undefuined,写法是isUnddf(vnode.text),如果他的text是undefined,极有可能children有值。
6.2、如果新的children有,旧的children无,可能是内容里面新增了节点,此时如果旧的children有值,要先把他设置为空,
if(isDef(oldVnode.text)){
api.setTextContent(旧的children,’’)
}
addVnode(~)
6.3、如果旧的children有值,新的children没有,则要移除。
invokeDestroyHook(ch);//hook操作,destroy生命周期,在执行移除dom元素。
removeVnodes(~)
6.4、新的有children,旧的是text,直接移除
6.5、如果他不是undefined,极有可能children是undefined,此时就可以直接对值进行对比;如果新旧vnode的text不相等,则直接移除旧的children,设置新的text。
updateChildren比较顺序,前一个为old,后一个为new
1、开始和开始
2、结束和技术
3、开始和结束
4、结束和开始
5、key和sel相等,表示是同一个select。
总结
patchVnode
addVnodea removeVnodes
updateChildren

vdom和diff总结
vdom核心概念很重要,h函数,vnode,patch,diff,key等。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值