Skip to content

Latest commit

 

History

History
1763 lines (1271 loc) · 59.3 KB

03-template-syntax.md

File metadata and controls

1763 lines (1271 loc) · 59.3 KB

Синтаксис шаблонов


Теги


Тег в нижнем регистре, например <div> — это обычный HTML элемент. Тег, написанный с большой буквы, такой как <Widget> или <Namespace.Widget>, обозначает компонент.

<script>
	import Widget from './Widget.svelte';
</script>

<div>
	<Widget/>
</div>

Атрибуты и свойства


По умолчанию атрибуты работают точно так же, как их HTML-аналоги.

<div class="foo">
	<button disabled>ненажимаемая кнопка</button>
</div>

Как и в HTML, значения могут быть указаны без кавычек.

<input type=checkbox>

Значения атрибута могут содержать выражения JavaScript.

<a href="page/{p}">страница {p}</a>

Или они целиком могут быть выражениями JavaScript.

<button disabled={!clickable}>...</button>

Булевые атрибуты присоединяются к элементу, если их значения истинное и убираются с него, когда значения являются ложными.

Все остальные атрибуты будут присоединены к элементу, только если их значение не является null-образным (null или undefined).

<input required={false} placeholder="Это поле ввода не является обязательным">
<div title={null}>У этого контейнера нет атрибута title</div>

Выражение может содержать символы, которые могут вызвать проблемы при подсветке синтаксиса в обычном HTML, поэтому допускается использование значения в кавычках. Кавычки не влияют на то, как анализируется значение:

<button disabled="{number !== 42}">...</button>

Когда имя и значение атрибута совпадают (name = {name}) — их можно заменить на {name}.

<!-- Эти строки эквивалентны -->
<button disabled={disabled}>...</button>
<button {disabled}>...</button>

Значения, передаваемые в компоненты, называются свойствами или пропсами, но не атрибутами, поскольку они не относятся к DOM.

Как и в DOM-элементах, name={name} можно заменить сокращением {name}.

<Widget foo={bar} answer={42} text="hello"/>

Развёртка атрибутов позволяет передать компоненту сразу несколько атрибутов или свойств.

Элемент или компонент может иметь сразу несколько таких развёрток вперемешку с обычными атрибутами.

<Widget {...things}/>

Объект $$props содержит в себе все свойства передаваемые компоненту, включая и те, которые не объявлены с помощью оператора export. В редких случаях использование этого объекта может быть полезным, но в целом не рекомендуется его использовать, поскольку это вызовет определённые трудности у Svelte при оптимизации приложения.

<Widget {...$$props}/>

Объект $$restProps содержит в себе только те переданные свойства, которые не были объявлены при помощи оператора export. Он может быть использован для передачи заранее неизвестных атрибутов какому-либо элементу внутри компонента.

<input {...$$restProps}>

Атрибут value у элемента input, а также дочерние элементы option не могут быть установлены развёрткой атрибутов когда используются привязки bind:group или bind:checked. В такой ситуации Svelte необходимо видеть значения атрибутов value непосредственно в шаблоне, чтобы связать его с соответствующей переменной.


Текстовые выражения

{выражение}

Текст также может содержать JavaScript-выражения:

<h1>Привет, {name}!</h1>
<p>{a} + {b} = {a + b}.</p>

<div>{(/^[A-Za-z ]+$/).test(value) ? x : y}</div>

Комментарии


Вы можете использовать внутри компонентов обычные HTML-комментарии.

<!-- это комментарий! -->
<h1>Привет мир</h1>

Комментарии, которые начинаются со svelte-ignore, отключают определённые предупреждения для следующего за ним блока разметки. Обычно это используется для предупреждения о доступности — убедитесь, что вы отключаете их по уважительной причине.

<!-- svelte-ignore a11y-autofocus -->
<input bind:value={name} autofocus>

