Vue 2閱讀理解之initRender與callHook組件詳解
initRender 組件渲染初始化
在 initEvents 事件系統(tǒng)初始化完成之后,緊接著的就是組件實例的渲染部分的初始化 initRender。
initRender 函數(shù)定義位于 src/core/instance/render.ts 文件內,基本定義如下:
export function initRender(vm: Component) {
vm._vnode = null
vm._staticTrees = null
const options = vm.$options
const parentVnode = (vm.$vnode = options._parentVnode!)
const renderContext = parentVnode && (parentVnode.context as Component)
vm.$slots = resolveSlots(options._renderChildren, renderContext)
vm.$scopedSlots = parentVnode
? normalizeScopedSlots(vm.$parent!, parentVnode.data!.scopedSlots, vm.$slots)
: emptyObject
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
const parentData = parentVnode && parentVnode.data
if (__DEV__) {
defineReactive(
vm,
'$attrs',
(parentData && parentData.attrs) || emptyObject,
() => !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm),
true
)
defineReactive(
vm,
'$listeners',
options._parentListeners || emptyObject,
() => !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm),
true
)
} else {
// 將 defineReactive 的第四個參數(shù)設為 null 重新執(zhí)行上面的步驟,即省略校驗和報錯部分
}
}
這部分其實比較好理解:
首先是 清空 組件的 VNode 對象和靜態(tài)dom節(jié)點樹;并獲取到該實例的 父組件虛擬dom樹對象 parentVnode 與 父組件實例指向 renderContext
然后是處理 當前組件的 slots 插槽對象 ,以及標準化處理組件的數(shù)據(jù)域插槽
給組件添加兩個 組件創(chuàng)建方法,但是這兩個方法有細微差別:
- _c 表示使用內部 render 函數(shù),不需要額外的標準化處理
- $createElement 則表示使用的是用戶自己編寫的 render 函數(shù),需要內部重新進行一次標準化處理
- 這兩個方法最終其實都是調用的 _createElement 方法,只是標準函數(shù)(即 _c)使用 simpleNormalizeChildren() 處理,而用戶自定義 render (即 $createElement)使用 normalizeChildren() 處理
最后對 attrs∗∗和∗∗attrs** 和 **attrs∗∗和∗∗listeners 進行響應式處理。這一步主要是為了提供給高階組件使用,當使用 attrs∗∗和∗∗attrs** 和 **attrs∗∗和∗∗listeners 進行綁定數(shù)據(jù)與事件透傳時,可以正確觸發(fā)高階組件內部的狀態(tài)更新。
整個過程其實就是解析了組件的 options 配置項與父組件的綁定參數(shù),并對插槽和數(shù)據(jù)域插槽進行不同處理,最后給組件添加 _createElement 的事件指向綁定,并響應式處理兩個組件內部沒有直接定義的參數(shù)/事件。
callHook('beforeCreate')
因為這部分篇幅較少,所以把 callHook() 方法也一并看了。
這個方法從名字上就可以看出,是用來觸發(fā)生命周期鉤子的回調函數(shù)。在之前的 mergeOptions 配置合并 中已經(jīng)知道,Vue 組件在實例化的時候會對 options 中的生命周期鉤子函數(shù)定義進行標準化處理,最后每個生命周期對應的都是一個 函數(shù)數(shù)組(如果有定義了鉤子函數(shù)的話)。
該方法的定義如下:
export function callHook(vm: Component, hook: string, args?: any[], setContext = true) {
pushTarget()
const prev = currentInstance
setContext && setCurrentInstance(vm)
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, args || null, vm, info)
}
}
if (vm._hasHookEvent) {
vm.$emit('hook:' + hook)
}
setContext && setCurrentInstance(prev)
popTarget()
}
這里可以分成一下幾步來理解:
- pushTarget() :在組件的 Dep 依賴中插入一個 undefined 元素并將當前依賴指向設置為 undefined,來禁止生命周期鉤子函數(shù)執(zhí)行時的依賴收集
- 遍歷 options 中對應的鉤子函數(shù)數(shù)組,調用 invokeWithErrorHandling 來執(zhí)行(這里其實與 initEvnets 中注冊組件事件的方法是一致的)
- 如果 _hasHookEvent 為 true,即父組件有設置子組件的生命周期監(jiān)聽函數(shù),則用 $emit 拋出對應生命周期事件
- popTarget() :刪除之前插入的 undefined 元素,并恢復 Dep 依賴對象中的依賴收集效果
- 兩個 setCurrentInstance:這部分則是為了適配 V3 的寫法而新增的部分,主要是保證在生命周期的鉤子函數(shù)中使用 getCurrentInstance() 方法獲取當前組件實例時能正確獲取到當前的組件狀態(tài),但是在鉤子函數(shù)執(zhí)行完之后會恢復到之前的狀態(tài)
以上就是Vue 2閱讀理解之initRender與callHook組件詳解的詳細內容,更多關于Vue2 組件initRender callHook的資料請關注腳本之家其它相關文章!
相關文章
淺談ElementUI el-select 數(shù)據(jù)過多解決辦法
下拉框的選項很多,上萬個選項甚至更多,這個時候如果全部把數(shù)據(jù)放到下拉框中渲染出來,瀏覽器會卡死,體驗會特別不好,本文主要介紹了ElementUI el-select 數(shù)據(jù)過多解決辦法,感興趣的可以了解一下2021-09-09
解決Vue使用百度地圖BMapGL內存泄漏問題?Out?of?Memory
這篇文章主要介紹了解決Vue使用百度地圖BMapGL內存泄漏問題?Out?of?Memory,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
element-plus結合sortablejs實現(xiàn)table行拖拽效果
使用element-plus的el-table組件創(chuàng)建出來的table,結合sortable.js實現(xiàn)table行拖動排序,文中有詳細的代碼示例供大家參考,具有一定的參考價值,感興趣的同學可以自己動手試一試2023-10-10
VUEX 數(shù)據(jù)持久化,刷新后重新獲取的例子
今天小編就為大家分享一篇VUEX 數(shù)據(jù)持久化,刷新后重新獲取的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11

