参考文档 插槽 Slots | Vue.js
1. 基本概念
Vue的插槽(slot),简单来说,就是一种 定义在组件中的 “占位符”。用于实现现组件的内容分发和复用。如下,是一个简单的默认插槽:
<!-- Parent.vue -->
<template><slot-com>按钮text </slot-com>
</template>
<script setup lang="ts">
import SlotCom from '@/components/SlotCom.vue'
</script><!-- ButtonCom.vue -->
<template><button><slot></slot></button>
</template>
渲染出来的DOM
<button>按钮text</button>
2. 具名插槽
有时在一个组件中可能会包含多个插槽出口,这时候就需要对它们进行区分,以便把内容渲染到对应区域。对此,<slot> 元素可以有一个特殊的 attribute name,用来给各个插槽分配唯一的 ID,以确定每一处要渲染的内容:
<!-- layout.vue -->
<header><!-- 标题内容放这里 --><slot name="header"></slot>
</header>
<main><!-- 主要内容放这里 --><slot></slot>
</main>
<footer><!-- 底部内容放这里 --><slot name="footer"></slot>
</footer>
具名,就是有name的。匿名,也就是没有name的,会隐式地命名为“default”。
使用 带有 v-slot 指令的template 标签为具名插槽传入内容
<layout><template v-slot:header><!-- header 插槽的内容放这里 --></template>
</layout>
v-slot 有对应的简写形式 #,所以 <template v-slot:header> 也可以简写为 <template #header>
<BaseLayout><template #header><h1>Here might be a page title</h1></template><template #default><p>A paragraph for the main content.</p><p>And another one.</p></template><template #footer><p>Here's some contact info</p></template>
</BaseLayout>
3. 条件插槽
有时需要根据插槽是否存在来渲染某些内容,结合v-if指令可以实现,仅当有向某个插槽传递内容时才会渲染对应的DOM
<template><div class="card"><div v-if="$slots.header" class="card-header"><slot name="header"></slot></div><div v-if="$slots.default" class="card-content"><slot></slot></div><div v-if="$slots.footer" class="card-footer"><slot name="footer"></slot></div></div>
</template>
4. 动态插槽
vue 的模板语法支持 在指令参数上使用一个 JS 表达式,需要包含在一对方括号内:
<a v-bind:[attributeName]="url"> ... </a>
<!-- 简写 -->
<a :[attributeName]="url"> ... </a>
这个特性,在 v-slot 上也是有效的,即可以定义下面这样的动态插槽名:
<SlotCom><template v-slot:[dynamicSlotName]> ... </template><!-- 缩写为 --><template #[dynamicSlotName]> ... </template>
</SlotCom>const dynamicSlotName = ref('header')
5. 作用域插槽
1.渲染作用域
尽管父组件提供的插槽内容,会被放入插槽组件对应的位置,但因为插槽内容本身依然是在父组件模板中定义的,所以插槽内容可以访问到父组件的数据作用域。且因为组件作用域的私有性,插槽内容无法访问子组件的数据。比如:
父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。
2. 默认作用域插槽
上面提到,默认情况下,插槽的内容无法访问到子组件的状态,但在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。这时候就可以这样做:
像对组件传递 props 那样,向插槽的出口上传递 attributes:
<!-- <MyComponent> 的模板 -->
<div><slot :text="greetingMessage" :count="1"></slot>
</div>
默认插槽接受 props,通过子组件标签上的 v-slot
指令,直接接收到一个插槽 props 对象:
<MyComponent v-slot="slotProps">{{ slotProps.text }} {{ slotProps.count }}
</MyComponent><!-- 也可以直接使用解构 -->
<MyComponent v-slot="{ text, count }">{{ text }} {{ count }}
</MyComponent>
3. 具名作用域插槽
和默认作用域插槽基本一样,不同的是,指令为 v-slot:name="slotProps"
<MyComponent><template v-slot:header="headerProps">{{ headerProps }}</template><--或者简写形式 --><template #header="headerProps">{{ headerProps }}</template>
</MyComponent>
若有错误或描述不当的地方,烦请评论或私信指正,万分感谢 😃
很多知识笔者也是通过从各种教程里搬运以及请教 “C老师” 写出来的,自己也没有完全掌握,这也是我写本文的最主要目的,搜集知识,忘了的时候自己看看。共勉!💪
如果我的文章对你有帮助,你的赞👍就是对我的最大支持^_^