{#if ...}

{#if выражение}...{/if}
{#if выражение}...{:else if выражение}...{/if}
{#if выражение}...{:else}...{/if}

Для отображения содержимого при выполнении какого-либо условия, нужно добавить его в блок if.

{#if answer === 42}
	<p>а какой был вопрос?</p>
{/if}

Дополнительные условия могут быть добавлены с помощью {:else if выражение}, а блок альтернативной разметки помещен после {:else}.

{#if porridge.temperature > 35}
	<p>слишком горячая!</p>
{:else if 25 > porridge.temperature}
	<p>слишком холодная!</p>
{:else}
	<p>то, что надо!</p>
{/if}

{#each ...}

{#each выражение as имя}...{/each}
{#each выражение as имя, индекс}...{/each}
{#each выражение as имя (ключ)}...{/each}
{#each выражение as имя, индекс (ключ)}...{/each}
{#each выражение as имя}...{:else}...{/each}

Перебор списков значений может быть выполнен блоком each.

<h1>Список покупок</h1>
<ul>
	{#each items as item}
		<li>{item.name} x {item.qty}</li>
	{/each}
</ul>

Можно выполнять перебор по массиву или массивоподобному значению, т.е. по любому объекту, у которого есть свойство length.


Блок each также может отдавать индекс элемента, аналогично второму аргументу callback-функции в array.map(...):

{#each items as item, i}
	<li>{i + 1}: {item.name} x {item.qty}</li>
{/each}

Если указать параметр ключ, который однозначно идентифицирует каждый элемент списка, то при изменении данных Svelte будет использовать его для изменения списка в нужном месте, а не просто удалять и добавлять элементы в конец массива. Ключом может быть любой объект, но рекомендуется использовать строки и числа, поскольку они позволяют сохранять уникальность при изменении самих объектов.

{#each items as item, i (item.id)}
	<li>{i + 1}: {item.name} x {item.qty}</li>
{/each}

При желании в блоках each можно использовать деструктуризацию и развёртку:

{#each items as { id, name, qty }, i (id)}
	<li>{i + 1}: {name} x {qty}</li>
{/each}

{#each objects as { id, ...rest }}
	<li><span>{id}</span><MyComponent {...rest}/></li>
{/each}

{#each items as [id, ...rest]}
	<li><span>{id}</span><MyComponent values={rest}/></li>
{/each}

Блок each тоже может иметь блок {:else}, который будет отрисовываться, если переданный список окажется пустым.

{#each todos as todo}
	<p>{todo.text}</p>
{:else}
	<p>Нет задач!</p>
{/each}

{#await ...}

{#await выражение}...{:then имя}...{:catch имя}...{/await}
{#await выражение}...{:then имя}...{/await}
{#await выражение then имя}...{/await}
{#await выражение catch имя}...{/await}

Блоки await позволяют обрабатывать три возможных состояния промисов — ожидание, выполнение или отклонение. В режиме SSR на сервере будет отображаться только состояние ожидания.

{#await promise}
	<!-- промис в состоянии ожидания -->
	<p>Ждём пока промис выполнится...</p>
{:then value}
	<!-- промис выполнился -->
	<p>Значение равно {value}</p>
{:catch error}
	<!-- промис отклонён -->
	<p>Что-то пошло не так: {error.message}</p>
{/await}

Блок catch может быть опущен, если не нужно ничего отрисовывать, при отклонении промиса (или это вообще невозможно).

{#await promise}
	<!-- промис в состоянии ожидания -->
	<p>Ждём пока промис выполнится...</p>
{:then value}
	<!-- промис выполнился -->
	<p>Значение равно {value}</p>
{/await}

Если состояние ожидания промиса не требует информирования, можно также опустить и первый блок.

{#await promise then value}
	<p>Значение равно {value}</p>
{/await}

Аналогично, если нужно показать только ошибку, можно опустить блок then.

{#await promise catch error}
	<p>Произошла ошибка: {error}</p>
{/await}

{#key ...}

{#key выражение}...{/key}

Блок key уничтожает и пересоздаёт свое содержимое всякий раз, когда значение выражения меняется.


Он полезен когда, вам нужно проиграть какой-либо переход при изменении значения переменной.

{#key value}
	<div transition:fade>{value}</div>
{/key}

Когда внутри помещаются компоненты, они будут пересозданы заново.

{#key value}
	<Component />
{/key}

{@html ...}

{@html выражение}

В текстовых выражениях, символы вроде < и > экранируются, а в HTML выражениях — нет.

Выражение должно быть самодостаточной и валидной HTML-разметкой — {@html "<div>"}содержимое{@html "</div>"} не сработает, поскольку </div> не является валидной HTML-разметкой, и не скомпилирует код Svelte.

Svelte не очищает HTML код перед его обработкой! Если данные приходят из ненадёжного источника, необходимо их проверить. В противном случае, вы подвергаете пользователей возможным XSS-атакам.

<div class="blog-post">
	<h1>{post.title}</h1>
	{@html post.content}
</div>

{@debug ...}

{@debug}
{@debug переменная1, переменная2, ..., переменнаяN}

Тег {@debug ...} — это альтернатива для функции console.log (...). Он отображает значение указанных переменных при их изменении, и приостанавливает дальнейшее выполнение кода при открытых инструментах разработчика в браузере.

<script>
	let user = {
		firstname: 'Ада',
		lastname: 'Лавлейс'
	};
</script>

{@debug user}

<h1>Привет {user.firstname}!</h1>

{@debug ...} принимает разделенный запятыми список имён переменных (не любых выражений).

<!-- Успешно скомпилируется -->
{@debug user}
{@debug user1, user2, user3}

<!-- НЕ скомпилируется -->
{@debug user.firstname}
{@debug myArray[0]}
{@debug !isReady}
{@debug typeof user === 'object'}

Тег {@debug} без каких-либо аргументов установит оператор debugger, который будет срабатывать при любом изменении состояния.

{@const ...}

{@const assignment}

Тег {@const ...} определяет локальную константу.

<script>
	export let boxes;
</script>

{#each boxes as box}
	{@const area = box.width * box.height}
	{box.width} * {box.height} = {area}
{/each}

{@const} допускается только в качестве прямого дочернего элемента {#each}, {:then}, {:catch}, <Component /> или <svelte:fragment />.

Директивы элементов

Наряду с атрибутами у элементов могут быть и директивы, которые предоставляют некоторые дополнительные возможности.

on:событие

on:событие={обработчик}
on:событие|модификаторы={обработчик}

Используйте директиву on: для обработки событий в DOM.

<script>
	let count = 0;

	function handleClick(event) {
		count += 1;
	}
</script>

<button on:click={handleClick}>
	счётчик: {count}
</button>

Можно задать обработчики непосредственно на месте, без какой-либо потери производительности. Как и у атрибутов, значения директив могут быть заключены в кавычки для совместимости с подсветкой синтаксиса.

<button on:click="{() => count += 1}">
	счётчик: {count}
</button>

Модификаторы событий DOM добавляются после символа |.

<form on:submit|preventDefault={handleSubmit}>
	<!-- стандартная обработка события `submit` предотвращена,
	     поэтому страница не перезагрузится -->
</form>

Доступны следующие модификаторы:

  • preventDefault — вызывает event.preventDefault() перед запуском обработчика. Полезно, в том числе для обработки форм на клиентской стороне.
  • stopPropagation — вызывает event.stopPropagation(), предотвращает распространение события до следующих элементов.
  • passive — улучшает производительность прокрутки при тач-событиях или при прокрутке колёсиком мышки (Svelte добавит этот модификатор автоматически там, где это безопасно).
  • nonpassive — явно устанавливает passive: false
  • capture — вызывает событие в режиме capture вместо bubbling.
  • once — удаляет обработчик события после первого вызова.
  • self — обработчик сработает, только если в свойстве event.target находится сам элемент, на котором слушается событие
  • trusted — обработчик сработает, только если event.isTrusted имеет значение true. Т.е. если событие инициируется действием пользователя.

Модификаторы можно соединять в цепочку, например on:click|once|capture={...}.


Если директива on: используется без значения, то компонент будет пробрасывать событие. Таким образом можно обрабатывать события из глубоко вложенных компонентов.

<button on:click>
	Так событие клика по кнопке сможет выйти за пределы компонента
</button>

Можно назначить несколько обработчиков для одного события:

<script>
	let counter = 0;
	function increment() {
		counter = counter + 1;
	}
	function track(event) {
		trackEvent(event)
	}
</script>

<button on:click={increment} on:click={track}>Нажми меня!</button>

bind:свойство

bind:свойство={переменная}

Данные обычно передаются от родительского элемента к потомкам. Директива bind: позволяет передавать данные в другую сторону, от дочернего элемента в родительский. Большинство привязок соотносятся с конкретными элементами.

Простейшие привязки просто передают значение свойства элемента, например, input.value.

<input bind:value={name}>
<textarea bind:value={text}></textarea>

<input type="checkbox" bind:checked={yes}>

Если имя свойства и значения одинаковые, можно использовать сокращение.

<!-- Эти строки эквивалентны -->
<input bind:value={value}>
<input bind:value>

Значения из числовых input элементов автоматически приводятся к нужному типу. В структуре DOM значение свойства input.value таких элементов будет являться строкой, но Svelte будет рассматривать его как число. Если значение input пустое или недействительное (в случае type="number"), оно будет равно undefined.

<input type="number" bind:value={num}>
<input type="range" bind:value={num}>

На элементах <input>с атрибутом type="file" можно использовать привязку bind:files, чтобы получить список выбранных файлов в виде FileList только для чтения.

<label for="avatar">Загрузить картинку:</label>
<input
	accept="image/png, image/jpeg"
	bind:files
	id="avatar"
	name="avatar"
	type="file"
/>

bind: может быть использован вместе с директивой on:. Их порядок определяет значение связанной переменной при вызове обработчика событий.

<script>
	let value = 'Hello World';
</script>

<input
	on:input="{() => console.log('Old value:', value)}"
	bind:value
	on:input="{() => console.log('New value:', value)}"
/>
Привязка к значению <select>

Привязка значения <select> соответствует свойству value в выбранном <option>, которое может быть абсолютно любым значением, а не только строкой, как это обычно бывает в DOM.

<select bind:value={selected}>
	<option value={a}>a</option>
	<option value={b}>b</option>
	<option value={c}>c</option>
</select>

Элемент <select multiple> ведет себя аналогично группе чекбоксов.

<select multiple bind:value={fillings}>
	<option value="Rice">Rice</option>
	<option value="Beans">Beans</option>
	<option value="Cheese">Cheese</option>
	<option value="Guac (extra)">Guac (extra)</option>
</select>

Когда значение <option> соответствует его текстовому содержимому, атрибут может быть опущен.

<select multiple bind:value={fillings}>
	<option>Rice</option>
	<option>Beans</option>
	<option>Cheese</option>
	<option>Guac (extra)</option>
</select>

Элементы с атрибутом contenteditable поддерживают привязки к innerHTML и textContent.

<div contenteditable="true" bind:innerHTML={html}></div>

Элемент <details> поддерживает биндинг к атрибуту open.

<details bind:open={isOpen}>
	<summary>Details</summary>
	<p>
		Что-то достаточно маленькое, чтобы избежать случайного уведомления.
	</p>
</details>
Привязка к медиа-элементам

Медиа-элементы (<audio> и <video>) имеют свой собственный набор привязок — шесть только для чтения ...

  • duration (только для чтения) — общая продолжительность, в секундах
  • buffered (только для чтения) — буфер, массив объектов {start, end}
  • played (только для чтения) — уже проиграно, то же самое
  • seekable (только для чтения) — доступное для перемотки, то же самое
  • seeking (только для чтения) — выполняется ли перемотка
  • ended (только для чтения) — окончилось ли воспроизведение

... и пять двусторонних привязок:

  • currentTime — текущая позиция проигрывания, в секундах
  • playbackRate — скорость проигрывания видео, где 1 обозначает 'нормально'
  • paused — остановлено проигрывание или нет
  • volume — громкость, значение между 0 и 1
  • muted — логическое значение, указывающее приглушен ли звук

Для видео также доступны привязки для чтения ширины videoWidth и высоты videoHeight.

<video
		src={clip}
	bind:duration
	bind:buffered
	bind:seekable
	bind:seeking
	bind:played
	bind:ended
	bind:currentTime
	bind:paused
	bind:volume
	bind:videoWidth
	bind:videoHeight
></video>
Привязка к блочным элементам

У блочных элементов есть 4 привязки, доступных только для чтения. Они рассчитываются с использованием метода, аналогичного этому:

  • clientWidth
  • clientHeight
  • offsetWidth
  • offsetHeight
<div
	bind:offsetWidth={width}
	bind:offsetHeight={height}
>
	<Chart {width} {height}/>
</div>

bind:group

bind:group={переменная}

Элементы input, которые работают вместе, могут использовать привязку bind:group.

<script>
	let tortilla = 'Plain';
	let fillings = [];
</script>

<!-- сгруппированные радиокнопки являются взаимоисключающими -->
<input type="radio" bind:group={tortilla} value="Plain">
<input type="radio" bind:group={tortilla} value="Whole wheat">
<input type="radio" bind:group={tortilla} value="Spinach">

<!-- сгруппированные чекбоксы образуют массив своих значений -->
<input type="checkbox" bind:group={fillings} value="Rice">
<input type="checkbox" bind:group={fillings} value="Beans">
<input type="checkbox" bind:group={fillings} value="Cheese">
<input type="checkbox" bind:group={fillings} value="Guac (extra)">

bind:this

bind:this={DOM-узел}

Для получения ссылки на сам элемент в DOM, используйте bind:this.

<script>
	import { onMount } from 'svelte';

	let canvasElement;

	onMount(() => {
		const ctx = canvasElement.getContext('2d');
		drawStuff(ctx);
	});
</script>

<canvas bind:this={canvasElement}></canvas>

class:имя

class:имя={значение}
class:имя

Директива class: обеспечивает простой способ управления классами элемента.

<!-- Эти строки эквивалентны -->
<div class="{active ? 'active' : ''}">...</div>
<div class:active={active}>...</div>

<!-- Сокращение, при одинаковых имени и значении -->
<div class:active>...</div>

<!-- можно использовать сразу несколько переключателей классов -->
<div class:active class:inactive={!active} class:isAdmin>...</div>

style:property

style:property={value}
style:property="value"
style:property

Директива style: предоставляет сокращение для установки нескольких стилей на элементе.

<!--Это эквивалентно -->
<div style:color="red">...</div>
<div style="color: red;">...</div>

<!-- Переменные могут быть использованы -->
<div style:color={myColor}>...</div>

<!-- Сокращение для при имении свойства и переменной имени -->
<div style:color>...</div>

<!-- Многократные стили могут быть включены -->
<div style:color style:width="12rem" style:background-color={darkMode ? "black" : "white"}>...</div>

Когда директивы style: объединяются с атрибутами style, директивы будут иметь приоритет:

<div style="color: blue;" style:color="red">This will be red</div>

use:действие

use:действие
use:действие={параметры}
action = (node: HTMLElement, parameters: any) => {
	update?: (parameters: any) => void,
	destroy?: () => void
}

Действия — это функции, которые вызываются при создании элемента. Они могут возвращать объект с методом destroy, который вызывается, когда этот элемент удаляется из DOM.

<script>
	function foo(node) {
		// при добавлении элемента в DOM
		// node — ссылка на элемент в DOM

		return {
			destroy() {
				// при удалении элемента из DOM
			}
		};
	}
</script>

<div use:foo></div>

Действие может иметь параметр. Если возвращаемый объект имеет метод update, он будет вызываться всякий раз, когда этот параметр изменяется, сразу же после изменения разметки.

Не беспокойтесь о том, что мы объявляем функцию foo в каждом экземпляре компонента — Svelte выведет из контекста компонента любые функции, которые не зависят от его локального состояния.

<script>
	export let bar;

	function foo(node, bar) {
		// при добавлении элемента в DOM
		// node — ссылка на элемент в DOM

		return {
			update(bar) {
				// при изменении значения параметра `bar`
			},

			destroy() {
				// при удалении элемента из DOM
			}
		};
	}
</script>

<div use:foo={bar}></div>

transition:fn

transition:fn
transition:fn={параметры}
transition:fn|local
transition:fn|local={параметры}
transition = (node: HTMLElement, params: any) => {
	delay?: number,
	duration?: number,
	easing?: (t: number) => number,
	css?: (t: number, u: number) => string,
	tick?: (t: number, u: number) => void
}

Переход инициируется добавлением или удалением элемента из DOM в результате изменения состояния приложения.

Элементы внутри исчезающего блока, включая и те, которым не назначены собственные переходы, будут находиться в DOM до тех пор, пока не будут выполнены все запущенные внутри блока переходы.

Директива transition: указывает на то, что переход является обратимым. Т.е. он может в любой момент начать проигрываться в обратную сторону.

{#if visible}
	<div transition:fade>
		появляется и исчезает
	</div>
{/if}

По умолчанию переход появления не проигрывается при первой отрисовке компонента. Вы можете изменить это поведение установив параметр intro: true при создании компонента.

Параметры перехода

Как и действия, переходы могут иметь параметры.

(Двойные фигурные скобки {{...}} не являются особым синтаксисом; это просто литерал объекта внутри тега выражения)

{#if visible}
	<div transition:fade="{{ duration: 2000 }}">
		Влетает, исчезает. По 2 секунды на каждый переход
	</div>
{/if}
Пользовательские переходы

Переходы могут использовать пользовательские функции. Если возвращённый объект имеет функцию css, Svelte создаст CSS-анимацию, которая воспроизводится на элементе.

Аргумент t, передаваемый в функцию css, представляет собой значение между 0 и 1 после применения функции плавности easing. Переходы появления выполняются от 0 до1, переходы исчезновения выполняются от 1 до 0 — другими словами, 1 - это естественное состояние элемента, как если бы переход не применялся. Аргумент u равен 1 - t.

Функция вызывается множество раз с разными аргументами t и u до начала перехода.

<script>
	import { elasticOut } from 'svelte/easing';

	export let visible;

	function whoosh(node, params) {
		const existingTransform = getComputedStyle(node).transform.replace('none', '');

		return {
			delay: params.delay || 0,
			duration: params.duration || 400,
			easing: params.easing || elasticOut,
			css: (t, u) => `transform: ${existingTransform} scale(${t})`
		};
	}
</script>

{#if visible}
	<div in:whoosh>
		whooshes
	</div>
{/if}

Пользовательская функция перехода также может возвращать функцию tick, которая вызывается во время перехода с теми же аргументамиt и u.

Если возможно использовать css вместоtick, используйте — CSS-анимация может запускаться вне основного потока, предотвращая лаги на медленных устройствах.

<script>
	export let visible = false;

	function typewriter(node, { speed = 1 }) {
		const valid = (
			node.childNodes.length === 1 &&
			node.childNodes[0].nodeType === Node.TEXT_NODE
		);

		if (!valid) {
 			throw new Error(`This transition only works on elements with a single text node child`);
 		}

		const text = node.textContent;
		const duration = text.length / (speed * 0.01);

		return {
			duration,
			tick: t => {
				const i = ~~(text.length * t);
				node.textContent = text.slice(0, i);
			}
		};
	}
</script>

{#if visible}
	<p in:typewriter="{{ speed: 1 }}">
		Съешь ещё этих мягких французских булок, да выпей же чаю
	</p>
{/if}

Если переход возвращает функцию вместо объекта перехода, то она будет вызвана в следующей микрозадаче. Это позволяет координировать несколько переходов, что дает возможность запускать перекрёстные переходы.

События переходов

Элемент, который имеет переходы, в дополнение к стандартным событиям DOM может запускать ещё и такие события:

  • introstart
  • introend
  • outrostart
  • outroend
{#if visible}
	<p
		transition:fly="{{ y: 200, duration: 2000 }}"
		on:introstart="{() => status = 'начало появления'}"
		on:outrostart="{() => status = 'начало исчезновения'}"
		on:introend="{() => status = 'конец появления'}"
		on:outroend="{() => status = 'конец исчезновения'}"
	>
		Прилетает и улетает
	</p>
{/if}

Локальные переходы воспроизводятся только когда создается или убирается конкретный блок, к которому они прикреплены, а не его родительские блоки.

{#if x}
	{#if y}
		<p transition:fade>
			проигрывается когда изменяются 'x' или 'y'
		</p>

		<p transition:fade|local>
			проигрывается только когда изменяется 'y'
		</p>
	{/if}
{/if}

in:fn/out:fn

in:fn
in:fn={параметры}
in:fn|local
in:fn|local={параметры}
out:fn
out:fn={параметры}
out:fn|local
out:fn|local={параметры}

Аналогичны transition:, но применяются только когда элемент появляется (in:) или убирается (out:) из DOM.

В отличие от transition:, переходы in: и out: не являются обратимыми. При исчезновении элемента, если переход появления ещё не закончился, он будет проигрываться дальше, но уже вместе с переходом исчезновения. Если исчезновение элемента, было прервано, то переходы будут запущены заново.

{#if visible}
	<div in:fly out:fade>
		влетает, исчезает
	</div>
{/if}

animate:fn

animate:имя
animate:имя={параметры}
animation = (node: HTMLElement, { from: DOMRect, to: DOMRect } , params: any) => {
	delay?: number,
	duration?: number,
	easing?: (t: number) => number,
	css?: (t: number, u: number) => string,
	tick?: (t: number, u: number) => void
}
DOMRect {
	bottom: number,
	height: number,
	​​left: number,
	right: number,top: number,
	width: number,
	x: number,
	y: number
}

Анимация запускается при изменении порядка содержимого блока each с ключом. Анимация не запускается при добавлении или удалении элемента, только при изменении индекса существующего элемента данных в каждом блоке. Анимационные директивы должны быть на элементе, который является непосредственным дочерним элементом каждого блока с ключом.

Анимация может использовать встроенные функции анимации или пользовательские функции анимации.

<!-- при изменении порядка элементов в списке запустится анимация-->
{#each list as item, index (item)}
	<li animate:flip>{item}</li>
{/each}
Параметры анимации

Как действия и переходы, анимации также могут иметь параметры.

(Двойные фигурные скобки {{...}} здесь не являются особым синтаксисом - это просто литерал объекта внутри тега выражения)

{#each list as item, index (item)}
	<li animate:flip="{{ delay: 500 }}">{item}</li>
{/each}
Пользовательские функции анимации

Анимации могут использовать пользовательские функции, которые принимают в качестве аргументов ссылку на элемент node, объект animation и объект параметров. Объект animation содержит свойстваfrom и to, каждое из которых является объектом DOMRect, описывающим геометрию элемента в начальном и конечном положениях. Свойство from - это DOMRect элемента в его начальной позиции, свойство to - это DOMRect элемента в его конечной позиции после переупорядочивания списка и обновления DOM.

Если в возвращаемом из функции объекте есть метод css, Svelte создаст CSS-анимацию, которая будет применена к элементу node.

Аргумент t, передаваемый в метод css, представляет собой значение от 0 до 1, которое возвращает функция плавности easing для нужного момента времени. Аргумент u равен 1 - t.

Функция вызывается множество раз до начала анимации, с различными аргументами t и u.

<script>
	import { cubicOut } from 'svelte/easing';

	function whizz(node, { from, to }, params) {

		const dx = from.left - to.left;
		const dy = from.top - to.top;

		const d = Math.sqrt(dx * dx + dy * dy);

		return {
			delay: 0,
			duration: Math.sqrt(d) * 120,
			easing: cubicOut,
			css: (t, u) =>
				`transform: translate(${u * dx}px, ${u * dy}px) rotate(${t*360}deg);`
		};
	}
</script>

{#each list as item, index (item)}
	<div animate:whizz>{item}</div>
{/each}

Пользовательская функция анимации также может возвращать функцию tick, которая вызывается во время анимации с теми же аргументами t и u.

Всегда старайтесь использоватьcss вместоtick, поскольку CSS-анимация запускается вне основного потока, предотвращая подёргивания на медленных устройствах.

<script>
	import { cubicOut } from 'svelte/easing';

	function whizz(node, { from, to }, params) {

		const dx = from.left - to.left;
		const dy = from.top - to.top;

		const d = Math.sqrt(dx * dx + dy * dy);

		return {
		delay: 0,
		duration: Math.sqrt(d) * 120,
		easing: cubicOut,
		tick: (t, u) =>
			Object.assign(node.style, {
				color: t > 0.5 ? 'Pink' : 'Blue'
			});
	};
	}
</script>

{#each list as item, index (item)}
	<div animate:whizz>{item}</div>
{/each}

Директивы компонентов

on:событие

on:событие={обработчик}

Компоненты могут отправлять события, используя диспетчер событий createEventDispatcher или пробрасывая события DOM. Обработка событий компонента выглядит так же, как обработка событий DOM.

<SomeComponent on:whatever={handler}/>

Если директива on: используется без значения, то компонент будет пробрасывать событие выше, как и в аналогичном случае с событиями DOM. Событие станет доступно для прослушивания в родительском компоненте.

<SomeComponent on:whatever/>

--style-props

--style-props="anycssvalue"

Также можно передавать стили в качестве реквизита компонентам для целей тематизации, используя пользовательские свойства CSS.

Реализация Svelte по сути является синтаксическим сахаром для добавления элемента обертки. Вот пример:

<Slider
bind:value
min={0}
--rail-color="black"
--track-color="rgb(0, 0, 255)"
/>

Без сахара:

<div style="display: contents; --rail-color: black; --track-color: rgb(0, 0, 255)">
<Slider
	bind:value
	min={0}
	max={100}
/>
</div>

Примечание: Поскольку это дополнительный div, помните, что ваша структура CSS может случайно зацепиться за это. Помните об этом добавленом элементе обертки при использовании этой функции.


Поддержка CSS-переменных Svelte позволяет легко создавать темизируемые компоненты:

<!-- Slider.svelte -->
<style>
.potato-slider-rail {
	background-color: var(--rail-color, var(--theme-color, 'purple'));
}
</style>

Таким образом, можно установить цвет темы :root:

/* global.css */
html {
--theme-color: black;
}

Или переопределить его на уровне потребителя:

<Slider --rail-color="goldenrod"/>

bind:свойство

bind:свойство={переменная}

К свойствам компонента можно привязаться, точно так же как к атрибутам элементов.

<Keypad bind:value={pin}/>

bind:this

bind:this={экземпляр_компонента}

Компоненты также поддерживают привязку bind:this, позволяющую взаимодействовать с экземпляром компонента в коде.

Обратите внимание, что использование {cart.empty} вызовет ошибку, поскольку при первой отрисовке кнопки cart ещё имеет значение undefined.

<ShoppingCart bind:this={cart}/>

<button on:click={() => cart.empty()}>
	Очистить корзину
</button>

<slot>

<slot><!-- содержимое по умолчанию --></slot>
<slot name="x"><!-- содержимое по умолчанию --></slot>
<slot свойство={значениие}></slot>

Как и любой HTML-элемент, компоненты могут иметь вложенные элементы.

Вложенное содержимое размещается в компоненте при помощи элемента <slot>, который также может содержать содержимое по умолчанию, которое отображается, если в компонент не было предано никакого содержимого.

<!-- Widget.svelte -->
<div>
	<slot>
		это содержимое по умолчанию, которое отобразится, если не передали иного содержимого.
	</slot>
</div>

<!-- App.svelte -->
<Widget></Widget> <!-- этот компонент покажет содержимое по умолчанию -->

<Widget>
	<p>вложенный элемент, который заменит собой содержимое по умолчанию.</p>
</Widget>

<slot name="имя">


Именованные слоты позволяют указать конкретные области. Они тоже могут иметь запасное содержимое по умолчанию.

<!-- Widget.svelte -->
<div>
	<slot name="header">Заголовок не задан</slot>
	<p>Любое содержимое между заголовком и футером</p>
	<slot name="footer"></slot>
</div>

<!-- App.svelte -->
<Widget>
	<h1 slot="header">Привет</h1>
	<p slot="footer">Все права (c) 2019 Svelte Industries</p>
</Widget>

Компоненты могут быть размещены в именованном слоте с использованием синтаксиса <Component slot="name" />. Чтобы разместить контент в слоте без использования элемента-оболочки, вы можете использовать специальный элемент <svelte:fragment>.

<!-- Widget.svelte -->
<div>
	<slot name="header">Заголовок не задан</slot>
	<p>Любое содержимое между заголовком и футером</p>
	<slot name="footer"></slot>
</div>

<!-- App.svelte -->
<Widget>
	<HeaderComponent slot="header" />
	<svelte:fragment slot="footer">
		<p>Все права защищены.</p>
		<p>Копирайт (c) 2019 Svelte Industries</p>
	</svelte:fragment>
</Widget>

$$slots


$$slots - это объект, ключи которого являются именами слотов, переданных в компонент родительским компонентом. Если родительский компонент не передавал содержимое для слота, то имя этого слота не будет присутствовать в $$slots. Эту особенность можно использовать для отображения как самого слота, так и части шаблона в зависимости от того, передавал ли родительский компонент содержимое для этого слота.

Обратите внимание, что передача пустого элемента в слот все равно добавляет значение в $$slots. Например, если родительский компонент передает <div slot ="title"/> в дочерний, то $$slots.title будет равно true.

<!-- Card.svelte -->
<div>
	<slot name="title"></slot>
	{#if $$slots.description}
		<!-- Элемент <hr> и слот будут отрисованы, только  если будет получен слот с именем "description". -->
		<hr>
		<slot name="description"></slot>
	{/if}
</div>

<!-- App.svelte -->
<Card>
	<h1 slot="title">Заголовок статьи</h1>
	<!-- Слота с именем "description" нет, поэтому ничего не будет отображено. -->
</Card>

<slot key={value}>


Слоты могут быть отрисованы ноль или более раз и могут передавать значения обратно родителю через свои свойства. Родитель может получить эти значения от слота при помощи директивы let:.

Обычные правила сокращения работают и тут — let:item то же самое, что и let:item={item}, а <slot {item}> эквивалентно <slot item={item}>.

<!-- FancyList.svelte -->
<ul>
	{#each items as item}
		<li class="fancy">
			<slot prop={item}></slot>
		</li>
	{/each}
</ul>

<!-- App.svelte -->
<FancyList {items} let:prop={thing}>
	<div>{thing.text}</div>
</FancyList>

Именованные слоты также могут предоставлять значения. Директива let: указывается на элементе с атрибутом slot.

<!-- FancyList.svelte -->
<ul>
	{#each items as item}
		<li class="fancy">
			<slot name="item" item={item}></slot>
		</li>
	{/each}
</ul>

<slot name="footer"></slot>

<!-- App.svelte -->
<FancyList {items}>
	<div slot="item" let:item={item}>{item.text}</div>
	<p slot="footer">Все права (c) 2019 Svelte Industries</p>
</FancyList>

<svelte:self>


Элемент <svelte: self> позволяет компоненту включать самого себя себя рекурсивно.

Он не может отображаться на верхнем уровне разметки, а должен быть помещён внутри блока if или each, а также может быть передан в слот компонента, чтобы избежать бесконечного цикла.

<script>
	export let count;
</script>

{#if count > 0}
	<p>Отсчёт... {count}</p>
	<svelte:self count="{count - 1}"/>
{:else}
	<p>Поехали!</p>
{/if}

<svelte:component>

<svelte:component this={выражение}/>

Элемент <svelte:component> отрисовывает компонент динамически, используя конструктор компонента, переданный в свойствеthis. Когда значение свойства изменяется, компонент уничтожается и создается заново.

Если выражение в свойстве this ложное, компонент не отрисовывается.

<svelte:component this={currentSelection.component} foo={bar}/>

<svelte:window>

<svelte:window on:событие={обработчик}/>
<svelte:window bind:свойство={значение}/>

Элемент <svelte:window> позволяет добавлять обработчики событий к объекту window, не беспокоясь об их удалении при уничтожении компонента или проверять существование window при рендеринге на стороне сервера.

В отличие от <svelte:self> этот элемент может быть только на верхнем уровне вашего компонента и никогда не должен находиться внутри блока или элемента.

<script>
	function handleKeydown(event) {
		alert(`нажата клавиша ${event.key}`);
	}
</script>

<svelte:window on:keydown={handleKeydown}/>

Также можно сделать привязку к следующим свойствам:

  • innerWidth
  • innerHeight
  • outerWidth
  • outerHeight
  • scrollX
  • scrollY
  • online — сокращение для window.navigator.onLine

Все свойства, кроме scrollX и scrollY доступны только для чтения.

<svelte:window bind:scrollY={y}/>

Обратите внимание, что страница не будет прокручиваться до начального значения, чтобы избежать проблем со специальными возможностями. Только последующие изменения связанной переменной scrollX и scrollY вызовут прокрутку. Однако, если требуется поведение прокрутки, вызовите scrollTo() в onMount().

<svelte:body>

<svelte:body on:событие={обработчик}/>

Подобно <svelte:window>, этот элемент позволяет добавлять обработчики событий на document.body, такие как mouseenter и mouseleave, которые не запускаются на window. Он также позволяет использовать actions для элемента <body>.

<svelte:body> также должен находиться на верхнем уровне вашего компонента.

<svelte:body
	on:mouseenter={handleMouseenter}
	on:mouseleave={handleMouseleave}
	use:someAction
/>

<svelte:head>

<svelte:head>...</svelte:head>

Этот элемент позволяет вставлять элементы в document.head. При рендеринге на стороне сервера содержимое head предоставляется отдельно от основного содержимого html.

Как и в случае со <svelte:window и <svelte:body, этот элемент должен быть на верхнем уровне вашего компонента и не может находиться внутри блока или другого элемента.

<svelte:head>
	<link rel="stylesheet" href="/tutorial/dark-theme.css">
</svelte:head>

<svelte:options>

<svelte:options параметр={значение}/>

Элемент <svelte:options> позволяет установить определенные параметры для компилятора для каждого отдельного компонента. Подробнее о параметрах компилятора можно узнать в разделе про функцию compile. Параметры, которые можно установить:

  • immutable={true} — установите, если вы нигде не используете изменяемые данные — тогда компилятор сможет выполнять более простые проверки равенства объектов для определения их изменения
  • immutable={false} — по умолчанию. Svelte будет проверять изменение объектов обычным способом
  • accessors={true} — добавляет сеттеры и геттеры для свойств компонента
  • accessors={false} — по умолчанию, аксессоры не добавляются
  • namespace="..." — пространство имен, где компонент будет использован (обычно требуется "svg"); используйте "foreign" чтобы имена аттрибутов стали чувствительны к регистру и не отображались ошибки специфичные для HTML
  • tag="..." — имя, которое используется при компиляции компонента в пользовательский элемент
<svelte:options tag="my-custom-element"/>

<svelte:fragment>

Элемент <svelte:fragment> позволяет размещать контент в именованных слотах не оборачивая его в дополнительный элемент DOM. Это сохраняет структуру макета вашего документа.

<!-- Widget.svelte -->
<div>
	<slot name="header">Заголовок не предоставлен</slot>
	<p>Любое содержимое между заголовком и футером</p>
	<slot name="footer"></slot>
</div>

<!-- App.svelte -->
<Widget>
	<h1 slot="header">Привет</h1>
	<svelte:fragment slot="footer">
		<p>Все права защищены.</p>
		<p>Копирайт (c) 2019 Svelte Industries</p>
	</svelte:fragment>
</Widget>