mirror of https://github.com/sveltejs/svelte
docs: add documentation for $$slots (#5277)
parent
5d7ffdb8a7
commit
169fd8497c
@ -0,0 +1,57 @@
|
|||||||
|
<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>
|
@ -0,0 +1,56 @@
|
|||||||
|
<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>
|
@ -0,0 +1,62 @@
|
|||||||
|
<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={true}>
|
||||||
|
<div>
|
||||||
|
<h2>{title}</h2>
|
||||||
|
<p>{tasksCompleted}/{totalTasks} tasks completed</p>
|
||||||
|
</div>
|
||||||
|
<div class="discussion">
|
||||||
|
<h3>Comments</h3>
|
||||||
|
<slot name="comments"></slot>
|
||||||
|
</div>
|
||||||
|
</article>
|
@ -0,0 +1,57 @@
|
|||||||
|
<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>
|
@ -0,0 +1,56 @@
|
|||||||
|
<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>
|
@ -0,0 +1,64 @@
|
|||||||
|
<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>
|
@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
title: Checking for slot content
|
||||||
|
---
|
||||||
|
|
||||||
|
In some cases, you may want to control parts of your component based on whether the parent passes in content for a certain slot. Perhaps you have a wrapper around that slot, and you don't want to render it if the slot is empty. Or perhaps you'd like to apply a class only if the slot is present. You can do this by checking the properties of the special `$$slots` variable.
|
||||||
|
|
||||||
|
`$$slots` is an object whose keys are the names of the slots passed in by the parent component. If the parent leaves a slot empty, then `$$slots` will not have an entry for that slot.
|
||||||
|
|
||||||
|
Notice that both instances of `<Project>` in this example render a container for comments and a notification dot, even though only one has comments. We want to use `$$slots` to make sure we only render these elements when the parent `<App>` passes in content for the `comments` slot.
|
||||||
|
|
||||||
|
In `Project.svelte`, update the `class:has-discussion` directive on the `<article>`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<article class:has-discussion={$$slots.comments}>
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, wrap the `comments` slot and its wrapping `<div>` in an `if` block that checks `$$slots`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
{#if $$slots.comments}
|
||||||
|
<div class="discussion">
|
||||||
|
<h3>Comments</h3>
|
||||||
|
<slot name="comments"></slot>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now the comments container and the notification dot won't render when `<App>` leaves the `comments` slot empty.
|
Loading…
Reference in new issue