vue源码解析pdf_Vue源码全面解析八 callHook函数(触发生命周期函数)

c63ab872d19a148538c784f179c60f2c.png

首先我们打开‘src/core/instance/lifecycle.js'文件,代码如下:

export function callHook (vm: Component, hook: string) {  pushTarget()  const handlers = vm.$options[hook]  const info = `${hook} hook`  if (handlers) {    for (let i = 0, j = handlers.length; i < j; i++) {      invokeWithErrorHandling(handlers[i], vm, null, vm, info)    }  }  if (vm._hasHookEvent) {    vm.$emit('hook:' + hook)  }  popTarget()}

可以看到这个函数比较简单,主要有3点:

1、禁止Dep的依赖收集

2、调用 "invokeWithErrorHandling" 触发对应的生命周期函数

3、触发对应是钩子函数,如果存在的话

pushTarget()// 函数代码如下export function pushTarget (target: ?Watcher) {  targetStack.push(target)  Dep.target = target}

可以看调用该函数的时候没有传任何参数,那就是 “target” 参数的 “undefined”,就没有收集对象了。

const handlers = vm.$options[hook]const info = `${hook} hook`

定义了 “handlers” 和 “info” 两个变量,分别存储生命周期函数和事件描述。

 if (handlers) {    for (let i = 0, j = handlers.length; i < j; i++) {      invokeWithErrorHandling(handlers[i], vm, null, vm, info)    }  }

可以看到 “handlers” 如果存在的话,那肯定是一个数组的形式,这里会遍历数组来进行调用。

vue官网说的是每个生命周期钩子都是函数类型,但是我们从这里看出来其实也可以是函数数组,例如:

beforeCreate:[

() => {conosle.log("beforeCreate1")},

() => {conosle.log("beforeCreate2")},

]

你会看到数组里面的两个函数都被执行了。

  if (vm._hasHookEvent) {    vm.$emit('hook:' + hook)  }

如果存在"hook" 钩子函数,则调用相关的事件

钩子函数的名称必须已 "hook:"开头,后面接对应的生命周期名称,例如:

this.$on("hook:mounted", () => {})

钩子函数必须注册在对应的生命周期函数内,或者之后的生命周期内定义才有效。

 popTarget()// 代码如下export function popTarget () {  targetStack.pop()  Dep.target = targetStack[targetStack.length - 1]}

最后是恢复Dep的依赖收集。把之前的 “target” 等于undefined移除掉。