Vue3 高级插槽用法
Vue3的插槽(Slots)系统是组件化开发中一个非常强大的特性,它允许开发者在组件之间传递内容,从而实现更灵活、更可复用的组件。在Vue3中,插槽在Vue2的基础上进行了优化,提供了更清晰的具名插槽语法和更强大的作用域插槽,使得组件的组合能力得到了进一步提升。
# 什么是插槽?
插槽是Vue组件中用于内容分发的一种机制。它允许父组件向子组件的指定位置注入内容,而子组件则负责渲染这些内容。这使得组件可以更加通用,父组件可以根据需要自定义子组件的内部结构。
# 1. 具名插槽 (Named Slots)
具名插槽允许父组件向子组件的多个不同位置注入内容。每个具名插槽都有一个唯一的名称,父组件通过这个名称来指定内容应该被渲染到哪个插槽。
# 子组件定义具名插槽
在子组件中,使用<slot name="name"></slot>来定义具名插槽。如果没有name属性,则默认为default插槽。
<!-- ChildComponent.vue -->
<template>
<div class="card">
<header>
<slot name="header">默认头部内容</slot>
</header>
<main>
<slot>默认主要内容</slot>
</main>
<footer>
<slot name="footer">默认底部内容</slot>
</footer>
</div>
</template>
# 父组件使用具名插槽
父组件通过v-slot:name或其简写形式#name来向具名插槽传递内容。
<!-- ParentComponent.vue -->
<template>
<ChildComponent>
<!-- 传递内容给 header 插槽 -->
<template #header>
<h1>自定义标题</h1>
</template>
<!-- 传递内容给 default 插槽 -->
<p>这是父组件传递给默认插槽的内容。</p>
<!-- 传递内容给 footer 插槽 -->
<template #footer>
<button>点击我</button>
</template>
</ChildComponent>
</template>
# 2. 作用域插槽 (Scoped Slots)
作用域插槽是插槽系统中最强大的特性之一。它允许子组件向父组件的插槽内容传递数据,使得父组件可以根据子组件提供的数据来渲染插槽内容。这在构建可复用的列表组件、表格组件等场景中非常有用。
# 子组件定义作用域插槽
子组件在<slot>标签上绑定属性,这些属性将作为插槽的props传递给父组件。
<!-- ListComponent.vue -->
<template>
<ul>
<li v-for="(item, index) in items" :key="item.id">
<!-- 将 item 和 index 作为插槽 props 传递 -->
<slot :item="item" :index="index">
<!-- 默认内容,如果父组件没有提供插槽内容,则显示此内容 -->
{{ index + 1 }}. {{ item.name }}
</slot>
</li>
</ul>
</template>
<script setup>
import { ref } from 'vue';
const items = ref([
{ id: 1, name: 'Apple', price: 1.0 },
{ id: 2, name: 'Banana', price: 0.5 },
{ id: 3, name: 'Orange', price: 1.2 }
]);
</script>
# 父组件使用作用域插槽
父组件通过v-slot="slotProps"或v-slot="{ item, index }"(解构赋值)来接收子组件传递的数据。
<!-- ParentComponent.vue -->
<template>
<h2>商品列表</h2>
<ListComponent v-slot="{ item, index }">
<div class="item-card">
<span>{{ index + 1 }}. {{ item.name }}</span>
<span class="price">${{ item.price.toFixed(2) }}</span>
<button>购买</button>
</div>
</ListComponent>
<h2>简单列表</h2>
<ListComponent>
<!-- 不使用作用域插槽,将显示子组件的默认内容 -->
</ListComponent>
</template>
<style scoped>
.item-card {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border: 1px solid #eee;
margin-bottom: 5px;
}
.price {
font-weight: bold;
color: green;
}
</style>
# 具名作用域插槽
具名插槽和作用域插槽可以结合使用。
<!-- ChildComponent.vue -->
<template>
<div>
<slot name="header" :title="headerTitle"></slot>
<slot :data="mainData"></slot>
</div>
</template>
<script setup>
import { ref } from 'vue';
const headerTitle = ref('这是头部标题');
const mainData = ref('这是主要数据');
</script>
<!-- ParentComponent.vue -->
<template>
<ChildComponent>
<template #header="{ title }">
<h2>{{ title }}</h2>
</template>
<template #default="{ data }">
<p>从子组件获取的数据: {{ data }}</p>
</template>
</ChildComponent>
</template>
# 总结
Vue3的高级插槽用法,特别是具名插槽和作用域插槽,为组件的灵活性和可复用性提供了强大的支持。通过合理利用插槽,开发者可以构建出更加通用、易于维护的组件,从而提升整个应用的开发效率和质量。掌握插槽的精髓,是成为一名优秀的Vue开发者不可或缺的技能。