chapters on <svelte:component> and <svelte:window>

pull/2179/head
Richard Harris 7 years ago
parent 37480a9331
commit 3e7eafe9de

@ -0,0 +1,27 @@
<script>
import RedThing from './RedThing.svelte';
import GreenThing from './GreenThing.svelte';
import BlueThing from './BlueThing.svelte';
const options = [
{ color: 'red', component: RedThing },
{ color: 'green', component: GreenThing },
{ color: 'blue', component: BlueThing },
];
let selected = options[0];
</script>
<select bind:value={selected}>
{#each options as option}
<option value={option}>{option.color}</option>
{/each}
</select>
{#if selected.color === 'red'}
<RedThing/>
{:else if selected.color === 'green'}
<GreenThing/>
{:else if selected.color === 'blue'}
<BlueThing/>
{/if}

@ -0,0 +1,5 @@
<style>
strong { color: blue; }
</style>
<strong>blue thing</strong>

@ -0,0 +1,5 @@
<style>
strong { color: green; }
</style>
<strong>green thing</strong>

@ -0,0 +1,5 @@
<style>
strong { color: red; }
</style>
<strong>red thing</strong>

@ -0,0 +1,21 @@
<script>
import RedThing from './RedThing.svelte';
import GreenThing from './GreenThing.svelte';
import BlueThing from './BlueThing.svelte';
const options = [
{ color: 'red', component: RedThing },
{ color: 'green', component: GreenThing },
{ color: 'blue', component: BlueThing },
];
let selected = options[0];
</script>
<select bind:value={selected}>
{#each options as option}
<option value={option}>{option.color}</option>
{/each}
</select>
<svelte:component this={selected.component}/>

@ -0,0 +1,5 @@
<style>
strong { color: blue; }
</style>
<strong>blue thing</strong>

@ -0,0 +1,5 @@
<style>
strong { color: green; }
</style>
<strong>green thing</strong>

@ -0,0 +1,5 @@
<style>
strong { color: red; }
</style>
<strong>red thing</strong>

@ -0,0 +1,23 @@
---
title: <svelte:component>
---
A component can change its category altogether with `<svelte:component>`. Instead of a sequence of `if` blocks...
```html
{#if selected.color === 'red'}
<RedThing/>
{:else if selected.color === 'green'}
<GreenThing/>
{:else if selected.color === 'blue'}
<BlueThing/>
{/if}
```
...we can have a single dynamic component:
```html
<svelte:component this={selected.component}/>
```
The `this` value can be any component constructor, or a falsy value — if it's falsy, no component is rendered.

@ -0,0 +1,42 @@
<script>
let key;
let keyCode;
function handleKeydown(event) {
key = event.key;
keyCode = event.keyCode;
}
</script>
<style>
div {
display: flex;
height: 100%;
align-items: center;
justify-content: center;
flex-direction: column;
}
kbd {
background-color: #eee;
border-radius: 4px;
font-size: 6em;
padding: 0.2em 0.5em;
border-top: 5px solid rgba(255,255,255,0.5);
border-left: 5px solid rgba(255,255,255,0.5);
border-right: 5px solid rgba(0,0,0,0.2);
border-bottom: 5px solid rgba(0,0,0,0.2);
color: #555;
}
</style>
<svelte:window/>
<div style="text-align: center">
{#if key}
<kbd>{key === ' ' ? 'Space' : key}</kbd>
<p>{keyCode}</p>
{:else}
<p>Focus this window and press any key</p>
{/if}
</div>

@ -0,0 +1,42 @@
<script>
let key;
let keyCode;
function handleKeydown(event) {
key = event.key;
keyCode = event.keyCode;
}
</script>
<style>
div {
display: flex;
height: 100%;
align-items: center;
justify-content: center;
flex-direction: column;
}
kbd {
background-color: #eee;
border-radius: 4px;
font-size: 6em;
padding: 0.2em 0.5em;
border-top: 5px solid rgba(255,255,255,0.5);
border-left: 5px solid rgba(255,255,255,0.5);
border-right: 5px solid rgba(0,0,0,0.2);
border-bottom: 5px solid rgba(0,0,0,0.2);
color: #555;
}
</style>
<svelte:window on:keydown={handleKeydown}/>
<div style="text-align: center">
{#if key}
<kbd>{key === ' ' ? 'Space' : key}</kbd>
<p>{keyCode}</p>
{:else}
<p>Focus this window and press any key</p>
{/if}
</div>

@ -0,0 +1,11 @@
---
title: <svelte:window>
---
Just as you can add event listeners to any DOM element, you can add event listeners to the `window` object with `<svelte:window>`.
On line 33, add the `keydown` listener:
```html
<svelte:window on:keydown={handleKeydown}/>
```

@ -0,0 +1,84 @@
<script>
const layers = [0, 1, 2, 3, 4, 5, 6, 7, 8];
let y;
</script>
<svelte:window/>
<a class="parallax-container" href="https://www.firewatchgame.com">
{#each [0, 1, 2, 3, 4, 5, 6, 7, 8] as layer}
<img
style="transform: translate(0,{-y * layer / (layers.length - 1)}px)"
src="https://www.firewatchgame.com/images/parallax/parallax{layer}.png"
alt="parallax layer {layer}"
>
{/each}
</a>
<div class="text">
<span style="opacity: {1 - Math.max(0, y / 40)}">
scroll down
</span>
<div class="foreground">
You have scrolled {y} pixels
</div>
</div>
<style>
.parallax-container {
position: fixed;
width: 2400px;
height: 712px;
left: 50%;
transform: translate(-50%,0);
}
.parallax-container img {
position: absolute;
top: 0;
left: 0;
width: 100%;
will-change: transform;
}
.parallax-container img:last-child::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: rgb(45,10,13);
}
.text {
position: relative;
width: 100%;
height: 300vh;
color: rgb(220,113,43);
text-align: center;
padding: 4em 0.5em 0.5em 0.5em;
box-sizing: border-box;
pointer-events: none;
}
span {
display: block;
font-size: 1em;
text-transform: uppercase;
will-change: transform, opacity;
}
.foreground {
position: absolute;
top: 711px;
left: 0;
width: 100%;
height: calc(100% - 712px);
background-color: rgb(32,0,1);
color: white;
padding: 50vh 0 0 0;
}
:global(body) { margin: 0; padding: 0; }
</style>

@ -0,0 +1,84 @@
<script>
const layers = [0, 1, 2, 3, 4, 5, 6, 7, 8];
let y;
</script>
<svelte:window bind:scrollY={y}/>
<a class="parallax-container" href="https://www.firewatchgame.com">
{#each [0, 1, 2, 3, 4, 5, 6, 7, 8] as layer}
<img
style="transform: translate(0,{-y * layer / (layers.length - 1)}px)"
src="https://www.firewatchgame.com/images/parallax/parallax{layer}.png"
alt="parallax layer {layer}"
>
{/each}
</a>
<div class="text">
<span style="opacity: {1 - Math.max(0, y / 40)}">
scroll down
</span>
<div class="foreground">
You have scrolled {y} pixels
</div>
</div>
<style>
.parallax-container {
position: fixed;
width: 2400px;
height: 712px;
left: 50%;
transform: translate(-50%,0);
}
.parallax-container img {
position: absolute;
top: 0;
left: 0;
width: 100%;
will-change: transform;
}
.parallax-container img:last-child::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: rgb(45,10,13);
}
.text {
position: relative;
width: 100%;
height: 300vh;
color: rgb(220,113,43);
text-align: center;
padding: 4em 0.5em 0.5em 0.5em;
box-sizing: border-box;
pointer-events: none;
}
span {
display: block;
font-size: 1em;
text-transform: uppercase;
will-change: transform, opacity;
}
.foreground {
position: absolute;
top: 711px;
left: 0;
width: 100%;
height: calc(100% - 712px);
background-color: rgb(32,0,1);
color: white;
padding: 50vh 0 0 0;
}
:global(body) { margin: 0; padding: 0; }
</style>

@ -0,0 +1,21 @@
---
title: <svelte:window> bindings
---
We can also bind to certain properties of `window`, such as `scrollY`. Update line 7:
```html
<svelte:window bind:scrollY={y}/>
```
The list of properties you can bind to is as follows:
* `innerWidth`
* `innerHeight`
* `outerWidth`
* `outerHeight`
* `scrollX`
* `scrollY`
* `online` — an alias for `window.navigator.onLine`
All except `scrollX` and `scrollY` are readonly.

@ -144,9 +144,9 @@ Maybe lifecycle should go first, since we're using `onMount` in the `this` demo?
## Special elements ## Special elements
* [ ] `<svelte:self>` * [x] `<svelte:self>`
* [ ] `<svelte:component>` * [x] `<svelte:component>`
* [ ] `<svelte:window>` * [x] `<svelte:window>`
* [ ] `<svelte:body>` * [ ] `<svelte:body>`
* [ ] `<svelte:head>` * [ ] `<svelte:head>`

Loading…
Cancel
Save