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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: