插槽(Slots):让组件更灵活
插槽(Slots):让组件更灵活
插槽让你在组件中预留一个"口子",让父组件决定里面放什么。这是 Vue 最强大的组合特性之一。
默认插槽
子组件定义插槽:
<!-- Card.vue -->
<template>
<div class="card">
<h3>{{ title }}</h3>
<slot></slot>
</div>
</template>
<script setup lang="ts">
defineProps<{ title: string }>()
</script>
父组件填充:
<Card title="用户信息">
<p>这里是插槽内容</p>
<p>可以放任意内容</p>
</Card>
具名插槽
子组件有多个插槽,给它们起名字:
<!-- Modal.vue -->
<template>
<div class="modal">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
父组件指定插槽:
<Modal>
<template #header>
<h2>标题</h2>
</template>
<p>主要内容</p>
<template #footer>
<button>取消</button>
<button>确定</button>
</template>
</Modal>
#header 是 v-slot:header 的简写。
作用域插槽
子组件的数据可以传递给插槽,让父组件决定怎么渲染:
<!-- UserList.vue -->
<script setup lang="ts">
const users = ref([
{ name: '张三', age: 25 },
{ name: '李四', age: 30 }
])
</script>
<template>
<div>
<slot v-for="user in users" :user="user"></slot>
</div>
</template>
父组件决定渲染方式:
<UserList>
<template #default="{ user }">
<p>{{ user.name }} - {{ user.age }}岁</p>
</template>
</UserList>
动态插槽名
插槽名也可以是动态的:
<template #[slotName]>内容</template>
<script setup>
const slotName = ref('header')
</script>
插槽的典型场景
布局组件
<!-- Layout.vue -->
<template>
<div class="layout">
<aside><slot name="sidebar" /></aside>
<main><slot /></main>
</div>
</template>
表单组件
<!-- Form.vue -->
<template>
<form>
<slot name="fields" :formData="formData" />
<button @click.prevent="handleSubmit">提交</button>
</form>
</template>
总结
<slot>定义插槽位置name属性定义具名插槽#slotName使用具名插槽- 作用域插槽让子组件数据传给父组件
- 插槽让组件更通用、更灵活
下篇讲自定义指令和 Teleport。
