什么是虚拟 dom
总所周知,操作 dom 有性能成本,而损耗性能的关键就是操作过程中造成的重绘、重排,所以如果我们能减少重绘、重排,就能提升 web 性能,进而改善用户体验,虚拟 dom 也就这么产生了。
虚拟 dom 其实就是一个用来描述 Dom 节点的 json 对象,比如 snabbdom 中的声明是这样的:
1 | interface VNode { |
其中 VNodeData 如下:
1 | interface VNodeData { |
上面的结构就是一个个虚拟 dom,东西少,很清晰,也正是因为这种结构的产生,进而衍生了服务端渲染,因为虚拟 dom 不依赖浏览器的 Dom 相关内容,所以可以在几乎任何环境下共存,搞不好以后还能出个 css 同构呢。
剩下的就是如果操作虚拟 dom,进而刷新浏览器的 ui,snabbdom 中,核心方法暂且说成两个,一个是 patch, 一个是 h。
方法解析
h
一个用来生成 Vnode 的方法,snabble 中定义了使用案例
1 | function h(sel: string): VNode; |
方法内的内容很比较简单,通过对函数参数个数的判断,来取到对应的所需参数,然后调用 Vnode 方法,返回创建的 Vnode 实例。
1 | function vnode( |
patch
功能主要是三个,比对两个 Vnode 的差异,然后赋值 Vnode.elm 和更新到 html 上,并调用注入的全局钩子
- 比较 Vnode 的差异
使用的是 updateChildren,该方法值取新的和旧的 Vnode 的 child 的 startIdx 和 endIdx,然后进行同级别的比较,之所以这么做是因为对于浏览器的场景是适用的,具体细节不啰嗦,也有很多分享,建议自己去看代码,最后我会把带有注释的代码贴上来,做下记录和分享。 - 赋值并更新 html
这块更简单了,就是调用 createElm 方法,然后赋值给 Vnode,之后调用 htmldomapi 里面封装好的各种 DOM 操作方法,进行 dom 的增删改查,updateChildren 中也有一些增删改查的操作。 - 调用全局钩子
这里的钩子是 snabbdom.bound.js 中挂载的,将 用于操作Vnode.data上属性的钩子方法 挂载到 snabbdom.js 中
1 | // snabbdom.bound.js |
1 | // snabbdom.js |
typescript类型学习
1 | function fn (modules: Array<Partial<Module>>){} |
snabbdom.js 注释版(不是很长,但是注释比较随性,所以看起来可能不是很舒服)
1 | /* global module, document, Node */ |