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