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
  • onlinewindow.navigator.onLineThe 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 changed
  • immutable={false}– Default value. Svelte is more conservative about whether mutable objects have changed
  • accessors={true}– Add a getter and setter for a component’s Prop
  • accessors={false}– the default value
  • namespace="..."– 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

in the application component. Replace

with

:

<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