news 2026/8/4 0:09:22

组件实例的创建与初始化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
组件实例的创建与初始化

组件实例的创建与初始化 | 源码解析系列 3.3

一、引言

在Vue中,组件是核心概念。当我们使用createApp创建应用并挂载组件时,背后经历了复杂的初始化过程。理解组件实例的创建与初始化,对于深入理解Vue的运行机制至关重要。本文将深入解析Vue3中组件实例的创建过程,包括createComponentInstance、setupComponent等核心函数的实现。

二、组件实例概述

2.1 什么是组件实例

组件实例是Vue组件的运行时表示,它包含了组件的状态、属性、方法、生命周期等信息。每个组件实例都是独立的,有自己的响应式数据和作用域。

// 组件实例的结构constinstance={// 组件配置type:Component,// propsprops:{},// 非props属性attrs:{},// 插槽slots:{},// 组件上下文ctx:{},// 响应式数据data:{},setupState:{},// 计算属性computed:{},// 方法methods:{},// 生命周期钩子mounted:[],updated:[],// ...}

2.2 组件创建的整体流程

组件从创建到渲染到挂载经历了以下主要阶段:VNode创建、组件实例创建、setup函数执行、render函数生成、DOM挂载。

// 整体流程// 1. 用户编写组件constApp={template:'<div>{{ message }}</div>',data(){return{message:'Hello'}}}// 2. 编译为渲染函数constApp={render(){returnh('div',{},this.message)}}// 3. 创建组件实例constinstance=createComponentInstance(vnode)// 4. 执行setupsetupComponent(instance)// 5. 执行渲染setupRenderEffect(instance)

三、createComponentInstance

3.1 函数定义

createComponentInstance用于创建组件实例。

// packages/runtime-core/src/component.tsexportfunctioncreateComponentInstance(vnode:VNode,parent:ComponentInternalInstance|null,suspense:SuspenseBoundary|null):ComponentInternalInstance{// 创建实例对象constinstance:ComponentInternalInstance={// 唯一标识uid:uid++,// VNode引用vnode,// 组件类型type:vnode.typeasComponent,// 父实例parent,// 应用上下文appContext:nullasany,// propsprops:{},// attrsattrs:{},// 插槽slots:{},// 渲染函数render:null,// setup返回的渲染函数setupRenderEffect:null,// 响应式数据data:{},// setup返回的状态setupState:{},// 计算属性computed:{},// 方法methods:{},// 观察者watch:{},// 提供/注入provides:parent?Object.create(parent.provides):{},// 组件上下文ctx:{},// 生命周期钩子lifecycle:{},// 更新函数update:null,// 是否挂载isMounted:false,// 是否卸载isUnmounted:false,// ...}// 初始化ctxinstance.ctx=createRenderContext(instance)returninstance}

3.2 组件实例的核心属性

组件实例包含多个核心属性。

// 核心属性说明interfaceComponentInternalInstance{// 标识uid:number// 唯一标识// 组件定义type:Component// 组件选项或setup函数vnode:VNode// 对应的VNode// 父子关系parent:ComponentInternalInstance|null// 父实例appContext:AppContext// 应用上下文// 数据props:Record<string,any>// 规范化后的propsattrs:Record<string,any>// 非props属性// 插槽slots:Record<string,Slot>// 插槽对象// 渲染render:InternalRenderFunction|null// 渲染函数setupRenderEffect:Function|null// 渲染effect// 响应式数据data:Record<string,any>// data()返回的数据setupState:Record<string,any>// setup返回的状态// 计算属性和方法computed:Record<string,ComputedRefImpl>// 计算属性methods:Record<string,Function>// 方法// 依赖注入provides:Record<string,any>// 提供的数据proxy:ComponentPublicInstance|null// 组件代理// 生命周期isMounted:boolean// 是否已挂载isUnmounted:boolean// 是否已卸载}

四、createRenderContext

4.1 渲染上下文的作用

渲染上下文是组件实例对外暴露的API集合,它代理了组件的各个部分。

