插槽(Slots)是 Vue.js 框架中的一个功能,允许在组件内部预留一些可替换的内容。通过插槽,可以给父组件填充模板代码,让父组件向子组件传递自定义的内容,以便在子组件中进行展示或处理。
1. 匿名插槽
匿名(默认)插槽是指在子组件中没有具名插槽时使用的插槽。如果子组件没有定义具名插槽,那么父组件中的内容将自动插入子组件的默认插槽中。
Son.vue
<template>
<div>
<header class="header"></header>
<main class="main">
<!-- 这里用于占位(父组件传内容,子组件接收) -->
<slot></slot>
</main>
<footer class="footer"></footer>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.header {
height: 200px;
background-color: red;
color: white;
}
.main {
height: 300px;
background-color: blue;
color: white;
}
.footer {
height: 200px;
background-color: green;
color: white;
}
</style>
App.vue
<template>
<div class="content">
<Son>
<template v-slot>
<div>插入中间</div>
</template>
</Son>
</div>
</template>
<script setup lang="ts">
import Son from './components/Son.vue'
</script>
<style scoped>
</style>
2. 具名插槽
具名插槽允许定义多个插槽,并且为每个插槽起一个名字。这样,父组件在使用子组件时可以选择性地往不同的插槽中传递内容。
Son.vue
<template>
<div>
<header class="header">
<slot name="header"></slot>
</header>
<main class="main">
<slot></slot>
</main>
<footer class="footer">
<slot name="footer"></slot>
</footer>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.header {
height: 200px;
background-color: red;
color: white;
}
.main {
height: 300px;
background-color: blue;
color: white;
}
.footer {
height: 200px;
background-color: green;
color: white;
}
</style>
App.vue
<template>
<div class="content">
<Son>
<template v-slot:header>
<div>插入上面</div>
</template>
<template v-slot>
<div>插入中间</div>
</template>
<template v-slot:footer>
<div>插入下面</div>
</template>
</Son>
</div>
</template>
<script setup lang="ts">
import Son from './components/Son.vue'
</script>
<style scoped>
</style>
3. 插槽作用域
作用域插槽是Vue中另一种强大的插槽类型,它允许子组件向父组件传递数据,并且在父组件中使用该数据进行渲染。这种机制可以让父组件更加灵活地控制子组件的渲染逻辑。
可以理解为数据在子那边,但根据数据生成的结构,却由父亲决定。压岁钱在孩子那,但根据压岁钱买的东西,却由父亲决定。
Son.vue
<template>
<div>
<header class="header">
<slot name="header"></slot>
</header>
<main class="main">
<div v-for="(item,index) in data">
<slot :index="index" :data="item"></slot>
</div>
</main>
<footer class="footer">
<slot name="footer"></slot>
</footer>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
type names = {
name: string,
age: number
}
const data = reactive<names[]>([
{
name: '张三',
age: 18
},
{
name: '李四',
age: 19
},
{
name: '王五',
age: 20
}
])
</script>
<style scoped>
.header {
height: 200px;
background-color: red;
color: white;
}
.main {
height: 300px;
background-color: blue;
color: white;
}
.footer {
height: 200px;
background-color: green;
color: white;
}
</style>
App.vue
<template>
<div class="content">
<Son>
<template v-slot:header>
<!-- 简写为:#header -->
<div>插入上面</div>
</template>
<!-- 直接解构出 data index -->
<template v-slot="{ data, index }">
<!-- 匿名插槽简写为:#default="{ data, index }" -->
<div>{{ data.name }}--{{ data.age }}--{{ index }}</div>
</template>
<template v-slot:footer>
<div>插入下面</div>
</template>
</Son>
</div>
</template>
<script setup lang="ts">
import Son from './components/Son.vue'
</script>
<style scoped></style>
4. 动态插槽
App.vue
<template>
<div class="content">
<Son>
<template v-slot:[name]>
<!-- 或者简写为:#[name] -->
<div>
我在哪儿?
</div>
</template>
</Son>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import Son from './components/Son.vue'
let name = ref('footer')
// let name = ref('deault') // 插入中间的匿名插槽
</script>
<style scoped></style>