参考:Vue 插槽(slot)使用(通俗易懂) - 掘金 (juejin.cn)
组件子级 / Slot 属性 • Svelte 教程 | Svelte 中文网
组件可以像元素一样拥有子内容,就像元素一样,使用<slot>元素可以在子组件中公开内容,该元素可以包含在未提供的子组件时渲染的后备内容,就是组件在接受子组件之前,要知道把它们放在哪里
Slot
<slot><!-- optional fallback --></slot>
<slot name="x"><!-- optional fallback --></slot>
<slot prop={value} />
实例运用:
App.svelte
<script>
import Box from './Box.svelte';
</script>
<Box>
<h2>Hello!</h2>
<p>This is a box. It can contain anything.</p>
</Box>
Bos.svelte
<style>
.box {
width: 300px;
border: 1px solid #aaa;
border-radius: 2px;
box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
padding: 1em;
margin: 0 0 1em 0;
}
</style>
<div class="box">
<slot></slot>
</div>
Box.svelte定义了Box组件的信息,并且预留了slot,就相当于一个空间吧,用来告诉其他组件,插入的内容放在哪里
App.svelte就引入Box作为标签,那其实就相当于下面的代码,只不过说把h2和p标签放在了其他的svelte文件中
<div class="box">
<h2>Hello!</h2>
<p>This is a box. It can contain anything.</p>
</div>
Slot fallbacks
组件中可以没有任何子项,用<em>标签来进行初始化(或者说显示提示内容
在上面的Box上进行修改
Box.svelte
<style>
.box {
width: 300px;
border: 1px solid #aaa;
border-radius: 2px;
box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
padding: 1em;
margin: 0 0 1em 0;
}
</style>
<div class="box">
<slot>
<em>no content was provided</em>
</slot>
</div>
App.svelte
<script>
import Box from './Box.svelte';
</script>
<Box>
<h2>Hello!</h2>
<p>This is a box. It can contain anything.</p>
</Box>
<Box>
</Box>
<Box/>
这里<Box></Box>和<Box/>显示出来的内容是一样的,因为它们里面都是没有内容的
Slot的name属性
有时候我们不一定只用了一个slot标签,对吧,那这时候就要对每一个slot标签来进行区分
App.svelte
<script>
import ContactCard from './ContactCard.svelte';
</script>
<ContactCard>
<span slot="name">
P. Sherman
</span>
<span slot="address">
42 Wallaby Way<br>
Sydney
</span>
</ContactCard>
ContactCard.svelte
<style>
.contact-card {
width: 300px;
border: 1px solid #aaa;
border-radius: 2px;
box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
padding: 1em;
}
h2 {
padding: 0 0 0.2em 0;
margin: 0 0 1em 0;
border-bottom: 1px solid #ff3e00
}
.address, .email {
padding: 0 0 0 1.5em;
background: 0 0 no-repeat;
background-size: 20px 20px;
margin: 0 0 0.5em 0;
line-height: 1.2;
}
.address { background-image: url(tutorial/icons/map-marker.svg) }
.email { background-image: url(tutorial/icons/email.svg) }
.missing { color: #999 }
</style>
<article class="contact-card">
<h2>
<slot name="name">
<span class="missing">Unknown name</span>
</slot>
</h2>
<div class="address">
<slot name="address">
<span class="missing">Unknown address</span>
</slot>
</div>
<div class="email">
<slot name="email">
<span class="missing">Unknown email</span>
</slot>
</div>
</article>
Slot 内容检查
在某些情况下,可能希望根据父级是否传入特定插槽的内容来控制组件的各个部分。也许在该插槽周围有一个包装器,如果插槽为空,则不想渲染它。或者,也许只想在插槽存在时才申请课程。可以通过检查特殊变量的属性来执行此操作。
$$slots是一个对象,其键是父组件传入的插槽的名称。如果父级将插槽留空,则不会有该插槽的条目。
下面的例子是希望用于确保仅在父级传入插槽内容时才呈现这些元素
App.svelte
<script>
import Project from './Project.svelte'
import Comment from './Comment.svelte'
</script>
<style>
h1 {
font-weight: 300;
margin: 0 1rem;
}
ul {
list-style: none;
padding: 0;
margin: 0.5rem;
display: flex;
}
@media (max-width: 600px) {
ul {
flex-direction: column;
}
}
li {
padding: 0.5rem;
flex: 1 1 50%;
min-width: 200px;
}
</style>
<h1>
Projects
</h1>
<ul>
<li>
<Project
title="Add Typescript support"
tasksCompleted={25}
totalTasks={57}
>
<div slot="comments">
<Comment name="Ecma Script" postedAt={new Date('2020-08-17T14:12:23')}>
<p>Those interface tests are now passing.</p>
</Comment>
</div>
</Project>
</li>
<li>
<Project
title="Update documentation"
tasksCompleted={18}
totalTasks={21}
/>
</li>
</ul>
Comment.svelte
<script>
export let name;
export let postedAt;
$: avatar = `https://ui-avatars.com/api/?name=${name.replace(/ /g, '+')}&rounded=true&background=ff3e00&color=fff&bold=true`;
</script>
<style>
article {
background-color: #fff;
border: 1px #ccc solid;
border-radius: 4px;
padding: 1rem;
}
.header {
align-items: center;
display: flex;
}
.details {
flex: 1 1 auto;
margin-left: 0.5rem
}
h4 {
margin: 0;
}
time {
color: #777;
font-size: 0.75rem;
text-decoration: underline;
}
.body {
margin-top: 0.5rem;
}
.body :global(p) {
margin: 0;
}
</style>
<article>
<div class="header">
<img src={avatar} alt="" height="32" width="32">
<div class="details">
<h4>{name}</h4>
<time datetime={postedAt.toISOString()}>{postedAt.toLocaleDateString()}</time>
</div>
</div>
<div class="body">
<slot></slot>
</div>
</article>
Project.svlte
<script>
export let title;
export let tasksCompleted = 0;
export let totalTasks = 0;
</script>
<style>
article {
border: 1px #ccc solid;
border-radius: 4px;
position: relative;
}
article > div {
padding: 1.25rem;
}
article.has-discussion::after {
content: '';
background-color: #ff3e00;
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
height: 20px;
position: absolute;
right: -10px;
top: -10px;
width: 20px;
}
h2,
h3 {
margin: 0 0 0.5rem;
}
h3 {
font-size: 0.875rem;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
}
p {
color: #777;
margin: 0;
}
.discussion {
background-color: #eee;
border-top: 1px #ccc solid;
}
</style>
<article class:has-discussion={$$slots.comments}>
<div>
<h2>{title}</h2>
<p>{tasksCompleted}/{totalTasks} tasks completed</p>
</div>
{#if $$slots.comments}
<div class="discussion">
<h3>Comments</h3>
<slot name="comments"></slot>
</div>
{/if}
</article>
现在,当插槽留空时,注释容器和通知点将不会呈现。
Slot属性
App.svelte
<script>
import Hoverable from './Hoverable.svelte';
</script>
<style>
div {
padding: 1em;
margin: 0 0 1em 0;
background-color: #eee;
}
.active {
background-color: #ff3e00;
color: white;
}
</style>
<Hoverable let:hovering={active}>
<div class:active>
{#if active}
<p>I am being hovered upon.</p>
{:else}
<p>Hover over me!</p>
{/if}
</div>
</Hoverable>
<Hoverable let:hovering={active}>
<div class:active>
{#if active}
<p>I am being hovered upon.</p>
{:else}
<p>Hover over me!</p>
{/if}
</div>
</Hoverable>
<Hoverable let:hovering={active}>
<div class:active>
{#if active}
<p>I am being hovered upon.</p>
{:else}
<p>Hover over me!</p>
{/if}
</div>
</Hoverable>
Hoverable.svelte
<script>
let hovering;
function enter() {
hovering = true;
}
function leave() {
hovering = false;
}
</script>
<div on:mouseenter={enter} on:mouseleave={leave}>
<slot hovering={hovering}></slot>
</div>
在上面的程序中,有一个名为 <Hoverable>
的组件来跟踪鼠标是否放在上面,它需要将数据传回父组件,以便我们可以渲染插入的内容
为此,我们使用 *插槽属性(slot props)*。将Hoverable.svelte
的hovering
的值传递给它的slot
命名插槽也拥有有属性,但是
let
指令需要写在slot="..."
标签上而不是组件上。