Vue原始碼學習(二)——生命週期
阿新 • • 發佈:2018-11-06
官網對生命週期給出了一個比較完成的流程圖,如下所示:
從圖中我們可以看到我們的Vue建立的過程要經過以下的鉤子函式:
beforeCreate => created => beforeMount => mounted
=> beforeUpdate => updated
=> beforeDestroy => destroyed
那麼我們就從原始碼的角度來看一看吧,當我們new Vue的時候,會執行_init函式
function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) }
init函式如下
export function initMixin (Vue: Class<Component>) { Vue.prototype._init = function (options?: Object) { .... 以下就是進行了生命週期 vm._self = vm // 首先進行初始化生命週期的引數 initLifecycle(vm) // 在初始化事件 initEvents(vm) // 初始化render initRender(vm) // 開始呼叫beforeCreate鉤子函式,和圖中的流程圖一樣 callHook(vm, 'beforeCreate') // 之後開始初始化變數等一些資料 initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props // 開始呼叫created鉤子函式 callHook(vm, 'created') /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { vm._name = formatComponentName(vm, false) mark(endTag) measure(`vue ${vm._name} init`, startTag, endTag) } if (vm.$options.el) { vm.$mount(vm.$options.el) } } }
以上init函式我們已經看到了beforeCreate和created,那麼callHook是怎麼呼叫的鉤子函式呢?
export function callHook (vm: Component, hook: string) { // #7573 disable dep collection when invoking lifecycle hooks pushTarget() // 從$options裡拿到鉤子函式 const handlers = vm.$options[hook] if (handlers) { for (let i = 0, j = handlers.length; i < j; i++) { try { // 然後再呼叫 handlers[i].call(vm) } catch (e) { handleError(e, vm, `${hook} hook`) } } } if (vm._hasHookEvent) { vm.$emit('hook:' + hook) } popTarget() }
這邊就會有幾個問題:
從vm.$options[hook]中取鉤子函式,那個這個鉤子函式是哪來來的? 為了拿到的鉤子函式是個陣列?我們平時使用不都是隻是寫個函式嗎?
我們可以看到在$options是在下面_init中進行合併的
Vue.prototype._init = function(){
...
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
...
}
export const LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
'activated',
'deactivated',
'errorCaptured'
]
我們可以看到鉤子函式一開始就已經在vue內部已經定義好了,並且還有幾個鉤子函式不是實話化例項的使用執行的。而是對keep-alive元件配合使用的activated,deactivated。以及錯誤丟擲鉤子函式errorCaptured
然後再根據這些內部定義的鉤子函式和傳入的引數進行合併
那麼為什麼鉤子函式是陣列呢?這個其實很簡單是因為vue內部也需要執行一些函式,顧把函式也放到鉤子函式裡。所以需要陣列遍歷。
所以這些所謂的鉤子函式就是一個回撥函式。
其餘幾個鉤子函式也是在需要呼叫的時候使用callHook(vm, 'xxx')來執行
如果對您有幫助請點個贊,謝謝!