vue3.0动态组件,vue如何实现动态组件 | 您所在的位置:网站首页 › 如何实现动态组件 › vue3.0动态组件,vue如何实现动态组件 |
vue3.0动态组件,vue如何实现动态组件 本文主要介绍vue3的动态组件是如何工作的,帮助大家更好的理解和学习使用vue框架。感兴趣的朋友可以了解一下。 目录 I、组件注册1.1全局注册1.2注册全局组件的流程1.3应用mount II的流程、动态组件2.1绑定字符串类型2.2绑定对象类型三、阿宝哥有话说3.1除了组件内置组件,还有哪些内置组件?3.2注册全局组件和本地组件有什么区别?注册全局组件注册本地组件解析全局注册和本地注册组件3.3动态组件可以绑定其他属性吗?在本文中,Po Ge将介绍Vue 3中的内置组件3354component,它用于将一个“元组件”渲染成一个动态组件。如果你对动态组件一无所知也没关系。在本文中,Po Ge将通过具体的例子介绍动态组件的应用。因为动态组件的内部组件和组件注册有一定的联系,为了让大家更好的了解动态组件的内部原理,阿宝哥先介绍一下组件注册的相关知识。 一、组件注册 1.1 全局注册 在Vue 3.0中,使用app对象的component方法可以很容易地注册或检索全局组件。组件方法支持两个参数: 名称:组件名称; 组件:组件定义对象。 接下来,让我们看一个简单的例子: div id=应用程序 组分a/组分a 组件b/组件b 组件c/组件c /div 脚本 const { createApp }=Vue const app=create app({ });// app.component(component-a ,{ // 模板:“p我是组件A/p” }); app.component(component-b ,{ 模板:“p pI am组件B/p” }); app.component(component-c ,{ 模板:“p我是组件C/p” }); app.mount(#app) // /脚本 在上面的代码中,我们通过app.component方法注册了3个组件,它们都是全局注册的。也就是说,它们可以在注册后用于任何新创建的组件实例的模板中。这个例子的代码相对简单,主要包括三个步骤:创建App对象、注册全局组件、应用挂载。创建App对象的细节将在后续文章中单独介绍。接下来,我们将重点介绍另外两个步骤。首先,我们来分析一下注册全局组件的过程。 1.2 注册全局组件的过程 在上面的示例中,我们使用app对象的component方法来注册全局组件: app.component(component-a ,{ 模板:“p我是组件A/p” }); 当然,除了注册全局组件,我们也可以注册本地组件,因为组件也接受组件的选项: const app=Vue.createApp({ 组件:{ 成分a:成分a, 组件-b :组件b } }) 请注意,部分注册的组件在其子组件中不可用。接下来,我们继续介绍注册全局组件的流程。对于前面的示例,我们使用的app.component方法是在runtime-core/src/apicreateapp . ts文件中定义的: 导出函数createAppAPIHostElement( render:rootdrenderfunction, 水合物?RootHydrateFunction ):CreateAppFunctionHostElement { 返回函数createApp(rootComponent,rootProps=null) { const context=createAppContext() const installedPlugins=新集合() 设isMounted=false const app: App=(context.app={ //省略一些代码 _context:上下文, //注册或检索全局组件 组件(名称:字符串,组件?组件):任何{ if (__DEV__) { validateComponentName(name,context.config) } 如果(!Component) {//获取名称对应的组件 返回context.components[name] } if(_ _ dev _ _ context . components[name]){//重复注册提示 警告(`组件 ${name} 已在目标应用程序中注册。`) } context . components[name]=component//注册全局组件 返回应用程序 }, }) 返回应用程序 } } 当所有的组件都注册成功之后,它们会被保存到语境对象的成分属性中,具体如下图所示: 而createAppContext函数被定义在运行时-core/src/apiCreateApp.ts文件中: //packages/runtime-core/src/apicreateapp。分时(同timesharing) 导出函数createAppContext(): AppContext { 返回{ app: null as any, 配置:{ //应用的配置对象 isNativeTag:没有, 表现:假的, 全局属性:{}, 选项合并策略:{}, isCustomElement:否, 错误处理程序:未定义, 警告处理程序:未定义 }, 混合:[],//保存应用内的混入 组件:{},//保存全局组件的信息 指令:{},//保存全局指令的信息 提供:对象.创建(空) } } 分析完应用组件方法之后,是不是觉得组件注册的过程还是挺简单的。那么对于已注册的组件,何时会被使用呢?要回答这个问题,我们就需要分析另一个步骤—— 应用挂载。 1.3 应用挂载的过程 为了更加直观地了解应用挂载的过程,阿宝哥利用铬开发者工具的表演标签栏,记录了应用挂载的主要过程: 在上图中我们发现了一个与组件相关的函数解决组件。很明显,该函数用于解析组件,且该函数在提出方法中会被调用。在源码中,我们找到了该函数的定义: //packages/runtime-core/src/helpers/resolve资产。分时(同timesharing) 常量组件=组件 导出函数解决组件(名称:string):混凝土构件 string { return resolveAsset(COMPONENTS,name) name } 由以上代码可知,在分解组件函数内部,会继续调用resolveAsset函数来执行具体的解析操作。在分析resolveAsset函数的具体实现之前,我们在分解组件函数内部加个断点,来一睹提出方法的"芳容": 在上图中,我们看到了解析组件的操作,比如_resolveComponent("组件一”)。前面我们已经知道在分解组件函数内部会继续调用resolveAsset函数,该函数的具体实现如下: //packages/runtime-core/src/helpers/resolve资产。分时(同timesharing) 函数resolveAsset( 类型:组件类型指令类型, 名称:字符串, warnMissing=true ) { const instance=currentRenderingInstance currentInstance 如果(实例){ 常量组件=实例。类型 //省略大部分处理逻辑 const res= //局部注册 //首先检查带有混入类或延伸的组件的实例[类型]. resolve(实例[类型] (组件作为组件选项)[类型],名称) //全局注册 解决(实例。应用程序上下文[类型],名称) 返回资源 } else if (__DEV__) { 警告( ` resolve $ { capital(type。slice(0,-1))} `只能在渲染()或设置()中使用,` ) } } 因为注册组件时,使用的是全局注册的方式,所以解析的过程会执行解决(实例。应用程序上下文[类型],名称)该语句,其中分解方法的定义如下: //packages/runtime-core/src/helpers/resolve资产。分时(同timesharing) 函数resolve(注册表:记录字符串,any 未定义,名称:字符串){ 返回( 登记处 (注册表[名称] 注册表[camelize(name)] 注册表[大写(camelize(name))]) ) } 分析完以上的处理流程,我们在解析全局注册的组件时,会通过分解函数从应用的上下文对象中获取已注册的组件对象。 (匿名函数(){ const _Vue=Vue 返回函数render(_ctx,_cache) { 带有(_ctx) { const { resolve component:_ resolve component,createVNode: _createVNode, Fragment: _Fragment,openBlock: _openBlock,createBlock: _createBlock}=_Vue const _ component _ component _ a=_ resolve component(组件-a’) const _ component _ component _ b=_ resolve组件(组件-b’) const _ component _ component _ c=_ resolve组件( component-c ) return (_openBlock(), _createBlock(_Fragment,null,[ _ createVNode(_ component _ component _ a), _ createVNode(_ component _ component _ b), _ createVNode(_ component _ component _ c)],64)) } } }) 在获取到组件之后,会通过_createVNode函数创建虚拟节点节点。然而,关于虚拟节点是如何被渲染成真实的数字正射影像图元素这个过程,阿宝哥就不继续往下介绍了,后续会写专门的文章来单独介绍这块的内容,接下来我们将介绍动态组件的相关内容。 二、动态组件 在Vue 3中为我们提供了一个成分内置组件,该组件可以渲染一个"元组件"为动态组件。根据存在的值,来决定哪个组件被渲染。如果存在的值是一个字符串,它既可以是超文本标记语言标签名称也可以是组件名称。对应的使用示例如下: !-动态组件由伏特计实例的" componentId "属性控制- 组件:is= componentId /组件 !-也能够渲染注册过的组件或支柱传入的组件- 组件:is= $ options。组件。子/组件 !-可以通过字符串引用组件- 组件:is=条件?foo组件: bar组件 /组件 !-可以用来渲染原生超文本标记语言元素- 组件:is=href?a : span /组件 2.1 绑定字符串类型 介绍完成分内置组件,我们来举个简单的示例: div id=应用程序 按钮 v-for=制表符中的制表符 :key=tab @ click= current tab= tab- tab。小写() {{ tab }} /按钮 组件:is=当前选项卡/组件 /div 脚本 const { createApp }=Vue const tabs=[Home , My] const app=createApp({ data() { 返回{ 选项卡, 当前标签:"标签-"标签[0]。toLowerCase() } }, }); app.component(tab-home ,{ 模板:` div style= border:1px solid;主页组件/分区` 2 }) app.component(tab-my ,{ 模板:` div style= border:1px solid;我的组件/div }) app。装载(应用数量) /脚本 在以上代码中,我们通过应用组件方法全局注册了选项卡-主页和选项卡-我的2个组件。此外,在模板中,我们使用了成分内置组件,该组件的存在属性绑定了数据对象的当前标签属性,该属性的类型是字符串。当用户点击标签按钮时,会动态更新当前标签的值,从而实现动态切换组件的功能。以上示例成功运行后的结果如下图所示: 看到这里你会不会觉得成分内置组件挺神奇的,感兴趣的小伙伴继续跟阿宝哥一起,来揭开它背后的秘密。下面我们利用Vue 3模板浏览器在线工具,看一下组件:is=当前选项卡/组件模板编译的结果: const _Vue=Vue 返回函数render(_ctx,_cache,$props,$setup,$data,$options) { 带有(_ctx) { const { resolveDynamicComponent:_ resolveDynamicComponent,openBlock: _openBlock, createBlock: _createBlock }=_Vue return (_openBlock(),_ create block(_ resolveDynamicComponent(currentTab))) } } 通过观察生成的渲染函数,我们发现了一个resolveDynamicComponent的函数,根据该函数的名称,我们可以知道它用于解析动态组件,它被定义在运行时-核心/src/助手/解析资产。分时(同timesharing)文件中,具体实现如下所示: //packages/runtime-core/src/helpers/resolve资产。分时(同timesharing) 导出函数resolveDynamicComponent(组件:未知):VNodeTypes { if (isString(component)) { return resolveAsset(COMPONENTS,component,false) component }否则{ //无效类型将失败,从而创建一个节点并引发警告 返回(组件 NULL _动态组件)为任何的 } } 在resolveDynamicComponent函数内部,若成分参数是字符串类型,则会调用前面介绍的resolveAsset方法来解析组件: //packages/runtime-core/src/helpers/resolve资产。分时(同timesharing) 函数resolveAsset( 类型:组件类型指令类型, 名称:字符串, warnMissing=true ) { const instance=currentRenderingInstance currentInstance 如果(实例){ 常量组件=实例。类型 //省略大部分处理逻辑 const res= //局部注册 //首先检查带有混入类或延伸的组件的实例[类型]. resolve(实例[类型] (组件作为组件选项)[类型],名称) //全局注册 resolve(instance . app context[类型],名称) 返回资源 } } 对于前面的示例,组件是全局注册的,因此在解析过程中将从app.context上下文对象的components属性中获取相应的组件。当currentTab发生变化时,resolveAsset函数会返回不同的组件,从而实现动态组件的功能。此外,如果resolveAsset函数无法获取相应的组件,它将返回当前组件参数的值。例如,resolveDynamicComponent(div )将返回一个 div 字符串。 //packages/runtime-core/src/helpers/resolve assets . ts export const NULL _ DYNAMIC _ COMPONENT=Symbol() 导出函数resolveDynamicComponent(组件:未知):VNodeTypes { if (isString(component)) { return resolveAsset(COMPONENTS,component,false) component }否则{ 返回(COMPONENT NULL _ DYNAMIC _ COMPONENT)为any } } 细心的朋友可能还会注意到,在resolveDynamicComponent函数内,如果Component参数不是字符串类型,就会返回语句COMPONENT NULL_DYNAMIC_COMPONENT的执行结果,其中NULL _ DYNAMIC _ COMPONENT的值是一个Symbol对象。 2.2 绑定对象类型 了解以上内容后,让我们重新实现一下之前动态页签的功能: div id=应用程序 按钮 v-for=制表符中的制表符 :key=tab @click=currentTab=tab {{ tab.name }} /按钮 组件:is= current tab . component /component /div 脚本 const { createApp }=Vue const tabs=[ { 姓名:家, 组件:{ 模板:` div style= border:1px solid;主页组件/分区` 2 } }, { 姓名:“我的”, 组件:{ 模板:` div style= border:1px solid;我的组件/div } }] const app=createApp({ data() { 返回{ 选项卡, 当前标签:标签[0] } }, }); app . mount(# app) /脚本 在上面的例子中,组件内置组件的is属性被绑定到currentTab对象的component属性,其值是一个对象。当用户点击Tab按钮时,currentTab的值会动态更新,导致currentTab.component的值发生变化,从而实现动态切换组件的功能。请注意,每次切换时,您都将重新创建动态组件。但是,在某些情况下,您会希望保留这些组件的状态,以避免重复重新渲染所导致的性能问题。 对于这个问题,我们可以使用Vue 3的另一个内置组件—— keep-alive,来包装动态组件。例如: 点火电极 组件:is= current tab /组件 /保持活力 Keep-alive内置组件主要用于保持组件状态或者避免重新渲染。当使用它来包装动态组件时,它将缓存不活动的组件实例,而不是销毁它们。关于keep-alive组件的内部工作原理,后面Po哥会专门写一篇文章来分析,有兴趣的朋友记得关注Vue 3.0 advanced系列。 三、阿宝哥有话说 3.1 除了 component 内置组件外,还有哪些内置组件? 在Vue 3中,除了本文介绍的组件和keep-alive内置组件,还提供了transition、transition-group、slot和telegram等内置组件。 3.2 注册全局组件与局部组件有什么区别? 注册全局组件 const { createApp,h }=Vue const app=create app({ }); app.component(component-a ,{ 模板:“p我是组件A/p” }); 用app.component方法注册的全局组件保存在app application对象的context对象中。而通过组件对象的组件属性注册的本地组件保存在组件实例中。 注册局部组件 const { createApp,h }=Vue const app=create app({ }); Const componentA=()=h(div ,我是组件A ); app.component(component-b ,{ 组件:{ 成分a:成分a }, 模板:` div 我是B组分,内部用A组分。 组分a/组分a /div ` 1 }) 解析全局注册和局部注册的组件 //packages/runtime-core/src/helpers/resolve assets . ts 函数resolveAsset( type:组件类型指令类型, 名称:字符串, warnMissing=true ) { const instance=currentRenderingInstance currentInstance if(实例){ 常量组件=实例.类型 //省略大部分处理逻辑 const res= //部分注册 //首先检查带有混入类或延伸的组件的实例[类型]. resolve(实例[类型] (组件作为组件选项)[类型],名称) //全局注册 解决(实例。应用程序上下文[类型],名称) 返回资源 } } 3.3 动态组件能否绑定其他属性? 成分内置组件除了支持存在绑定之外,也支持其他属性绑定和事件绑定: 组件:is=当前选项卡。 component :name= name @ click= say hi /组件 这里阿宝哥使用Vue 3模板浏览器这个在线工具,来编译上述的模板: const _Vue=Vue 返回函数render(_ctx,_cache,$props,$setup,$data,$options) { 带有(_ctx) { const { resolveDynamicComponent:_ resolveDynamicComponent, openBlock: _openBlock,createBlock: _createBlock }=_Vue return (_openBlock(),_ create block(_ resolveDynamicComponent(当前选项卡。组件),{ 姓名:姓名, onClick: sayHi },null,8 /* PROPS */,[name , onClick])) } } 观察以上的渲染函数可知,除了存在绑定会被转换为_resolveDynamicComponent函数调用之外,其他的属性绑定都会被正常解析为小道具对象。 以上就是vue3的动态组件是如何工作的的详细内容,更多关于vue3动态组件的资料请关注我们其它相关文章! 郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系QQ332078507,我们将第一时间修改或删除,多谢。 |
CopyRight 2018-2019 实验室设备网 版权所有 |