返回
一叶知秋,Vue 源码阅读(五):组件虚拟 DOM 渲染为真实 DOM 全解析
前端
2024-01-28 09:52:15
从组件虚拟 DOM 到真实 DOM
我们在上一篇文章中介绍了如何将普通虚拟 DOM 转为真实的 DOM,本文将继续介绍如何将组件类型的虚拟 DOM 转为真实的 DOM。
创建组件实例
如果 vnode 是组件类型的,则在生成 DOM 时,会调用 createComponent 方法。我们可以看到,该方法首先判断 vnode.data 上是否有 hook 和 init 方法,如果有,则会调用这些方法。
function createComponent (vnode, parentElm, childElm, refElm) {
const vnodeComponentOptions = vnode.data.componentOptions
let hooks = vnode.data.hook
// 对组件 vnode 初始化
if (isDef(hooks)) {
// 调用 vnode 钩子函数
for (let i = 0; i < hooks.length; i++) {
invokeCreateHooks(hooks[i], parentElm, vnode, childElm)
}
}
const name = vnode.data.ref
if (isDef(name)) {
// 创建组件引用
createRef(parentElm, refElm, vnode)
}
// 判断是否有 init 钩子函数
if (isDef(vnodeComponentOptions)) {
setupComponent(vnode, parentElm, childElm, refElm)
}
}
初始化组件实例
在创建组件实例后,会调用 setupComponent 方法来初始化组件实例。该方法首先会调用 vnodeComponentOptions.beforeCreate 方法,然后创建组件的实例,并调用 vnodeComponentOptions.created 方法。
function setupComponent (vnode, parentElm, childElm, refElm) {
let componentOptions = vnode.data.componentOptions
let hook = vnode.data.hook
// 调用 beforeCreate 生命周期钩子函数
if (isDef(componentOptions.beforeCreate)) {
componentOptions.beforeCreate(
vnode,
parentElm,
childElm
)
}
// 创建组件实例
const child = new vnodeComponentOptions.Ctor(
// 传入组件 vnode 的数据部分
options = resolveAsyncComponentOptions(
componentOptions,
resolveVNodeComponentOptions
)
)
// 调用 created 生命周期钩子函数
if (isDef(hook)) {
if (isDef(hook.create)) {
hook.create(child, parentElm, vnode, childElm)
}
} else if (isDef(componentOptions.created)) {
componentOptions.created.call(child)
}
}
挂载组件实例
在初始化组件实例后,会调用 mountComponent 方法来挂载组件实例。该方法首先会调用 vnodeComponentOptions.beforeMount 方法,然后调用 vnodeComponentOptions.mounted 方法。
function mountComponent (vnode, parentElm, childElm, refElm) {
const options = vnode.componentOptions
if (isDef(options.beforeMount)) {
options.beforeMount(vnode, parentElm, childElm, refElm)
}
// 调用 mount 生命周期钩子函数
if (isDef(options.mounted)) {
options.mounted(vnode, parentElm, childElm, refElm)
}
}
更新组件实例
在组件实例挂载后,如果组件的 props 或 state 发生变化,则会调用 updateComponent 方法来更新组件实例。该方法首先会调用 vnodeComponentOptions.beforeUpdate 方法,然后调用 vnodeComponentOptions.updated 方法。
function updateComponent (prevVnode, vnode) {
const componentOptions = vnode.data.componentOptions
if (isDef(componentOptions)) {
const prevVnodeComponentOptions = prevVnode.data.componentOptions
if (isDef(componentOptions.beforeUpdate)) {
// 调用 beforeUpdate 生命周期钩子函数
componentOptions.beforeUpdate(
prevVnode,
vnode,
prevVnode.context
)
}
// 调用 updated 生命周期钩子函数
if (isDef(componentOptions.updated)) {
componentOptions.updated(prevVnode, vnode, prevVnode.context)
}
}
}
总结
本文介绍了如何将组件类型的虚拟 DOM 转为真实的 DOM。我们首先介绍了如何创建组件实例,然后介绍了如何初始化、挂载和更新组件实例。希望本文能够帮助大家更好地理解 Vue 源码。