Vue.js中的核心之一就是虚拟DOM,而要研究虚拟DOM最好的就是看snabbdom,这个玩意就是利用虚拟DOM来进行驱动的,相比Vue来说,snabbdom对于研究虚拟DOM更好,因为它里面没有其他干扰的东西,因此研究起来更方便。

为什么需要虚拟DOM

我们先来看一个有增加,删除功能的列表:

一般情况下,我们的实现方法如下:

就是直接利用js操作我们的DOM,在后面添加一个或者将自己删除。这样做似乎没有什么问题,但是如果我们要做列表排序可能就比较麻烦了,于是我们可能想到一个更好的办法,就是将列表的内容用数组保存起来,排序完成后,直接重新渲染列表就好了:

主要代码如下:

这种方式虽然可以解决列表排序问题,但是比较暴力,就是将之前的全部删除,重新来过一遍,这样明显是效率低下的,因为假如有些元素位置根本没有变,那么就没有必要移动了。

上述的两个实现,各有优缺点,从数据层面上来说,第二个更好,因为它是先改变数据,再改变视图,这样就免去了再次收集数据的步骤,但是第二个过于粗暴,如果能像第一个那样精准就好了,因此我们设想的步骤大致如下:

background Layer 1 Event Data View 控制 diff渲染

其实上面大概就有点虚拟DOM的意思了,首先是先控制数据再渲染视图,但是视图不是直接渲染的,是采用diff渲染的,diff渲染就是通过比较渲染前后的数据,只当数据有变动才会发生真正的渲染。

snabbdom中的数据结构

上面我们说到,虚拟DOM中,只有前后的数据发生变动才会法身渲染,那么,在snabbdom中,它的数据结构是什么样的呢?

在snabbdom中,它的数据是一个树形结构的DOM节点,是利用createElement所创造出来的节点。

snabbdom中有一个h方法,通过给定一个标签的名称,例如div,span等,可以创造出对应的DOM节点,它的参数中有一个数组,用来放下一级的DOM节点,原理和开始一样,在snabbdom中,我们一般如下构造数据:

上面的代码先是创建了一个div,然后设置了点击事件,并且有一个孩子节点span,内容为aaa。

至于如何具体的通过数据不同反应到视图,将会在下一章详细讲解,这里主要讲解一下snabbdom数据中的一些配置参数。

h函数初始化

初始化方法比较多,一般形如h('div.a',{/*配置参数*/},'bb'),其中的配置参数可以不写,就是h('div#b','ccc'),如果要弄一个下面有子元素的,就是h('div#nb',{/*配置,可以不写*/},[/*又是h函数*/])

key

用来给一个元素设置内部id的,这个key在该节点发生位置移动的时候很重要,大致如下:

style

用来给元素设置样式的,其中配置里面还有一个delayed,表示动画延迟执行,这个需要配合css中设置transition才会有效果;remove表示该节点即将移除后执行的样式;destroy和remove不同,例如一个节点a通过比较后发现需要移除,那么a会执行remove里面的样式(也会执行destroy里面的样式),但是a中的孩子节点b会执行destroy样式(不会执行remove样式)。remove只是当前移除才会执行,destroy则具有遗传性。

class

返回一个对象,key是className,如果value是true,则包含这个类,如果为false,则不包含。如{active:true,disable:false}。

on

添加事件,例如:on{click:[_c,a,b,c]},其中_c是方法名,在外面写好,a,b,c是参数;当然也可以不传参数:on{click:_c}

hook

回调事件,一般有insert,remove,destroy三种,insert在该虚拟DOM插入真实DOM之后执行,可以获取真正的该DOM节点;remove表示自己删除后的回调;destroy表示自己remove或者祖先被remove执行的回调。

实例分析

现在我们来看一个可以增加,删除,排序,用snabbdom做的列表:

首先我们用h函数制造出整个DOM结构,然后加上一些样式和事件:

这里用了一个insert的hook,在元素真正插入之后,获取元素的高度,用来计算下一个元素的transfromY;这里要使用动画,需要先在css上写上transition:opacity 1s linear,transform 1s linear等。

下一章将介绍如何详细的diff渲染。

其他文章

0
我要评论

评论

返回
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

提交
还可以输入500个字