module的作用
通过pacth过程中的各种钩子,和vnode.data提供的自定义数据(class/style/dataset等等)来拦截并做出相应处理。在diff过程中DOM的class/style/attributes等等都是交给模块处理,diff本身只关心的树结构,节点是否可以复用,如果不能复用就会通过createElm/setTextContent来创建新的元素
diff过程中的细节
vnode.children和vnode.text
vnode.children和vnode.text对立处理的,vnode.text优先级高于vnode.children(正常情况下vnode这两个属性不应该同时有值),如果有children则递归对比(-> updateChildren),如果有text则直接对比text是否相等并修改(不用递归)
patch、patchVnode、updateChildren的区别
patch
: 是不太确定新老vnode是否相等是给开发者调用的用来更新界面的;patchVnode
是内部方法,该方法是用来对比两个相同(sameVnode)的新老vnode的的孩子节点差异的,该方法主要处理vnode.text和vnode.children的差异处理。 init.ts
如果存在 vnode.text,则直接在当前方法中处理掉,显然没必要进入递归处理;而vnode.children则需要递归对比,新老孩子节点的复用情况。
updateChildren
第二点说了,其目的是对比孩子节点(数组,只对比一层),哪些老节点可以被复用(原地保留或者移动),哪些老节点需要删除,哪些新节点需要添加
dom节点先创创建再衔接: 移动的DOM或者新创建的DOM会调用document.insertBefore/appendChill等api来衔接到DOM树中。
生命周期
Snabbdom 提供了一系列丰富的生命周期函数,这些生命周期函数适用于拓展 Snabbdom 模块或者在虚拟节点生命周期中执行任意代码。
名称 | 触发节点 | 回调参数 |
---|---|---|
pre | patch 开始执行 | none |
init | vnode 被添加 | vnode |
create | 一个基于 vnode 的 DOM 元素被创建 | emptyVnode, vnode |
insert | 元素 被插入到 DOM | vnode |
prepatch | 元素 即将 patch | oldVnode, vnode |
update | 元素 已更新 | oldVnode, vnode |
postpatch | 元素 已被 patch | oldVnode, vnode |
destroy | 元素 被直接或间接得移除 | vnode |
remove | 元素 已从 DOM 中移除 | vnode, removeCallback |
post | 已完成 patch 过程 | none |
适用于模块(module.xxx):pre
, create
,update
, destroy
, remove
, post
适用于单个元素(vnode.data.hook.xxx):init
, create
, insert
, prepatch
, update
,postpatch
, destroy
, remove
虽然很多钩子的触发时机是一致,但是为什么还要区分这两类钩子呢?因为有些逻辑是共同的,这些逻辑收敛到模块中,而有些逻辑对于不同的vnode有差异,因此交给具体的vnode自己处理。