vue3 插槽

79 阅读2分钟

默认插槽

<!-- 组件B内容  -->
<template>
  <div>
    <slot>B组件</slot>
  </div>
</template>
<!-- 父组件内容  -->
<CompB>
    父组件提供的插槽内容
</CompB>

渲染后内容:

<div> 父组件提供的插槽内容 </div>

如果父组件没有提供插槽内容,即使用方式为:

<CompB/>

渲染后内容:

<div>B组件</div>

具名插槽

这类带 name 的插槽被称为具名插槽 (named slots)。没有提供 name 的 <slot> 出口会隐式地命名为“default”。

要为具名插槽传入内容,我们需要使用一个含 v-slot 指令的 <template> 元素,并将目标插槽的名字传给该指令:

<!-- B组件内容 -->
<template>
  <div>
    <div class="header">
      header内容
      <slot name="header">header默认值</slot>
    </div>
    <div class="main">
      main内容
      <slot name="main"></slot>
    </div>

    <div class="footer">
      footer内容
      <slot name="footer"></slot>
    </div>

  </div>
</template>
<!-- 父组件内容 -->
<CompB>
    <template #header>
      父组件传入的header
    </template>
    <template #main>
      父组件传入的main
    </template>
    <template #footer>
      父组件传入的footer
    </template>
</CompB>

渲染内容:

<div>
    <div class="header"> header内容  父组件传入的header </div>       
    <div class="main"> main内容  父组件传入的main </div>
    <div class="footer"> footer内容  父组件传入的footer</div>
</div>

当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容,如果存在<template>节点,该节点的内容不会被渲染

动态插槽名

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

  <!-- 缩写为 -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>
const dynamicSlotName = ref('header')

作用域插槽

在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时将一部分数据提供给插槽。

我们也确实有办法这么做!可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes:

只有一个具名插槽或者默认插槽

<CompB v-slot="{ count, text }">
    {{ count }} -- {{ text }}
</CompB>
<CompB #default="{ count, text }">
      {{ count }} --- {{ text }}
</CompB>
<CompB>
    <template #default="{ count, text }">
      {{ count }} --- {{ text }}
    </template>
</CompB>
<CompB #main="{ content }">
      {{ content }}
</CompB>
<!-- CompB模板 -->
<template>
  <div>
    <slot text="a message" count="1"></slot>
    <div style="width: 300px; height: 100px; border: 1px solid #ccc;">
      <slot name="main" content="child content"></slot>
    </div>
  </div>
</template>

有多个具名插槽

<CompB>
    <template #default="{ count, text }">
      {{ count }} --- {{ text }}
    </template>
    <template #main="{ content }">
      <div style="background-color: #E9967A; height: 100%;">{{ content }}</div>
    </template>
</CompB>

如果你同时使用了具名插槽与默认插槽,则需要为默认插槽使用显式的 <template> 标签。尝试直接为组件添加 v-slot 指令将导致编译错误,同时在编写代码过程中,编辑器也会提示错误。这是为了避免因默认插槽的 props 的作用域而困惑