思维导图
抛出问题
- 如何给所有组件都添加生命周期函数?
- 生命周期是怎样实现的?钩子方法(回调函数)?
寻找思路
添加Vue.mixin方法
- global/index.js
import { mergeOptions } from "../utils"
export function initGlobalAPI(Vue) {
Vue.options = {} //全局属性, 在每个组件初始化的时候将这些属性放到每个组件上
Vue.mixin = function (options) {
// 实例上的参数和 方法上的参数
this.options = mergeOptions(this.options, options)
return this
}
Vue.component = function () { }
Vue.filter = function () { }
Vue.directive = function () { }
}
缓存钩子函数
utils.js
//存放所有策略
const strategies = {}
let lifeCycle = [
'beforeCreate',
'created',
'beforeMount',
'mounted'
]
lifeCycle.forEach(hook => {
strategies[hook] = function (parentVal, childVal) {
if (childVal) {
if (parentVal) {
return parentVal.concat(childVal)
} else {
if (isArray(childVal)) {
return childVal
} else {
return [childVal]
}
}
} else {
return parentVal
}
}
})
// 选项的合并
export function mergeOptions(parentVal, childVal) {
// 合并两个对象,以子对象为准
let options = {}
for (let key in parentVal) {
mergeFiled(key)
}
for (let key in childVal) {
//合并父对象上不存在的属性
if (!parentVal.hasOwnProperty(key)) {
mergeFiled(key)
}
}
function mergeFiled(key) {
let strategy = strategies[key]
//有策略
if (strategy) {
options[key] = strategy(parentVal[key], childVal[key])
} else {
// 先取子对象上的值
options[key] = childVal[key] || parentVal[key]
}
}
return options
}
调用钩子函数
lifecycle.js
import Watcher from "./observe/watcher"
import { patch } from "./vnode/patch"
export function mountComponent(vm) {
// vm._render() 获取到vnode
// vm._update(vnode) 把vnode 渲染成真实节点,更新到页面上
let updateComponent = () => {
vm._update(vm._render())
}
callHook(vm, 'beforeCreate')
new Watcher(vm, updateComponent, () => {
console.log('后续增添组件更新的钩子函数')
}, true)
callHook(vm, 'mounted')
}
export function lifeCycleMixin(Vue) {
//给个对象,把对象渲染成真实DOM
Vue.prototype._update = function (vnode) {
//采用的是先序深度遍历,创建节点。
const vm = this
vm.$el = patch(vm.$el, vnode)
}
}
export function callHook(vm, hook) {
// 从$options里面拿对应的钩子函数进行调用
let handlers = vm.$options[hook]
handlers && handlers.forEach(fn => {
//声明周期中的this 永远指向实例
fn.call(vm)
})
}
小结回顾
- 用一个
哈希表收集所有的生命周期的钩子函数,在适当的时机去执行他。 Vue.mixin函数调用之后会把mixin里面的参数合并到Vue.options上面,然后再调用vm.$options = mergeOptions(vm.constructor.options, options)把全局的参数与用户传递的参数进行合并之后生成一个新的$options给当前的实例
Vue.mixin 全局api的作用
Vue.options = {} //全局属性, 在每个组件初始化的时候将这些属性放到每个组件上
this.options = mergeOptions(this.options, options)
然后再实例化的时候再调用
vm.$options = mergeOptions(vm.constructor.options, options)