1. 钩子函数
通过该钩子函数,可以让使用者在vue的生命周期的不同阶段去执行对应的方法以及逻辑,根据传入的字符串hook,并在vm.$options
中获取对应的回调函数数组,并遍历执行
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()
}
复制代码
2. 生命周期中的钩子
2.1. beforeCreate和created
源码中,beforeCreate
在initState
之前调用,
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
复制代码
initState
中初始化props
、methods
、data
、computed
、watch
等属性,故这些属性中的值在beforeCreate
钩子中无法获取。created
钩子中可以访问props
、data
、methods
等属性
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
复制代码
2.2. beforeMount 和 mounted
created
之后就是挂载,vm.$mount(vm.$options.el)
,其中,在$mount
中调用了mountComponent
方法,beforeMount
是在mountComponent
方法中调用的。执行完beforeMount
钩子,会执行vm._render()
,通过_render()
方法获取vnode
,然后执行vm._update()
方法进行vnode
的更新,更新完会挂载mounted
钩子。
export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
...
callHook(vm, 'beforeMount')
let updateComponent
...
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)
...
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
return vm
}
复制代码
2.3. beforeUpdate 和 updated
上面代码中的new Watcher()
为渲染watcher。若是第一次初始化组件,因组件未挂载,vm._isMounted
为false
,并不会执行beforeUpdate
钩子。当组件需要更新时,会执行beforeUpdate
钩子。组件更新完之后会调用updated
钩子
2.4. beforeDestroy 和 destroyed
vm._update()
方法更新vnode
的时候,将$destroy
方法挂载到Vue的原型上,如下所示。
当组件开始销毁时,会调用beforeDestroy
钩子。接着会将自身从父组件中删除,销毁watcher,并将当前的vnode进行销毁。销毁之后调用destroyed
钩子
Vue.prototype.$destroy = function () {
const vm: Component = this
if (vm._isBeingDestroyed) {
return
}
callHook(vm, 'beforeDestroy')
vm._isBeingDestroyed = true
// remove self from parent
const parent = vm.$parent
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
remove(parent.$children, vm)
}
// teardown watchers
if (vm._watcher) {
vm._watcher.teardown()
}
let i = vm._watchers.length
while (i--) {
vm._watchers[i].teardown()
}
// remove reference from data ob
// frozen object may not have observer.
if (vm._data.__ob__) {
vm._data.__ob__.vmCount--
}
// call the last hook...
vm._isDestroyed = true
// invoke destroy hooks on current rendered tree
vm.__patch__(vm._vnode, null)
// fire destroyed hook
callHook(vm, 'destroyed')
// turn off all instance listeners.
vm.$off()
// remove __vue__ reference
if (vm.$el) {
vm.$el.__vue__ = null
}
// release circular reference (#6759)
if (vm.$vnode) {
vm.$vnode.parent = null
}
}
}
复制代码
3. 每个生命周期中可以做哪些事情?
created:可以获取data,props,methods等属性,可以发送资源请求
mounted:此时dom已经挂载完成,可以对dom进行操作
destroyed: 可以在这个钩子中清楚定时器以及事件绑定