关于slot
web组件内部的占位符,可以使用自己的标记填充这个占位符
,具名插槽就是在slot标签上添加name属性(https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/slot)
vue3官方文档:https://cn.vuejs.org/guide/components/slots.html#named-slots
子组件FancyButton
<script setup>
</script>
<template>
<button class="fancy-btn">
<slot>
<!-- 如果父组件没有提供插槽内容的时候就会显示默认值 -->
submit
</slot>
</button>
</template>
<style>
.fancy-btn {
color: #fff;
background: linear-gradient(315deg, #42d392 25%, #647eff);
border: none;
padding: 5px 10px;
margin: 5px;
border-radius: 8px;
cursor: pointer;
}
</style>
在父组件中引入,并使用
<script setup>
import FancyButton from "./components/FancyButton.vue";
</script>
<template>
<FancyButton>click me</FancyButton>
<FancyButton></FancyButton>
</template>
分别显示
###具名插槽
当一个组件包含多个插件出口时,就需要用到具名插槽即为slot标签添加name属性,没有提供 name 的 出口会隐式地命名为“default”
Layout.vue
<script setup>
</script>
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot>
</slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
父组件中使用
当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 节点都被隐式地视为默认插槽的内容
<script setup>
import Layout from './components/Layout.vue'
</script>
<template>
<!-- 具名插槽 -->
<Layout>
<template v-slot:header>
<h1>头部插槽内容</h1>
</template>
<p>其他内容,就是没有指定插槽名称的会显示在默认插槽里面</p>
<template #footer>
底部插槽内容,插槽也可以写成#footer的形式
</template>
</Layout>
</template>
条件插槽
根据插槽是否存在来渲染内容
Card.vue
<script setup>
</script>
<template>
<div class="card">
<div v-if="$slots.header" class="header">
<slot name="header"></slot>
</div>
<div v-if="$slots.default" class="main">
<slot></slot>
</div>
<div v-if="$slots.footer" class="footer">
<slot name="footer"></slot>
</div>
</div>
</template>
<style>
.card{
border: 1px solid rgb(151, 138, 204);
}
.header{
color: cornflowerblue;
}
.footer{
background: darkseagreen;
}
</style>
使用
在使用子组件Card时,除了具名插槽,其他的标签和内容不能写进去
<script setup>
import Card from './components/Card.vue'
</script>
<template>
<Card>
<!-- <template #header>
<h1>This is the header</h1>
</template> header将不显示-->
<!-- <p>默认插槽内容</p> 不能这样写会报错-->
<template #default>
<p>This is the content</p>
</template>
<template #footer>
<em>This is the footer</em>
</template>
</Card>
</template>
正常使用的展示
动态插槽
动态指令参数在 v-slot 上也是有效的,即可以定义下面这样的动态插槽名:
<script setup>
import Card from './components/Card.vue'
function changeDynamicSlotName(){
dynamicSlotName.value = dynamicSlotName.value === "header" ? "footer" : "header"
}
</script>
<template>
<!-- 动态插槽 -->
<button @click="changeDynamicSlotName">change dynamicSlotName</button>
<Card>
<!-- 也可以写成v-slot: dynamicSlotName-->
<template #[dynamicSlotName]>
<h1>This is the header</h1>
</template>
</Card>
</template>
作用域插槽
插槽的内容无法访问到子组件的状态,在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。通过像对组件传递 props 那样,向一个插槽的出口上传递 attributes,el-table中就使用了作用域插槽
FancyButton.vue
<script setup>
const greetingMessage='我是fancyButton组件'
</script>
<template>
<button class="fancy-btn">
<slot :text="greetingMessage">
<!-- 如果父组件没有提供插槽内容的时候就会显示默认值 -->
submit
</slot>
</button>
</template>
<style>
.fancy-btn {
color: #fff;
background: linear-gradient(315deg, #42d392 25%, #647eff);
border: none;
padding: 65px 50px;
margin: 5px;
border-radius: 8px;
cursor: pointer;
}
</style>
父组件中使用
<script setup>
import Card from './components/Card.vue'
function changeDynamicSlotName(){
dynamicSlotName.value = dynamicSlotName.value === "header" ? "footer" : "header"
}
</script>
<template>
<!-- 作用域插槽 -->
<FancyButton v-slot="props">{{props.text}}</FancyButton>
</template>