vue3 v-slot,v-slot插槽

  vue3 v-slot,v-slot插槽

  本文主要介绍Vue3 Slot槽的实现原理的详细说明。有需要的朋友可以借鉴一下,希望能有所帮助。祝大家进步很大,早日升职加薪。

  

目录

   Vue官方对槽的定义到底什么是槽?如何用slot复习组件渲染原理?slot的初始化原理来分析slot中的内容?范围槽原则命名槽原则默认内容槽原则

  

Vue官方对插槽的定义

  Vue实现了一套用于内容分发的API。这个API的设计灵感来源于Web组件的规范草案,slot元素作为承载分布式内容的出口。

  

Slot到底是什么

  那么槽到底是什么?Slot实际上是一个接受父组件传递的slot内容,然后生成VNode并返回的函数。

  通常,我们使用slot/slot标签来接受父组件传输的内容。然后标签最终编译好之后,就是一个创建VNode的函数,我们可以称之为创建slot VNode的函数。

  //slot/slot标签由vue3编译。

  导出函数render(_ctx,_cache,$props,$setup,$data,$options) {

  return _renderSlot(_ctx。$slots,默认)

  }

  我们可以清楚的看到slot/slot标签被Vue3编译后变成了一个名为_renderSlot的函数。

  

如何使用插槽

  要使用插槽,必须有父子组件。

  假设父组件如下:

  待办事项按钮

  添加待办事项

  /todo-button

  我们在父组件中使用了todo-button的子组件,并传递了Add todo的槽内容。

  todo-按钮子组件模板内容

  button class=btn-primary

  插槽/插槽

  /按钮

  当组件被渲染时,slot/slot将被替换为“Add todo”。

  

回顾组件渲染的原理

  那么背后的原理是什么呢?在了解slot的底层原理之前,我们还需要回顾一下Vue3的组件运行原理。

  组件的核心是可以产生一堆VNode。对于Vue来说,一个组件的核心是它的渲染函数,组件的挂载本质是执行渲染函数,得到要渲染的VNode。至于data/props/computed,它为渲染函数产生VNode提供数据源服务,关键是组件最终产生的VNode,因为这是需要渲染的内容。

  

插槽的初始化原理

  Vue3在渲染VNode时发现VNode的类型是组件类型,就会经历组件渲染的过程。组件渲染的过程是先创建一个组件实例,然后初始化组件实例。当组件实例初始化时,将处理与Slot相关的内容。

  源代码的runtime-core\src\component.ts中

  在initSlots函数中初始化组件槽的相关内容。

  那么initSlots函数看起来像什么,它做了什么?

  runtime-core \ src \ component slots . ts

  首先要确定这个组件是不是槽组件,那么如何确定这个组件是不是槽组件呢?让我们回过头来看看上面父组件的编译代码:

  导出函数render(_ctx,_cache,$props,$setup,$data,$options) {

  const _ component _ todo _ button=_ resolve component( todo-button )

  return (_openBlock(),_ create block(_ component _ todo _ button,null,{

  默认值:_ witchtx(()=[

  _createTextVNode( Add todo )

  ],未定义,真),

  _: 1 /*稳定*/

  }))

  }

  我们可以看到Slot组件的子内容是一个对象类型,它是下面的代码:

  {

  默认值:_ witchtx(()=[

  _createTextVNode( Add todo )

  ],未定义,真),

  _: 1 /*稳定*/

  }

  然后,在创建这个组件的VNode时,我们会判断它的子节点是否是Object类型。如果是Object类型,我们会在这个组件的VNode的shapeFlag上挂一个Slot组件标志。

  如果它是通过模板编译的,那么它就是标准的slots子元素,带有_ attribute,可以直接放在组件实例上。

  如果slot对象是用户自己写的,那么就没有_ attribute,所以需要规范化和规格化。

  如果用户的骚操作不遵循规范,那就走normalizeVNodeSlots流程。

  

解析插槽中的内容

  我们先看看子组件编译之后的代码:

  导出函数render(_ctx,_cache,$props,$setup,$data,$options) {

  return (_openBlock(),_createElementBlock(button ,{ class: btn-primary },[

  _renderSlot(_ctx .$老虎机,默认)

  ]))

  }

  上面我们也讲过了插槽/插槽标签被vue3编译之后的就变成了一个叫_renderSlot的函数。

  渲染槽函数接受五个参数,第一个是实例上的插槽函数对象插槽,第二个是插槽的名字,也就是将插槽内容渲染到指定位置,第三个是插槽作用域接收的道具,第四个是插槽的默认内容渲染函数,第五个暂不太清楚什么意思。

  

作用域插槽原理

  作用域插槽是一种子组件传父组件的传参的方式,让插槽内容能够访问子组件中才有的数据。

  子组件模板

  狭槽用户名= coboy /插槽

  编译后的代码

  导出函数render(_ctx,_cache,$props,$setup,$data,$options) {

  return _renderSlot(_ctx .$slots, default ,{ username: coboy })

  }

  父组件模板

  待办事项按钮

  模板v-slot:default=slotProps

  {{ slotProps.username }}

  /模板

  /todo-button

  编译后的代码

  导出函数render(_ctx,_cache,$props,$setup,$data,$options) {

  const _ component _ todo _ button=_ resolve组件( todo-button )

  return (_openBlock(),_ create block(_ component _ todo _ button,null,{

  默认值:_ witchtx((老虎机道具)=[

  _ createTextVNode(_ toDisplayString(slot props。用户名),1 /* TEXT */)

  ]),

  _: 1 /*稳定*/

  }))

  }

  上面讲过渲染槽函数,可以简单概括成下面的代码

  导出函数渲染插槽(插槽,名称,道具){

  const slot=slots[name]

  如果(插槽){

  如果(槽类型===函数){

  return createVNode(Fragment,{},slot(props))

  }

  }

  }

  时间是组件实例上传过来的插槽内容,其实就是这段内容

  {

  默认值:_ witchtx((老虎机道具)=[

  _ createTextVNode(_ toDisplayString(slot props。用户名),1 /* TEXT */)

  ]),

  _: 1 /*稳定*/

  }

  名字是默认,那么插槽[名称]得到的就是下面这个函数

  _ witchtx((老虎机道具)=[

  _ createTextVNode(_ toDisplayString(slot props。用户名),1 /* TEXT */)

  ])

  插槽(道具)就很明显是插槽({用户名: coboy }),这样就把子组件内的数据传到父组件的插槽内容中了。

  

