默认插槽
插槽可以让父组件给子组件传递模板片段
- 在父组件中,在组件内编写模板片段传递给子组件
- 在子组件中,编写
slot
元素,指定模板片段输出的位置
- 插槽内容可以访问到父组件的数据,但无法访问到子组件的数据。因为插槽本身是在父组件模板中定义的
- 可以在子组件的
slot
标签内设置插槽的默认内容。当父组件没有提供任何插槽内容时,子组件会渲染默认内容
<template>
<!-- 在组件内编写模板片段传递给子组件 -->
<HelloWorld> {
{ content }} </HelloWorld>
</template>
<script lang="ts" setup>
import HelloWorld from '@/components/HelloWorld.vue';
import {
ref } from 'vue';
const content = ref('插槽内容');
</script>
<template>
<p>
<!-- 编写 `slot` 元素,指定模板片段输出的位置 -->
<slot> 插槽默认内容 </slot>
</p>
</template>
具名插槽
当一个组件中包含多个插槽出口时,需使用具名插槽指定父组件中的内容要传到哪个 slot
元素内
-
在子组件中,给
slot
元素设置name
attribute,来唯一标识各个插槽没有提供
name
的slot
会隐式地命名为'default'
-
在父组件中,给
template
元素设置v-slot
指令,并将目标插槽的名字传给该指令v-slot
指令可以简写为#
- 默认插槽写法:
v-slot
/v-slot:default
/#default
- 具名插槽写法:
v-slot:XXName
/#XXName
- 默认插槽写法:
<template>
<p>
<slot name="header"> header 插槽默认内容 </slot>
<slot> 插槽默认内容 </slot>
<slot name="footer"> footer 插槽默认内容 </slot>
</p>
</template>
<template>
<HelloWorld>
<template #header> header </template>
<template #default> default </template>
<template #footer> footer </template>
</HelloWorld>
</template>
<script lang="ts" setup>
import HelloWorld from '@/components/HelloWorld.vue';
</script>
- 当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非
template
节点都被隐式地视为默认插槽内容。
所以上例可以写成:
<template>
<HelloWorld>
<template #header> header </template>
<!-- 隐式的默认插槽 -->
default
<template #footer> footer </template>
</HelloWorld>
</template>
作用域插槽
在某些场景下,插槽的内容需要使用到子组件中的数据。此时可以使用作用域插槽
- 在子组件中,给
slot
元素设置自定义属性,以传递数据给父组件 - 在父组件中,从
v-slot
指令的值中获取子组件传递过来的数据- 默认插槽写法:
v-slot="XXX"
/v-slot:default="XXX"
/#default="XXX"
- 具名插槽写法:
v-slot:XXName="XXX"
/#XXName="XXX"
- 默认插槽写法:
- 注意插槽上的
name
是一个 Vue 特别保留的 attribute,不会作为 props 传递给插槽
<template>
<p>
<slot
name="header"
text="header slot"
>
header 插槽默认内容
</slot>
<!-- 使用 v-bind 设置自定义属性 -->
<slot v-bind="data"> 插槽默认内容 </slot>
</p>
</template>
<script setup lang="ts">
import {
ref } from 'vue';
const data = ref({
text: 'default slot', number: 1 });
</script>
<template>
<HelloWorld>
<template #header="headerData"> header: {
{ headerData }} </template>
<!-- 使用 [解构赋值] 获取子组件传递过来的数据 -->
<template #default="{ text, number }"> default: {
{ text }} - {
{ number }}</template>
</HelloWorld>
</template>
<script lang="ts" setup>
import HelloWorld from '@/components/HelloWorld.vue';
</script>
动态插槽名
可以给 v-slot
指令传递动态参数,就可以定义动态插槽名啦
- 动态参数中表达式的值只能为 String /
null
;null
表示移除该绑定 - 动态参数表达式有一些语法限制,比如空格和引号,在 HTML attribute 名称中都是不合法的;
推荐使用 [计算属性] 替换复杂的表达式
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
<!-- 缩写为 -->
<template #[dynamicSlotName]>
...
</template>
</base-layout>