vue3插槽

70 阅读1分钟

- 基础

  • <slot>是一个插槽出口,在子组件中标识了父组件中传递的内容应该在哪里渲染;通过使用插槽子组件只负责渲染(外层的样式及html标签),内部内容由父组件提供。
  • 插槽内容可以是任意合法模板内容,可传入多个元素或组件

js实现其原理为

// 父元素传入插槽内容
FancyButton('Click me!')
// FancyButton 在自己的模板中渲染插槽内容
function FancyButton(slotContent) {
  return `<button class="fancy-btn">
      ${slotContent}
    </button>`
}

其作用域

插槽内容可以访问到父组件的数据作用域,因为其本身是在父组件模板中定义的

默认插槽内容

在外部没有提供任何内容的情况下,可以为插槽指定默认内容

例子:

<button type="submit">
  <slot>
    Submit <!-- 默认内容 -->
  </slot>
</button>

具名插槽

子组件
  • <slot>元素拥有一个特殊的name属性可以给各个插槽分配唯一的id,以及确定每一处插槽渲染的内容; 这类插槽被称为:具名插槽。没有提供name<slot>出口会被隐式命名为default
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
父组件
  • 在父组件中要给子组件插槽传递内容时,需要用到一个包含v-slot指令的<template>元素并将目标插槽的名字传给该指令。
  • v-slot有对应的简写#,比如<template v-slot:name>可以简写为<template #name>
  • 当一个组件同时接收默认插槽和具名插槽时,所有顶级的非<template>节点都会被视为默认插槽的内容
<BaseLayout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <!-- 隐式的默认插槽 -->
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>
<!--v-slot简写-->
  <template #footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>

js函数类比具名插槽

// 传入不同的内容给不同名字的插槽
BaseLayout({
  header: `...`,
  default: `...`,
  footer: `...`
})

// <BaseLayout> 渲染插槽内容到对应位置
function BaseLayout(slots) {
  return `<div class="container">
      <header>${slots.header}</header>
      <main>${slots.default}</main>
      <footer>${slots.footer}</footer>
    </div>`
}

动态插槽

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

  <!-- 缩写为 -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>

作用域插槽

父组件模板中的表达式只能访问父组件的作用域,子组件模板中的表达式只能访问子组件的作用域。 插槽的内容如何同时使用父组件和子组件域的数据呢?
  1. 在插槽的出口上传递attributes(属性)
<!-- <MyComponent> 的模板 -->
<div>
  <slot :text="greetingMessage" :count="1"></slot>
</div>

2.在父组件中如何接收子组件传过来的数据呢? 在默认插槽中,是通过子组件标签上的v-slot指令来接收一个插槽对象slotProps

<MyComponent v-slot="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

同时也可以使用解构

<MyComponent v-slot="{text,cont}">
{{text}}{{cont}}
<MyComponent/>

具名作用域插槽

  • v-slot:name="slotPros" 可简写为 #name="slotProps"
<MyComponent>
  <template #header="headerProps">
    {{ headerProps }}
  </template>

  <template #default="defaultProps">
    {{ defaultProps }}
  </template>

  <template #footer="footerProps">
    {{ footerProps }}
  </template>
</MyComponent>