// 创建渲染上下文functioncreateRenderContext(instance:ComponentInternalInstance){// 初始化上下文对象constcontext={}asRecord<string,any>// 添加实例到上下文constinstanceProxy=newProxy(context,{// get拦截get(_,key){// 优先从setupState获取if(setupState[key]){returnsetupState[key]}// 然后从data获取if(data[key]){returndata[key]}// 从props获取if(props[key]){returnprops[key]}// 从计算属性获取if(computed[key]){returncomputed[key]}// 从方法获取if(methods[key]){returnmethods[key]}},// set拦截set(_,key,value){if(setupState[key]){setupState[key]=value}elseif(data[key]){data[key]=value}elseif(props[key]){// props只读,警告console.warn(...)}returntrue}})returninstanceProxy}

4.2 上下文代理的处理

组件模板中使用的this实际上指向的是这个代理对象。

// 模板中使用 this.message// 编译后this.message// 实际上是通过代理访问instance.proxy.message

五、setupComponent

5.1 setupComponent函数

setupComponent是初始化组件实例的核心函数。

// packages/runtime-core/src/component.tsexportfunctionsetupComponent(instance:ComponentInternalInstance,isSSR=false){// 获取组件的props定义const{props}=instance.type// 初始化propsinstance.props=props// 初始化slotsinstance.slots=normalizeSlots(instance.vnode.children||{},instance)// 执行setup函数setupStatefulComponent(instance,isSSR)}

5.2 setupStatefulComponent

setupStatefulComponent负责执行setup函数并处理返回值。

// setupStatefulComponent实现functionsetupStatefulComponent(instance:ComponentInternalInstance,isSSR:boolean){// 获取组件类型constComponent=instance.typeasComponentOptions// 创建渲染上下文代理instance.proxy=newProxy(instance.ctx,PublicInstanceProxyHandlers)// 判断是否为setup函数constsetup=Component.setupif(setup){// 创建setup上下文constsetupContext=createSetupContext(instance)// 执行setup,获取返回值constsetupResult=setup(instance.props,// 只读的propssetupContext// 上下文对象)// 处理setup返回值handleSetupResult(instance,setupResult,isSSR)}else{// 没有setup,直接完成初始化finishComponentSetup(instance,isSSR)}}

5.3 createSetupContext

创建setup函数的上下文对象。

// createSetupContext实现functioncreateSetupContext(instance:ComponentInternalInstance):SetupContext{return{// attrsattrs:instance.attrs,// slotsslots:instance.slots,// emitemit:(event:string,...args:any[])=>{// 调用实例的emit方法instance.emit(event,...args)},// exposeexpose:(exposed:Record<string,any>)=>{instance.exposed=exposed}}}

六、handleSetupResult

6.1 处理setup返回值

setup函数可以返回对象或渲染函数。

// handleSetupResult实现functionhandleSetupResult(instance:ComponentInternalInstance,setupResult:SetupResult,isSSR:boolean){if(isFunction(setupResult)){// setup返回渲染函数instance.render=setupResult}elseif(isObject(setupResult)){// setup返回对象,作为响应式状态instance.setupState=proxyRefs(setupResult)}// 完成组件初始化finishComponentSetup(instance,isSSR)}

6.2 proxyRefs

proxyRefs用于处理setup返回的ref。

// proxyRefs实现exportfunctionproxyRefs(objectWithRefs:any){returnisShallow(objectWithRefs)?objectWithRefs:newProxy(objectWithRefs,{get(target,key,receiver){// 自动解包refconstvalue=Reflect.get(target,key,receiver)returnisRef(value)?value.value:value},set(target,key,value,receiver){constoldValue=target[key]if(isRef(oldValue)){// ref直接设置valueoldValue.value=valuereturntrue}returnReflect.set(target,key,value,receiver)}})}

七、finishComponentSetup

7.1 完成组件初始化

// finishComponentSetup实现functionfinishComponentSetup(instance:ComponentInternalInstance,isSSR:boolean){// 获取组件类型constComponent=instance.typeasComponentOptions// 如果没有render函数if(!instance.render){// 编译模板获取renderif(Component.template){Component.render=compile(Component.template,{isCustomElement:Component.isCustomElement,delimiters:Component.delimiters}asCompilerOptions)}}// 设置render函数instance.render=instance.render||function(){returnComponent.render}// 处理兼容选项式APIif(Component.data){instance.data=Component.data()}// 处理methodsif(Component.methods){instance.methods=Component.methods}// 处理computedif(Component.computed){instance.computed=Component.computed}}

