「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」
init
在我们之前使用 Snabbdom 简单Demo的时候都知道,我们需要调用 init 方法,返回patch函数,所以我们在看 patch 函数之前,我们要先看看 init 函数做了那些工作?
init.ts 整体解析
- 文件名: init.js
- 路径地址: src/package/init.ts
hooks函数
首先我们先移动到:hooks数组这里
const hooks: Array<keyof Module> = ['create', 'update', 'remove', 'destroy', 'pre', 'post']
这个hooks数组中存储的是钩子函数的名称,最后定义并导出了 init 函数
init函数
- 入参:
- modules(模块数组,用来处理元素的行内样式、事件)
- domApi(把VNode对象转换成其他平台下对应的元素,当我们不传入该参数时,这里会把api默认成操作浏览器平台dom元素的api)
接下来我们进入代码中:
const api: DOMAPI = domApi !== undefined ? domApi : htmlDomApi
这里就是实现 domApi 不传入时,这里会把api默认成操作浏览器平台dom元素的api 的操作
htmlDomApi
有了上面的判断,我们先查询我们为定义类型的时候 htmlDomApi 的代码吧!
路径: src/package/htmldomapi.ts
这里给这个对象初始化了一些方法,这些方法都是用来操作DOM元素的
export const htmlDomApi: DOMAPI = {
createElement,
createElementNS,
createTextNode,
createComment,
insertBefore,
removeChild,
appendChild,
parentNode,
nextSibling,
tagName,
setTextContent,
getTextContent,
isElement,
isText,
isComment,
}
cbs(init函数中定义的第二个常量)
-
首先 cbs 初始化成咯一个对象
-
细细观察我们会发现,cbs中存储的属性名称和hooks数组中的回调函数钩子名称是一致的
-
这个属性名称我们都初始化成一个空数组,因为之后可能有多个钩子函数
钩子函数的初始化
我们找到如图所示的位置中:
- 外层循环:初始化cbs中属性的值
- 内层循环:取出每一个模块中的钩子函数,如果这个钩子存在为cbs中对应的属性添加钩子函数 初始化完毕之后的cbs内容大概如下
cbs => { create: [fn1, fn2], update: [fn1, fn2]}
接着就是一堆的工具方法了
最后
我们可以看见代码中返回了patch函数,init函数整体就是一个高阶函数,一个函数返回一个函数;
这样做的好处:如果没有init方法,那么patch函数需要接收四个参数
- modules
- domApi
- oldVnode
- vnode 因为后续 patch函数 要被经常的调用,我们先使用 init函数把前两个参数缓存,以后在调用 patch函数的时候,就需要传入剩余的两个参数就行了。以后我们在查看vue源码的时候就会有很多这样的东西