Snabbdom 源码解析 - init 方法

948 阅读2分钟

「这是我参与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函数中定义的第二个常量)

image.png

  1. 首先 cbs 初始化成咯一个对象

  2. 细细观察我们会发现,cbs中存储的属性名称和hooks数组中的回调函数钩子名称是一致的 image.png

  3. 这个属性名称我们都初始化成一个空数组,因为之后可能有多个钩子函数

钩子函数的初始化

我们找到如图所示的位置中: image.png

  • 外层循环:初始化cbs中属性的值
  • 内层循环:取出每一个模块中的钩子函数,如果这个钩子存在为cbs中对应的属性添加钩子函数 初始化完毕之后的cbs内容大概如下
cbs => { create: [fn1, fn2], update: [fn1, fn2]}

接着就是一堆的工具方法了

最后

我们可以看见代码中返回了patch函数,init函数整体就是一个高阶函数,一个函数返回一个函数;

这样做的好处:如果没有init方法,那么patch函数需要接收四个参数

  • modules
  • domApi
  • oldVnode
  • vnode 因为后续 patch函数 要被经常的调用,我们先使用 init函数把前两个参数缓存,以后在调用 patch函数的时候,就需要传入剩余的两个参数就行了。以后我们在查看vue源码的时候就会有很多这样的东西