八、组件实例的挂载

8.1 setupRenderEffect

setupRenderEffect用于设置组件的渲染effect。

// setupRenderEffect实现functionsetupRenderEffect(instance:ComponentInternalInstance,initialVNode:VNode,container:HostElement,anchor:HostNode|null,parentSuspense:SuspenseBoundary|null,isMounted:boolean){// 创建响应式effectinstance.update=effect(functioncomponentEffect(){if(!instance.isMounted){// 首次挂载constsubTree=instance.render.call(instance.proxy,instance.proxy)patch(null,subTree,container,anchor,instance,parentSuspense)initialVNode.el=subTree.el instance.isMounted=true}else{// 更新constnextTree=instance.render.call(instance.proxy,instance.proxy)patch(instance.subTree,nextTree,container,anchor,instance,parentSuspense)}},{scheduler:queueJob})// 立即执行一次,完成首次挂载instance.update()}

九、总结

本文深入解析了Vue3中组件实例的创建与初始化过程。createComponentInstance用于创建组件实例对象,setupComponent负责初始化props和slots,setupStatefulComponent执行setup函数并处理返回值,finishComponentSetup完成剩余的初始化工作,最后setupRenderEffect设置响应式渲染effect。

理解组件实例的创建过程对于深入掌握Vue的运行机制非常重要。后续我们将学习setup函数的执行机制、render函数的执行与追踪、以及组件挂载流程的详细内容。


参考资料

  • Vue3 官方源码:https://github.com/vuejs/core
  • Vue3 组件系统:packages/runtime-core/src/component.ts
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/4 0:07:04

第三章 MySQL数据库的体系结构_上

第三章 MySQL数据库的体系结构_上 3.1、MySQL客户端服务器架构 客户端-服务器&#xff08;Client/Server&#xff09;结构简称 C/S 结构&#xff0c;是一种网络架构&#xff0c;通常在该网络架构下的软件分为客户端和服务器。MySQL是C/S架构的服务模式。 客户端和服务器程序通常…

作者头像 李华
网站建设 2026/8/4 0:08:13

解决 bedtools Segmentation fault (core dumped)

背景说明 粉丝的问题如下: 我使用 bedtools 将基因组坐标(bed 文件格式,如 chrX x1:x2)转换为基因组序列内容(fasta 文件格式,如 ‘ACGT…G’)。 bedtools 提取序列的命令格式为: bedtools getfasta -fi input_sequences.fa -bed genomic_coordinates.bed -fo outp…

作者头像 李华
网站建设 2026/8/4 0:09:03

HP8304@ACP#HP8304与MT3905参数对比

HP8304/HP8304F 与 MT3905 参数规格差异表表格核心参数HP8304/HP8304F&#xff08;厚朴半导体&#xff09;MT3905&#xff08;M3TEK&#xff09;拓扑结构同步降压 DC/DC&#xff0c;COT 恒定频率模式同步降压 DC/DC&#xff0c;PWM 模式输入电压范围4~32V&#xff08;最大 36V…

作者头像 李华
网站建设 2026/7/21 6:15:42

Nature 软体机器人实时原位磁化重编程

磁性软体机器人凭借形状可编程性、高柔顺性和物理适应性&#xff0c;在生物医学、工业、海洋探索、搜索救援等场景中展现出巨大潜力&#xff0c;其变形与功能实现源于外部磁场与机器人固有磁化分布的相互作用。磁驱动是软体机器人在受限环境中操作的最优策略之一&#xff0c;但…

作者头像 李华
网站建设 2026/7/21 6:15:42

挂耳耳机最建议买的品牌有哪些?盘点最建议买的开放式耳机前十

现在市面上的挂耳耳机看着热闹&#xff0c;其实水挺深。很多网红款就是套个好看的壳子&#xff0c;戴上才知道多坑人——材质又硬又糙&#xff0c;夹得耳朵生疼&#xff1b;发声单元也偷工减料&#xff0c;声音糊成一团&#xff0c;听个响都嫌难受。更别说那些几十块的劣质货了…

作者头像 李华