Vue3$View-Slots
0. Slots in Big Picture
我们知道,在 Vue 中,数据 data 驱动着页面 view。之前我们已经讨论了 data,现在讨论 view。
在 Vue 中,我们使用 template 来表示 view,之前的 Vue3$View-Template 里讨论了 template 的基本语法。
除了可以定义自己的 template,组件也可以接收外部的 template。而这个预留的空间,就是slot。
props 和 slot 的理解:
- props 接收的是数据(虽然也可以是函数)
- slot 接收的是函数(函数可以返回各种类型,也就可以返回 template)
1. Slot 的基本使用 Slot Content and Outlet
// @file FancyButton.vue
<button class="fancy-btn">
<slot></slot> <!-- slot outlet -->
</button>
<FancyButton>
Click me! <!-- slot content -->
</FancyButton>
1.1 Fallback Content
<button type="submit">
<slot>
Submit <!-- fallback content -->
</slot>
</button>
2. Named Slots
当有多个 slots 时,可以给每个 slot 命名(name),没有命名的名字为 default。
// @file BaseLayout.vue -- producer
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
// consumer
<BaseLayout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<template #default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
2.1 Dynamic Slot Names
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
<!-- with shorthand -->
<template #[dynamicSlotName]>
...
</template>
</base-layout>
3. Conditional Slots
<template>
<div class="card">
<div v-if="$slots.header" class="card-header">
<slot name="header" />
</div>
<div v-if="$slots.default" class="card-content">
<slot />
</div>
<div v-if="$slots.footer" class="card-footer">
<slot name="footer" />
</div>
</div>
</template>
4. Scoped Slots
默认情况下,consumer 传给 slot 的内容只能包含自身的数据。如果 consumer 想在 slot 中使用 producer 自身的数据,可以使用 scoped slots。即接收 slot 的数据。
两种情况:默认的 slot 和 命名的 slot。
4.1 Default Scoped Slot
4.2 Named Scope Slot
// @file MyComponent -- producer
<slot name="header" message="hello"></slot>
// name is a reserved, so not passed.
// consumer
<MyComponent>
<template #header="headerProps">
{{ headerProps }}
</template>
<template #default="defaultProps">
{{ defaultProps }}
</template>
<template #footer="footerProps">
{{ footerProps }}
</template>
</MyComponent>