v-slot
用于声明具名插槽 或 作用域插槽;简写模式:v-slot:top > #top
<slot />
在封装组件时,可以通过<slot>标签定义插槽,从而给预留内容占位;
插槽的html, css内容写在调用组件的父组件中;
匿名插槽
子组件.vue
<template>
<div class="card-wrapper">
<div class="top">标题</div>
<slot></slot> // 占位符,预留内容
</div>
</template>
<template>
<Left>
<h4>{{ msg1 }}</h4>
</Left>
<Left>
<h5>{{ msg2 }}</h5>
</Left>
</template>
<script>
import Left from "./components/Left.vue";
export default {
components: {
Left,
},
data() {
return {
msg1: "给h4的内容",
msg2: "这是给h5...",
};
},
};
</script>

如果调用组件没有传内容,可默认内容
父组件.vue
<template>
<Left></Left>
</template>
子组件.vue
<template>
<div class="card-wrapper">
<div class="top">标题</div>
<slot>没有内容</slot>
</div>
</template>

具名插槽
在封装组件时可以预留多个插槽,为每个<slot>插槽指定具体的name名称;
子组件.vue
<template>
<div class="card-wrapper">
<div class="top">
<slot name="top"></slot>
</div>
<slot>默认内容</slot> // 等价于 <slot name="default">默认内容</slot>
<div class="bot">
<slot name="bot"></slot>
</div>
</div>
</template>
父组件.vue
<template>
<Left>
<template #top>
<div>商品1</div>
</template>
<div style="height:100px;">
{{ msg }}
</div>
<template v-slot:bot>
<div style="color:red">2022-04-28</div>
</template>
</Left>
</template>

作用域插槽
获取子组件插槽的数据
子组件.vue
<template>
<div class="card-wrapper">
<div class="top">
<slot name="top"></slot>
</div>
<slot :content="info"></slot>
<div class="bot">
<slot name="bot" :timer="stampTime"></slot>
</div>
</div>
</template>
<script>
export default {
props:{
info:Object,
stampTime: Object,
}
}
</script>
父组件.vue
<Left :info="info" :stamp-time="timer">
<template #top>
<div>商品1</div>
</template>
<template #default="{ content }">
<div>{{ content.name }}</div>
<div>{{ content.desc }}</div>
</template>
<template #bot="{ timer }">
<div style="color: red">
{{ timer.hour }}-{{ timer.min }}-{{ timer.sec }}
</div>
</template>
</Left>
<script>
import Left from "./components/Left.vue";
export default {
components: { Left },
data() {
return {
info: {
name: "一件不同寻常的商品",
desc: "奇幻、科幻、梦幻",
},
timer: {
hour: "12",
min: "59",
sec: "59",
},
};
},
};
</script>

<Left>
<template #[whichSlot]>
<div>这是内容</div>
</template>
</Left>
<script>
import Left from "./components/Left.vue";
export default {
components: { Left },
data() {
return {
whichSlot: 'default'
};
},
};
</script>
透传命名插槽 和 作用域插槽
<template>
<my-input v-model="searchValue" placeholder="请输入">
<template #addonBefore>
<StrikethroughOutlined />
</template>
</my-input>
</template>
<script lang="ts" setup>
import { StrikethroughOutlined } from "@ant-design/icons-vue";
</script>
<template>
<a-input ref="inputRef" v-bind="$attrs">
<!--
1. UI组件的命名插槽
<template #addonBefore>
<StrikethroughOutlined />
</template>
-->
<!--
2. 将自定义组件的命名插槽 传递给 UI组件的命名插槽;
这种方案在没有传递内容时, 依然给UI组件的命名插槽addonBefore传了空内容的<slot name="before"/>标签过去;
<template #addonBefore>
<slot name="before"></slot>
</template>
-->
<!-- 3. 将传递给自定义组件标签上的所有属性和方法,绑定透传给UI组件上 -->
<template v-for="(value, slotName) in $slots" #[slotName]="slotData">
<!-- 再将UI组件的插槽数据slotData重新绑定到自定义组件的命名插槽上 -->
<slot :name="slotName" v-bind="slotData || {}"></slot>
</template>
</a-input>
</template>
<script setup>
import { ref } from "vue";
const inputRef = ref(null);
</script>