具名插槽原理

  有时我们需要多个插槽。例如对于一个带有如下模板的基本布局组件:

  div class=容器

  页眉

  !-我们希望把页头放这里-

  /页眉

  主要的

  !-我们希望把主要内容放这里-

  /main

  页脚

  !-我们希望把页脚放这里-

  /页脚

  /div

  对于这样的情况,插槽元素有一个特殊的属性:名称。通过它可以为不同的插槽分配独立的ID,也就能够以此来决定内容应该渲染到什么地方:

  !-子组件-

  div class=容器

  页眉

  插槽名称=标题/槽

  /页眉

  主要的

  插槽/插槽

  /main

  页脚

  插槽名称=页脚/插槽

  /页脚

  /div

  一个不带名字的狭槽出口会带有隐含的名字默认。

  在向具名插槽提供内容的时候,我们可以在一个模板元素上使用v形槽指令,并以v形槽的参数的形式提供其名称:

  !-父组件-

  基本布局

  模板v型槽:标题

  氕标题/h1

  /模板

  模板v形槽:默认

  p默认/p

  /模板

  模板v形槽:页脚

  pfooter/p

  /模板

  /base-布局

  父组件编译之后的内容:

  导出函数render(_ctx,_cache,$props,$setup,$data,$options) {

  const _ component _ base _ layout=_ resolve组件( base-layout )

  return (_openBlock(),_ create block(_ component _ base _ layout,null,{

  header:_ witchtx(()=[

  _createElementVNode(h1 ,null, header )

  ]),

  默认值:_ witchtx(()=[

  _createElementVNode(p ,null, default )

  ]),

  页脚:_ witchtx(()=[

  _createElementVNode(p ,null, footer )

  ]),

  _: 1 /*稳定*/

  }))

  }

  子组件编译之后的内容:

  导出函数render(_ctx,_cache,$props,$setup,$data,$options) {

  return (_openBlock(),_createElementBlock(div ,{ class: container },[

  _createElementVNode(header ,null,[

  _renderSlot(_ctx。$slots, header )

  ]),

  _createElementVNode(main ,null,[

  _renderSlot(_ctx。$slots,默认)

  ]),

  _createElementVNode(footer ,null,[

  _renderSlot(_ctx。$插槽,页脚)

  ])

  ]))

  }

  我们可以通过子组件的编译内容看到这三个槽渲染函数。

  _renderSlot(_ctx。$slots, header )

  _renderSlot(_ctx。$slots,默认)

  _renderSlot(_ctx。$插槽,页脚)

  然后我们来回顾一下renderSlot渲染函数。

  //简化Renderslots

  导出函数renderSlots(插槽,名称,道具){

  const slot=slots[name]

  如果(插槽){

  if(槽类型===函数){

  return createVNode(Fragment,{},slot(props))

  }

  }

  }

  这时候我们就可以清楚的知道,所谓的命名函数是通过renderSlots渲染函数的第二个参数来定位要渲染的父组件提供的槽内容。父组件的槽内容在编译后成为对象数据类型。

  {

  header:_ witchtx(()=[

  _createElementVNode(h1 ,null, header )

  ]),

  默认值:_ witchtx(()=[

  _createElementVNode(p ,null, default )

  ]),

  页脚:_ witchtx(()=[

  _createElementVNode(p ,null, footer )

  ]),

  _: 1 /*稳定*/

  }

  

默认内容插槽的原理

  在大多数情况下,我们可能希望在这个按钮中呈现“提交”文本。要使用“Submit”作为替代内容,我们可以将它放在slot标签中。

  按钮类型=提交

  插槽提交/插槽

  /按钮

  现在,当我们在父组件中使用submit-button而不提供任何槽内容时:

  lt;提交按钮gt。lt;/submit-buttongt。

  将呈现替代内容“提交”:

  按钮类型=提交

  使服从

  /按钮

  但是如果我们提供内容:

  提交按钮

  救援

  /提交按钮

  则该提供的内容将被呈现以替换替代内容:

  按钮类型=提交

  救援

  /按钮

  这是什么原理?我们来看看上面默认内容槽的编译代码。

  导出函数render(_ctx,_cache,$props,$setup,$data,$options) {

  return (_openBlock(),_createElementBlock(button ,{ type: submit },[

  _renderSlot(_ctx。$slots, default ,{},()=[

  _createTextVNode(Submit )

  ])

  ]))

  }

  我们可以看到槽函数的内容如下

  _renderSlot(_ctx。$slots, default ,{},()=[

  _createTextVNode(Submit )

  ])

  让我们回头看看renderSlot函数。

  renderSlot函数接受五个参数,第四个是插槽的默认内容呈现函数。

  我们可以从renderSlot函数的源代码中看到,

  第一步是获得由父组件提供的内容槽的内容,

  步骤二,如果父组件提供了槽位内容,则使用父组件提供内容槽位,否则,执行默认内容呈现功能以获得默认内容。

  以上是Vue3槽实现原理的详细内容。更多关于Vue3槽的信息,请关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

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