深入理解vue slot插槽

单个插槽

只使用这个标签的话,可以将父组件放在子组件的内容,放到想让他显示的地方

具名插槽

将放在子组件里的不同html标签放在不同的位置
父组件在要分发的标签里添加 slot=’name’ 属性
子组件在对应分发的位置的slot标签里,添加name=’name’ 属性,
然后就会将对应的标签放在对应的位置了

这里写图片描述

案例地址:http://dotwe.org/vue/e639fd36e7af82cce248ef835fa5d761
从案例里面知道, 可以多次定义具名slot的内容,内容会被按顺序append到插槽中。未指定slot值的元素会被append到匿名插槽中。

Vue slot 原理

web-components中有slot的概念,https://developers.google.com/web/fundamentals/web-components/shadowdom

<slot> 元素
Shadow DOM 使用 <slot> 元素将不同的 DOM 树组合在一起。Slot 是组件内部的占位符,用户可以使用自己的标记来填充。

通过定义一个或多个 slot,您可将外部标记引入到组件的 shadow DOM 中进行渲染。 这相当于您在说“在此处渲染用户的标记”。

注:Slot 是为网络组件创建“声明性 API”的一种方法。它们混入到用户的 DOM 中,帮助对整个组件进行渲染,从而将不同的 DOM 树组合在一起。

如果 <slot> 引入了元素,则这些元素可“跨越” shadow DOM 的边界。 这些元素称为分布式节点。从概念上来看,分布式节点似乎有点奇怪。 Slot 实际上并不移动 DOM;它们在 shadow DOM 内部的其他位置进行渲染。

组件可在其 shadow DOM 中定义零个或多个 slot。Slot 可以为空,或者提供回退内容。 如果用户不提供 light DOM 内容,slot 将对其备用内容进行渲染。

<!-- Default slot. If there's more than one default slot, the first is used. -->
<slot></slot>

<slot>Fancy button</slot> <!-- default slot with fallback content -->

<slot> <!-- default slot entire DOM tree as fallback -->
  <h2>Title</h2>
  <summary>Description text</summary>
</slot>

您还可以创建已命名 slot。已命名 slot 是 shadow DOM 中用户可通过名称引用的特定槽。

例如 - <fancy-tabs> shadow DOM 中的已命名 slot:

#shadow-root
  <div id="tabs">
    <slot id="tabsSlot" name="title"></slot>
  </div>
  <div id="panels">
    <slot id="panelsSlot"></slot>
  </div>
组件用户对 <fancy-tabs> 的声明类似于:

<fancy-tabs>
  <button slot="title">Title</button>
  <button slot="title" selected>Title 2</button>
  <button slot="title">Title 3</button>
  <section>content panel 1</section>
  <section>content panel 2</section>
  <section>content panel 3</section>
</fancy-tabs>

<!-- Using <h2>'s and changing the ordering would also work! -->
<fancy-tabs>
  <h2 slot="title">Title</h2>
  <section>content panel 1</section>
  <h2 slot="title" selected>Title 2</h2>
  <section>content panel 2</section>
  <h2 slot="title">Title 3</h2>
  <section>content panel 3</section>
</fancy-tabs>

而且如果您很好奇,您会发现扁平树看起来类似于:


<fancy-tabs>
  #shadow-root
    <div id="tabs">
      <slot id="tabsSlot" name="title">
        <button slot="title">Title</button>
        <button slot="title" selected>Title 2</button>
        <button slot="title">Title 3</button>
      </slot>
    </div>
    <div id="panels">
      <slot id="panelsSlot">
        <section>content panel 1</section>
        <section>content panel 2</section>
        <section>content panel 3</section>
      </slot>
    </div>
</fancy-tabs>

注意,我们的组件可处理不同的配置,但是扁平的 DOM 树保持不变。 我们还可以从 <button> 切换到 <h2>。 编写此组件的目的在于处理不同类型的子项 - 如同 <select> 一样。

通过vue的渲染过程,可以看出slot渲染的原理
vm对象的$slots 会存储组件的所有插槽的vdom, 主要通过解析children,如果子组件指定了插槽名,会将vdom push 到对应名称的数组中,否则会push到default的数组中。

// named slots should only be respected if the vnode was rendered in the
// same context.
if ((child.context === context || child.fnContext === context) &&
  data && data.slot != null
) {
  const name = data.slot
  const slot = (slots[name] || (slots[name] = []))
  if (child.tag === 'template') {
    slot.push.apply(slot, child.children || [])
  } else {
    slot.push(child)
  }
} else {
  (slots.default || (slots.default = [])).push(child)
}

具体可以参看vue源码中的resolve-slots过程

https://github.com/vuejs/vue/blob/dev/src/core/instance/render-helpers/resolve-slots.js#L17

那么创建DOM的过程就可以通过名称拿到具体组件:

// 单个插槽(匿名插槽)
this.$slots['default'];
// 具名插槽
this.$slots[slotName]
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Vue中的Slots)是一种在父组件中将子组件的内容进行分发的机制。通过,我们可以在父组件中定义一些占位符,然后在子组件中填充具体的内容。 在Vue中,有两种类型:具名和默认。 具名允许我们在父组件中使用多个不同的,并且可以根据需要进行分发和填充。我们可以使用`<slot>`元素和`name`属性来定义具名。例如: ```html <!-- 父组件 --> <template> <div> <slot name="header"></slot> <slot></slot> <slot name="footer"></slot> </div> </template> <!-- 子组件 --> <template> <div> <slot name="header"> <!-- 默认内容 --> <h1>默认标题</h1> </slot> <p>子组件内容</p> <slot name="footer"> <!-- 默认内容 --> <p>默认页脚</p> </slot> </div> </template> ``` 在上面的例子中,父组件定义了三个:`header`、默认和`footer`。子组件可以根据需要填充这些,并且如果没有提供相应的内容,那么会显示中的默认内容。 默认是没有名字的,如果在父组件中没有定义具名的话,子组件的内容会被分发到默认中。 除了使用`<slot>`元素和`name`属性来定义,我们还可以使用`<template>`元素和`v-slot`指令来定义和填充。例如: ```html <!-- 父组件 --> <template> <div> <template v-slot:header> <!-- 内容 --> </template> <!-- 默认内容 --> <template v-slot:default> <!-- 内容 --> </template> <template v-slot:footer> <!-- 内容 --> </template> </div> </template> ``` 使用可以使我们的组件更具灵活性,可以根据需要在父组件中定制子组件的部分内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值