[Svelte] Svelte Element
Svelte has some useful elements.
Let's take a look at it.
<svelte:self>
This element allows a component to include itself, recursively.
This element is useful in cases such as tree traverse.
<script lang="ts">
import Self from '../components/Self.svelte';
const objs = {
name: 'HoYa',
children: [
{ name: 'Park', children: [{ name: 'Choi' }, { name: 'Hwang' }] },
{ name: 'Lee', children: [{ name: 'Kim' }, { name: 'Hong' }] }
]
};
</script>
<Self {objs} />
I created an object with a repeated structure and passed using props.
<!-- components/Self.svelte -->
<script lang="ts">
export let objs;
</script>
<ul>
<li>
{objs.name}
{#if objs.children}
{#each objs.children as objs}
<svelte:self {objs} />
{/each}
{/if}
</li>
</ul>
<svelte:self {objs} /> is the same as <Self {objs} />.
<svelte:component>
This element renders a component dynamically, using the component constructor specified as the this property.
<svelte:component this={expression} />
The syntax is the above.
<!-- components/Component.svelte -->
<script lang="ts">
import Test1 from './ComponentTest1.svelte';
import Test2 from './ComponentTest2.svelte';
let components = [
{ name: 'Test1', component: Test1 },
{ name: 'Test2', component: Test2 }
];
let selectedName;
$: selected = components.find((c) => c.name === selectedName);
</script>
{#each components as { name } (name)}
<label>
<input type="radio" value={name} bind:group={selectedName} />
{name}
</label>
{/each}
{#if selected}
<svelte:component this={selected.component} />
{/if}
The Test1 and Test2 components are rendered automatically as follows the selected radio button.
We can pass the props as well.
<svelte:window>
This element allows you to add event listeners to the window object without worrying about removing than when the component is destroyed or checking for the existence of window when server-side rendering.
<svelte:window on:event={handler} />
<svelte:window bind:prop={value} />
The syntax is the above.
<!-- components/Window.svelte -->
<script lang="ts">
let key = '';
</script>
<svelte:window on:keydown={(e) => (key = e.key)} />
<h1>{key}</h1>
It is the same as these codes.
<svelte:window on:keydown={(e) => (key = e.key)} />
window.addEventListener('keydown', (event) => {
key = event.key;
});
You can also bind to these properties.
<!-- components/Window.svelte -->
<script lang="ts">
let innerWidth;
let innerHeight;
let outerWidth;
let outerHeight;
let scrollX;
let scrollY;
let online;
</script>
<svelte:window
bind:innerWidth
bind:innerHeight
bind:outerWidth
bind:outerHeight
bind:scrollX
bind:scrollY
bind:online
/>
<div>innerWidth: {innerWidth}</div>
<div>innerHeight: {innerHeight}</div>
<div>outerWidth: {outerWidth}</div>
<div>outerHeight: {outerHeight}</div>
<input type="number" bind:value={scrollX} />
<input type="number" bind:value={scrollY} />
<div>online: {online}</div>
<div class="scroll" />
<style>
.scroll {
height: 1000px;
}
</style>
All except scrollX and scrollY are readonly.
<svelte:body>
This element allows you to add listeners to events on document.body, such as mouseenter and mouseleave, which don't fire on window.
<svelte:body on:event={handler} />
The syntax is the above.
<!-- components/Body.svelte -->
<script lang="ts">
import BodyTest from './BodyTest.svelte';
let toggle = false;
</script>
{#if toggle}
<BodyTest />
{/if}
<button on:click={() => (toggle = !toggle)}>Toggle</button>
This component simply creates and destroys the BodyTest component.
<!-- components/BodyTest.svelte -->
<svelte:body on:mousemove={(e) => console.log(e.clientX, e.clientY)} />
<h1>Body Test</h1>
When this component is mounted, the mousemove event is activated.
<svelte:head>
This element makes it possible to insert elements into document.head.
<svelte:head>...</svelte:head>
The syntax is the above.
<!-- components/Head.svelte -->
<script lang="ts">
import HeadTest from './HeadTest.svelte';
let toggle = false;
</script>
{#if toggle}
<HeadTest />
{/if}
<button on:click={() => (toggle = !toggle)}>Toggle</button>
This is the same as the svelte:body case.
<svelte:head>
<link rel="stylesheet" href="./main.css" />
</svelte:head>
<h1>Head Test</h1>
If this component is mounted, the contents are added to the document.head.
/* static/main.css */
body {
background: royalblue;
}
Please test with the toggle button.
<svelte:options>
This element provides a place to specify per component compiler options.
<svelte:options options={value} />
The syntax is the above.
immutable
If props that is passed to a components is reassigned, components are updated.
Even if the same value is passed through props, components are updated.
<!-- components/Options.svelte -->
<script lang="ts">
import OptionsImmutable from './OptionsImmutable.svelte';
let fruits = [
{ id: 1, name: 'Apple' },
{ id: 2, name: 'Banana' },
{ id: 3, name: 'Cherry' }
];
</script>
{#each fruits as fruit (fruit.id)}<OptionsImmutable {fruit} />{/each}
<button
on:click={() => {
fruits[0] = { id: 1, name: 'Apple' };
fruits = fruits;
}}
>
Update
</button>
<!-- components/OptionsImmutable -->
<svelte:options immutable />
<script lang="ts">
import { afterUpdate } from 'svelte';
export let fruit;
let updateCount = 0;
afterUpdate(() => {
updateCount += 1;
});
</script>
<div>{fruit.name} ({updateCount})</div>
If one of the data in the fruits is updated, all OptionsImmutable components are updated.
immutable informs the components that it passes the components immutable props.
Therefore, if you use the immutable option, it updates only the component that has changed data by checking props using === operator.
accessors
This option adds getters and setters for the component's props.
<!-- components/OptionsAccessors.svelte -->
<svelte:options accessors />
<script lang="ts">
export let name = 'HoYa';
let age = 18;
export function getAge() {
console.log(age);
}
</script>
<h1 on:click={getAge}>{name}</h1>
This component has two props.
The accessors option makes it easy to use these props in the upper components.
<!-- components/Options.svelte -->
<script lang="ts">
import OptionsAccessors from './OptionsAccessors.svelte';
let accessors;
function getData() {
console.log(accessors);
console.log(accessors.name);
console.log(accessors.getAge());
}
</script>
<OptionsAccessors bind:this={accessors} />
<button on:click={getData}>Get Data</button>
It binds the child component and accesses the props through it.
<svelte:fragment>
This element allows you to place content in a named slot without wrapping it in a container DOM element.
<!-- components/FragmentTest.svelte -->
<div>
<slot name="header" />
<hr />
<slot name="content" />
<hr />
<slot name="footer" />
</div>
I made a component with the named slot.
<!-- components/Fragment.svelte -->
<script lang="ts">
import FragmentTest from './FragmentTest.svelte';
</script>
<FragmentTest>
<h1 slot="header">Header</h1>
<div slot="content">Content</div>
<svelte:fragment slot="footer">
<h4>Footer</h4>
<span>Copyright</span>
</svelte:fragment>
</FragmentTest>
It is similar to React's fragment.