Vue3 组件挂载流程(源码解读)
1. 入口:createApp 创建应用实例
挂载的起点是 createApp 函数,它创建一个应用实例(App),并关联根组件。
// packages/runtime-dom/src/index.ts
export function createApp(rootComponent, rootProps = null) {// 创建应用实例(包含全局配置、组件、指令等)const app = {_component: rootComponent, // 根组件_props: rootProps,_container: null,// 挂载方法mount(container) {this._container = container;// 核心:创建根组件的虚拟 DOM 并渲染render(h(this._component, this._props), container);}};return app;
}createApp接收根组件和 props,返回一个含mount方法的应用实例。mount方法是挂载的入口,它调用render函数将根组件渲染到容器(DOM 元素)。
2. 核心渲染:render 函数
render 函数负责将虚拟 DOM(VNode)转换为真实 DOM 并插入容器。
// packages/runtime-core/src/renderer.ts
function render(vnode, container) {if (vnode == null) {// 卸载逻辑(略)} else {// 核心:执行补丁算法,对比新旧 VNode 并更新 DOMpatch(container._vnode || null, vnode, container);}// 缓存当前 VNode 用于下次更新container._vnode = vnode;
}render接收虚拟 DOM(vnode)和容器(container)。- 首次渲染时,
container._vnode为null,直接执行patch初始化 DOM。
3. 补丁算法:patch 处理组件挂载
patch 是虚拟 DOM 的核心算法,根据 VNode 类型执行不同操作(元素 / 组件 / 文本等)。对于组件,会触发初始化流程。
// packages/runtime-core/src/renderer.ts
function patch(n1, n2, container) {if (n1 === n2) return;if (n2.type === Fragment) {// 处理 Fragment(略)} else if (typeof n2.type === 'object') {// 组件类型 VNode:执行组件挂载processComponent(n1, n2, container);} else if (typeof n2.type === 'string') {// 普通元素(略)}// 其他类型(文本、注释等,略)
}- 当 VNode 的
type是对象(组件选项)时,调用processComponent处理组件。
4. 组件初始化:processComponent
processComponent 区分首次挂载和更新,首次挂载时会创建组件实例并初始化。
// packages/runtime-core/src/renderer.ts
function processComponent(n1, n2, container) {if (n1 == null) {// 首次挂载:创建组件实例并挂载mountComponent(n2, container);} else {// 更新组件(略)}
}5. 组件实例化与挂载:mountComponent
mountComponent 是组件挂载的核心,负责创建组件实例、初始化生命周期、执行渲染等。
// packages/runtime-core/src/renderer.ts
function mountComponent(vnode, container) {// 1. 创建组件实例const instance = createComponentInstance(vnode);// 2. 初始化组件(处理 props、slots、设置上下文等)setupComponent(instance);// 3. 设置组件渲染Effect(响应式触发更新)setupRenderEffect(instance, container);
}5.1 创建组件实例:createComponentInstance
// packages/runtime-core/src/component.ts
function createComponentInstance(vnode) {const instance = {vnode, // 组件对应的 VNodetype: vnode.type, // 组件选项(如 { setup, render })props: {}, // 接收的 propsslots: {}, // 插槽ctx: {}, // 组件上下文isMounted: false, // 是否已挂载// 其他生命周期状态...};return instance;
}- 实例包含组件的核心信息:VNode、props、插槽、上下文等。
5.2 初始化组件:setupComponent
处理 props、slots,并执行 setup 函数(若有)。
// packages/runtime-core/src/component.ts
function setupComponent(instance) {// 1. 解析 props 和 slotsconst { props, slots } = instance.vnode;instance.props = resolveProps(instance.type.props, props); // 解析 propsinstance.slots = resolveSlots(slots); // 解析插槽// 2. 执行 setup 函数const setupResult = instance.type.setup?.(instance.props, {slots: instance.slots,emit: (event, ...args) => { /* 处理事件发射 */ }});// 3. 处理 setup 返回值(函数或对象)if (typeof setupResult === 'function') {instance.render = setupResult; // setup 返回渲染函数} else if (isObject(setupResult)) {instance.setupState = setupResult; // 暴露给模板的响应式数据}// 4. 若组件无 render 函数,自动编译模板生成(需编译器支持)if (!instance.render) {instance.render = compileTemplate(instance.type.template);}
}setup函数的返回值会被处理为组件的渲染函数或响应式状态。- 若组件未定义
render,则通过编译器将template转换为render函数(运行时 + 编译器版本支持)。
5.3 设置渲染 Effect:setupRenderEffect
创建响应式 Effect,关联组件渲染逻辑,实现数据变化自动更新。
// packages/runtime-core/src/renderer.ts
function setupRenderEffect(instance, container) {// 创建 Effect:依赖收集+触发更新instance.effect = effect(() => {if (!instance.isMounted) {// 首次渲染:执行 render 生成子 VNodeconst subTree = instance.render.call(instance.ctx);instance.subTree = subTree;// 递归 patch 子 VNode(渲染组件内容到 DOM)patch(null, subTree, container);instance.isMounted = true; // 标记为已挂载} else {// 更新逻辑(略)}},{ scheduler: queueJob } // 调度器:控制更新时机);
}effect是 Vue3 响应式系统的核心,首次执行时会:- 调用组件的
render函数生成子虚拟 DOM(subTree)。 - 递归执行
patch处理subTree,将其转换为真实 DOM 并插入容器。 - 标记组件为已挂载(
isMounted = true)。
- 调用组件的
- 当组件依赖的数据变化时,
effect会重新执行,触发更新逻辑。
6. 最终:真实 DOM 插入容器
patch 递归处理子 VNode 时,会将组件的模板内容(如 <div>{{ msg }}</div>)转换为真实 DOM 节点,并插入到挂载容器中,完成整个组件的挂载。
总结:挂载核心流程
createApp创建应用实例,关联根组件。- 调用
app.mount(container)触发渲染。 render函数调用patch处理根组件 VNode。patch识别组件类型,调用processComponent。mountComponent完成:- 创建组件实例(
createComponentInstance)。 - 初始化 props、slots、执行
setup(setupComponent)。 - 创建渲染 Effect,执行
render生成子 VNode 并递归渲染为真实 DOM(setupRenderEffect)。
- 创建组件实例(
整个过程通过虚拟 DOM 桥接组件逻辑与 DOM 操作,结合响应式系统实现数据驱动视图。

