This is the NTH day of my participation in the August More Text Challenge. For details, see:August is more challenging
<svelte:self>
Svelte provides a variety of built-in elements. The first is
, which allows components to contain themselves recursively.
It is useful for things like a folder tree view, where folders can contain other folders. In Folder.svelte, we want to be able to do this:
{#if file.files}
<Folder {. file} / >
{:else}
<File {. file} / >
{/if}
Copy the code
But this is not possible because modules cannot import themselves. Instead, we use
.
{#if file.files}
<svelte:self {. file} / >
{:else}
<File {. file} / >
{/if}
Copy the code
Complete code:
File. Svelte:
<script>
export let name;
$: type = name.slice(name.lastIndexOf('. ') + 1);
</script>
<span style="background-image: url(tutorial/icons/{type}.svg)">{name}</span>
<style>
span {
padding: 0 0 0 1.5 em;
background: 0 0.1 em no-repeat;
background-size: 1em 1em;
}
</style>
Copy the code
Folder. Svelte:
<script>
import File from './File.svelte';
export let expanded = false;
export let name;
export let files;
function toggle() { expanded = ! expanded; }</script>
<span class:expanded on:click={toggle}>{name}</span>
{#if expanded}
<ul>
{#each files as file}
<li>
{#if file.files}
<svelte:self {. file} / >
{:else}
<File {. file} / >
{/if}
</li>
{/each}
</ul>
{/if}
<style>
span {
padding: 0 0 0 1.5 em;
background: url(tutorial/icons/folder.svg) 0 0.1 em no-repeat;
background-size: 1em 1em;
font-weight: bold;
cursor: pointer;
}
.expanded {
background-image: url(tutorial/icons/folder-open.svg);
}
ul {
padding: 0.2 em 0 0 0.5 em;
margin: 0 0 0 0.5 em;
list-style: none;
border-left: 1px solid #eee;
}
li {
padding: 0.2 em 0;
}
</style>
Copy the code
App. Svelte:
<script>
import Folder from './Folder.svelte';
let root = [
{
name: 'Important work stuff'.files: [{name: 'quarterly-results.xlsx'}]}, {name: 'Animal GIFs'.files: [{name: 'Dogs'.files: [{name: 'treadmill.gif' },
{ name: 'rope-jumping.gif'}]}, {name: 'Goats'.files: [{name: 'parkour.gif' },
{ name: 'rampage.gif'}]}, {name: 'cat-roomba.gif' },
{ name: 'duck-shuffle.gif' },
{ name: 'monkey-on-a-pig.gif'}]}, {name: 'TODO.md'}];</script>
<Folder name="Home" files={root} expanded/>
Copy the code
Examples have a lot of knowledge, you can go to the official experience: svelte-self
<svelte:component>
Dynamically load components using
. Instead of a series of if blocks:
{#if selected.color === 'red'}
<RedThing/>
{:else if selected.color === 'green'}
<GreenThing/>
{:else if selected.color === 'blue'}
<BlueThing/>
{/if}
Copy the code
We can use a separate dynamic component:
<svelte:component this={selected.component}/>
Copy the code
The this value can be any component constructor, or it can be a false value. If it is false, no component will be rendered.
The original code:
RedThing.svelte
<strong>Red thing</strong>
<style>
strong {
color: red;
}
</style>
Copy the code
GreenThing.svelte
<strong>Green thing</strong>
<style>
strong {
color: green;
}
</style>
Copy the code
BlueThing.svelte
<strong>Blue thing</strong>
<style>
strong {
color: blue;
}
</style>
Copy the code
App.svelte
<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}/>
Copy the code
Check out svelte component
<svelte:window>
Just as you can add event listeners to any DOM element, you can also use
to add event listeners to window objects.
<script>
let key;
let keyCode;
function handleKeydown(event) {
key = event.key;
keyCode = event.keyCode;
}
</script>
<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>
<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.2 em 0.5 em;
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>
Copy the code
As with the DOM element, you can add the event modifier, such as preventDefault.
We can also bind to certain properties of the window, such as scrollY.
<svelte:window bind:scrollY={y}/>
Copy the code
The list of properties to which you can bind is as follows:
innerWidth
innerHeight
outerWidth
outerHeight
scrollX
scrollY
online
—window.navigator.onLine
The alias
All files except scrollX and scrollY are read-only.
Complete code:
<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 layers 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.5 em 0.5 em 0.5 em;
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;
background-color: rgb(253.174.51);
}
</style>
Copy the code
You can go to the website: Svelte – Window
<svelte:body>
Like
, the
element allows you to listen for events fired on document.body. This is useful for mouseEnter and Mouseleave events, which do not fire on the window.
Add mouseEnter and mouseleave handlers to the
tag:
<svelte:body
on:mouseenter={handleMouseenter}
on:mouseleave={handleMouseleave}
/>
Copy the code
Complete code:
<script>
let hereKitty = false;
const handleMouseenter = () = > hereKitty = true;
const handleMouseleave = () = > hereKitty = false;
</script>
<svelte:body
on:mouseenter={handleMouseenter}
on:mouseleave={handleMouseleave}
/>
<! -- creative commons BY-NC http://www.pngall.com/kitten-png/download/7247 -->
<img
class:curious={hereKitty}
alt="Kitten wants to know what's going on"
src="tutorial/kitten.png"
>
<style>
img {
position: absolute;
left: 0;
bottom: -60px;
transform: translate(-80%.0) rotate(-30deg);
transform-origin: 100% 100%;
transition: transform 0.4 s;
}
.curious {
transform: translate(-15%.0) rotate(0deg);
}
:global(body) {
overflow: hidden;
}
</style>
Copy the code
Experience site: Svelte – Body
<svelte:head>
The
element allows you to insert elements in the of the document:
<svelte:head>
<link rel="stylesheet" href="tutorial/dark-theme.css">
</svelte:head>
Copy the code
In server-side rendering (SSR) mode, the content of
is returned separately from the rest of the HTML.
Complete code:
<svelte:head>
<link rel="stylesheet" href="tutorial/dark-theme.css">
</svelte:head>
<h1>Hello world!</h1>
Copy the code
Experience site: Svelte – Head
<svelte:options>
The
element allows you to specify compiler options.
We will use the immutable option as an example. In this application, the
component flashes when it receives new data. Click one of the items to toggle its completed state by creating an updated Todos array. This causes the other
items to flicker, even if they don’t end up making any changes to the DOM.
We can optimize this by telling the
component to expect immutable data. This means that we promise never to change the Todo Prop, but to create a new Todo object when the situation changes.
Add the following to the top of the todo.svelte file:
<svelte:options immutable={true}/>
Copy the code
If you wish, you can shorten it to
.
Now, when you toggle TODO by clicking TODO, only the updated components will blink.
Options that can be set here are:
immutable={true}
– You never use mutable data, so the compiler can perform a simple reference equality check to determine if the value has changedimmutable={false}
– Default value. Svelte is more conservative about whether mutable objects have changedaccessors={true}
– Add a getter and setter for a component’s Propaccessors={false}
– the default valuenamespace="..."
– This component’s namespace will be used, most commonly “SVG”tag="..."
– The name used to compile this component into a custom element
For more information about these options, see API References.
Complete code:
<script>
import Todo from './Todo.svelte';
let todos = [
{ id: 1.done: true.text: 'wash the car' },
{ id: 2.done: false.text: 'take the dog for a walk' },
{ id: 3.done: false.text: 'mow the lawn'}];function toggle(toggled) {
todos = todos.map(todo= > {
if (todo === toggled) {
// return a new object
return {
id: todo.id,
text: todo.text,
done: !todo.done
};
}
// return the same object
return todo;
});
}
</script>
<h2>Todos</h2>
{#each todos as todo}
<Todo {todo} on:click={()= > toggle(todo)}/>
{/each}
Copy the code
Site: svelte-options
<svelte:fragment>
The
element allows you to place content in named slots instead of wrapping it in a container DOM element. This will keep the flow layout of the document intact.
In this example, notice how we applied a flex layout spaced 1em to cuboids.
<! -- Box.svelte -->
<div class="box">
<slot name="header">No header was provided</slot>
<p>Some content between header and footer</p>
<slot name="footer"></slot>
</div>
<style>
.box {
display: flex;
flex-direction: column;
gap: 1em;
}
</style>
Copy the code
However, the content in the footer is not separated by this rule, because wrapping it in a div creates a new flow layout.
We can solve this problem by changing the
:
<svelte:fragment slot="footer">
<p>All rights reserved.</p>
<p>Copyright (c) 2019 Svelte Industries</p>
</svelte:fragment>
Copy the code
Complete code:
<! -- Box.svelte -->
<div class="box">
<slot name="header">No header was provided</slot>
<p>Some content between header and footer</p>
<slot name="footer"></slot>
</div>
<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;
display: flex;
flex-direction: column;
gap: 1em;
}
</style>
Copy the code
<! -- App.svelte -->
<script>
import Box from './Box.svelte'
</script>
<Box>
<svelte:fragment slot="footer">
<p>All rights reserved.</p>
<p>Copyright (c) 2019 Svelte Industries</p>
</svelte:fragment>
</Box>
Copy the code
Official website Address: Svelte-fragment