Spec-Zone.ru › Svelte 3

Svelte

Прежде чем начать

Эта страница содержит подробную справочную документацию API. Она предназначена для людей, которые уже знакомы с Svelte.

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

Не стесняйтесь обращаться за помощью в чат-комнате Discord.

Используете старую версию Svelte? Посмотрите документацию v2.

Начало работы

Чтобы попробовать Svelte в интерактивной онлайн-среде, вы можете попробовать REPL или StackBlitz.

Для создания проекта локально мы рекомендуем использовать SvelteKit, официальный фреймворк для приложений от команды Svelte:

npm create svelte@latest myapp
cd myapp
npm install
npm run dev

SvelteKit будет обрабатывать вызов компилятора Svelte для преобразования ваших .svelte файлов в .js файлы, которые создают DOM, и .css файлы, которые стилизуют его. Он также предоставляет все остальные необходимые компоненты для создания веб-приложения, такие как сервер разработки, маршрутизацию и развертывание. SvelteKit использует Vite для сборки вашего кода и обработки серверной отрисовки (SSR). Существуют плагины для всех основных веб-бандлеров, которые обрабатывают компиляцию Svelte, что выведет .js и .css, которые можно вставить в ваш HTML, но большинство других не будут поддерживать SSR.

Если вам не нужен полноценный фреймворк приложения, а нужно создать простой сайт/приложение только для фронтенда, вы также можете использовать Svelte (без Kit) с Vite, выполнив npm init vite и выбрав опцию svelte. При этом npm run build сгенерирует HTML, JS и CSS файлы внутри директории dist.

Команда Svelte поддерживает расширение VS Code, а также существуют интеграции с различными другими редакторами и инструментами.

Если у вас возникнут проблемы, получите помощь на Discord или StackOverflow.

Формат компонента

Компоненты — это строительные блоки приложений Svelte. Они записываются в файлы .svelte, используя расширение HTML.

Все три раздела — сценарий, стили и разметка — необязательны.

<script>
	// logic goes here
</script>

<!-- markup (zero or more items) goes here -->

<style>
	/* styles go here */
</style>

<script>

Блок <script> содержит JavaScript-код, который выполняется при создании экземпляра компонента. Переменные, объявленные (или импортированные) на верхнем уровне, «видимы» из разметки компонента. Существуют четыре дополнительных правила:

1. export создаёт свойство компонента

Svelte использует ключевое слово export для обозначения переменной как свойства или параметра, что означает, что оно станет доступным для потребителей компонента (см. раздел о атрибутах и параметрах для получения дополнительной информации).

<script>
	export let foo;

	// Values that are passed in as props
	// are immediately available
	console.log({ foo });
</script>

Вы можете указать значение по умолчанию для свойства. Оно будет использоваться, если потребитель компонента не указывает свойство (или если его начальное значение равно undefined) при создании компонента. Обратите внимание, что при удалении свойства потребителем его значение устанавливается в undefined, а не в начальное значение.

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

<script>
	export let bar = 'optional default initial value';
	export let baz = undefined;
</script>

Если вы экспортируете const, class или function, оно будет только для чтения снаружи компонента. Функции являются допустимыми значениями свойств, как показано ниже.

<script>
	// these are readonly
	export const thisIs = 'readonly';

	export function greet(name) {
		alert(`hello ${name}!`);
	}

	// this is a prop
	export let format = n => n.toFixed(2);
</script>

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

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

<script>
	let className;

	// creates a `class` property, even
	// though it is a reserved word
	export { className as class };
</script>

2. Присваивания «реактивные»

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

Выражения обновления (count += 1) и присваивания свойств (obj.x = y) имеют тот же эффект.

<script>
	let count = 0;

	function handleClick () {
		// calling this function will trigger an
		// update if the markup references `count`
		count = count + 1;
	}
</script>

Поскольку реактивность Svelte основана на присваиваниях, использование методов массивов, таких как .push() и .splice(), не вызовет автоматических обновлений. Для запуска обновления требуется последующее присваивание. Подробности об этом и многом другом можно найти в учебнике.

<script>
	let arr = [0, 1];

	function handleClick () {
		// this method call does not trigger an update
		arr.push(2);
		// this assignment will trigger an update
		// if the markup references `arr`
		arr = arr
	}
</script>

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

<script>
	export let person;
	// this will only set `name` on component creation
	// it will not update when `person` does
	let { name } = person;
</script>

3. $: помечает оператор как реактивный

Любой оператор верхнего уровня (т. е. не внутри блока или функции) может быть сделан реактивным, добавив префикс $: синтаксис JS метки. Реактивные операторы выполняются после других кодов сценария и перед отрисовкой разметки компонента, всякий раз, когда изменяются значения, от которых они зависят.

<script>
	export let title;
	export let person

	// this will update `document.title` whenever
	// the `title` prop changes
	$: document.title = title;

	$: {
		console.log(`multiple statements can be combined`);
		console.log(`the current title is ${title}`);
	}

	// this will update `name` when 'person' changes
	$: ({ name } = person);

	// don't do this. it will run before the previous line
	let name2 = name;
</script>

Только значения, которые непосредственно появляются внутри блока $:, станут зависимостями реактивного оператора. Например, в коде ниже total обновится только тогда, когда x изменится, но не y.

<script>
	let x = 0;
	let y = 0;
	
	function yPlusAValue(value) {
		return value + y;
	}
	
	$: total = yPlusAValue(x);
</script>

Total: {total}
<button on:click={() => x++}>
	Increment X
</button>

<button on:click={() => y++}>
	Increment Y
</button>

Важно отметить, что реактивные блоки упорядочиваются с помощью простого статического анализа на этапе компиляции, и все, что анализирует компилятор, — это переменные, которым присваиваются значения и которые используются в самом блоке, а не в любых функциях, вызываемых ими. Это означает, что yDependent не будет обновляться при обновлении x в следующем примере:

<script>
	let x = 0;
	let y = 0;
	
	const setY = (value) => {
		y = value;
	}
	
	$: yDependent = y;
	$: setY(x);
</script>

Перемещение строки $: yDependent = y ниже $: setY(x) приведет к обновлению yDependent при обновлении x.

Если оператор состоит целиком из присваивания необъявленной переменной, Svelte вставит объявление let от вашего имени.

<script>
	export let num;

	// we don't need to declare `squared` and `cubed`
	// — Svelte does it for us
	$: squared = num * num;
	$: cubed = squared * num;
</script>

4. Префикс $ перед хранилищами для доступа к их значениям

Хранилище — это объект, который позволяет получать доступ к значению с помощью простого контракта хранилища. Модуль svelte/store содержит минимальные реализации хранилищ, которые соответствуют этому контракту.

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

Присваивания к переменным с префиксом $ требуют, чтобы переменная была записываемым хранилищем, и приведут к вызову метода .set хранилища.

Обратите внимание, что хранилище должно быть объявлено на верхнем уровне компонента — не внутри блока if или функции, например.

Локальные переменные (которые не представляют значения хранилища) не должны иметь префикс $.

<script>
	import { writable } from 'svelte/store';

	const count = writable(0);
	console.log($count); // logs 0

	count.set(1);
	console.log($count); // logs 1

	$count = 2;
	console.log($count); // logs 2
</script>
Контракт хранилища
store = { subscribe: (subscription: (value: any) => void) => (() => void), set?: (value: any) => void }

Вы можете создать собственные хранилища, не полагаясь на svelte/store, реализовав контракт хранилища:

  1. Хранилище должно содержать метод .subscribe, который должен принимать в качестве аргумента функцию подписки. Эта функция подписки должна немедленно и синхронно вызываться со значением хранилища в момент вызова .subscribe. Все активные функции подписки хранилища должны впоследствии синхронно вызываться всякий раз, когда значение хранилища изменяется.
  2. Метод .subscribe должен возвращать функцию отписки. Вызов функции отписки должен прекратить подписку, и соответствующая функция подписки не должна вызываться хранилищем снова.
  3. Хранилище может необязательно содержать метод .set, который должен принимать в качестве аргумента новое значение для хранилища и синхронно вызывать все активные функции подписки хранилища. Такое хранилище называется записываемым хранилищем.

Для взаимодействия с RxJS Observables метод .subscribe также разрешено возвращать объект с методом .unsubscribe вместо прямой передачи функции отписки. Обратите внимание, однако, что если .subscribe не синхронно вызывает подписку (что не требуется спецификацией Observable), Svelte будет видеть значение хранилища как undefined до тех пор, пока это не произойдёт.

<script context="module">

Тег <script> с атрибутом context="module" выполняется один раз при первом вычислении модуля, а не для каждого экземпляра компонента. Значения, объявленные в этом блоке, доступны из обычного <script> (и разметки компонента), но не наоборот.

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

Вы не можете export default, так как экспорт по умолчанию — это сам компонент.

Переменные, определённые в скриптах module, не реактивные — повторное присваивание не вызовет перерисовку, хотя сама переменная обновится. Для значений, общих для нескольких компонентов, рассмотрите использование хранилища.

<script context="module">
	let totalComponents = 0;

	// this allows an importer to do e.g.
	// `import Example, { alertTotal } from './Example.svelte'`
	export function alertTotal() {
		alert(totalComponents);
	}
</script>

<script>
	totalComponents += 1;
	console.log(`total number of times this component has been created: ${totalComponents}`);
</script>

<style>

CSS внутри блока <style> будет ограничен этим компонентом.

Это работает путём добавления класса к затронутым элементам, который основан на хеше стилей компонента (например, svelte-123xyz).

<style>
	p {
		/* this will only affect <p> elements in this component */
		color: burlywood;
	}
</style>

Чтобы применить стили к селектору глобально, используйте модификатор :global(...).

<style>
	:global(body) {
		/* this will apply to <body> */
		margin: 0;
	}

	div :global(strong) {
		/* this will apply to all <strong> elements, in any
			 component, that are inside <div> elements belonging
			 to this component */
		color: goldenrod;
	}

	p:global(.red) {
		/* this will apply to all <p> elements belonging to this 
			 component with a class of red, even if class="red" does
			 not initially appear in the markup, and is instead 
			 added at runtime. This is useful when the class 
			 of the element is dynamically applied, for instance 
			 when updating the element's classList property directly. */
	}
</style>

Если вы хотите сделать @keyframes доступными глобально, вам нужно добавить префикс к именам ваших keyframes с помощью -global-.

Часть -global- будет удалена при компиляции, и к keyframe будет обращаться только с помощью my-animation-name в других частях вашего кода.

<style>
	@keyframes -global-my-animation-name {...}
</style>
END_OF_DOCUMENT_MARKER

В компоненте должен быть только 1 тег верхнего уровня <style>.

Однако, можно иметь тег <style>, вложенный внутри других элементов или блоков логики.

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

<div>
	<style>
		/* this style tag will be inserted as-is */
		div {
			/* this will apply to all `<div>` elements in the DOM */
			color: red;
		}
	</style>
</div>

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

Теги

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

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

<div>
	<Widget/>
</div>

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

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

<div class="foo">
	<button disabled>can't touch this</button>
</div>

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

<input type=checkbox>

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

<a href="page/{p}">page {p}</a>

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

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

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

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

<input required={false} placeholder="This input field is not required">
<div title={null}>This div has no title attribute</div>

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

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

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

<!-- These are equivalent -->
<button disabled={disabled}>...</button>
<button {disabled}>...</button>

По соглашению, значения, передаваемые компонентам, называются свойствами или props, а не атрибутами, которые являются функцией DOM.

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

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

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

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

<Widget {...things}/>

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

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

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

<input {...$$restProps}>

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

Иногда порядок атрибутов имеет значение, так как Svelte устанавливает атрибуты последовательно в JavaScript. Например, в <input type="range" min="0" max="1" value={0.5} step="0.1"/> Svelte попытается установить значение в 1 (округляя вверх с 0.5, так как шаг по умолчанию равен 1), а затем установить шаг в 0.1. Чтобы исправить это, измените на <input type="range" min="0" max="1" step="0.1" value={0.5}/>.

Другой пример – <img src="..." loading="lazy" />. Svelte установит img src перед тем, как сделать img-элемент loading="lazy", что, вероятно, произойдет слишком поздно. Измените это на <img loading="lazy" src="...">, чтобы изображение загружалось лениво.

Выражения текста

{expression}

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

Если вы используете регулярное выражение (RegExp) в виде литерала, вам нужно заключить его в скобки.

<h1>Hello {name}!</h1>
<p>{a} + {b} = {a + b}.</p>

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

Комментарии

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

<!-- this is a comment! -->
<h1>Hello world</h1>

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

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

{#if ...}

{#if expression}...{/if}
{#if expression}...{:else if expression}...{/if}
{#if expression}...{:else}...{/if}

Условный контент можно заключить в блок if.

{#if answer === 42}
	<p>what was the question?</p>
{/if}

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

{#if porridge.temperature > 100}
	<p>too hot!</p>
{:else if 80 > porridge.temperature}
	<p>too cold!</p>
{:else}
	<p>just right!</p>
{/if}

{#each ...}

{#each expression as name}...{/each}
{#each expression as name, index}...{/each}
{#each expression as name (key)}...{/each}
{#each expression as name, index (key)}...{/each}
{#each expression as name}...{:else}...{/each}

Итерацию по спискам значений можно выполнять с помощью блока each.

<h1>Shopping list</h1>
<ul>
	{#each items as item}
		<li>{item.name} x {item.qty}</li>
	{/each}
</ul>

Вы можете использовать блоки each для итерации по любому массиву или массивоподобному значению — то есть любому объекту со свойством length.

Блок each также может указывать индекс, эквивалентный второму аргументу в вызове array.map(...):

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

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

{#each items as item (item.id)}
	<li>{item.name} x {item.qty}</li>
{/each}

<!-- or with additional index value -->
{#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>No tasks today!</p>
{/each}

{#await ...}

{#await expression}...{:then name}...{:catch name}...{/await}
{#await expression}...{:then name}...{/await}
{#await expression then name}...{/await}
{#await expression catch name}...{/await}

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

{#await promise}
	<!-- promise is pending -->
	<p>waiting for the promise to resolve...</p>
{:then value}
	<!-- promise was fulfilled -->
	<p>The value is {value}</p>
{:catch error}
	<!-- promise was rejected -->
	<p>Something went wrong: {error.message}</p>
{/await}

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

{#await promise}
	<!-- promise is pending -->
	<p>waiting for the promise to resolve...</p>
{:then value}
	<!-- promise was fulfilled -->
	<p>The value is {value}</p>
{/await}

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

{#await promise then value}
	<p>The value is {value}</p>
{/await}

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

{#await promise catch error}
	<p>The error is {error}</p>
{/await}

{#key ...}

{#key expression}...{/key}

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

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

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

При использовании вокруг компонентов это приведет к их повторной инициализации.

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

{@html ...}

{@html expression}
END_OF_DOCUMENT_MARKER

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

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

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

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

{@debug ...}

{@debug}
{@debug var1, var2, ..., varN}

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

<script>
	let user = {
		firstname: 'Ada',
		lastname: 'Lovelace'
	};
</script>

{@debug user}

<h1>Hello {user.firstname}!</h1>

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

<!-- Compiles -->
{@debug user}
{@debug user1, user2, user3}

<!-- WON'T compile -->
{@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} разрешен только как непосредственный дочерний элемент {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, <Component /> или <svelte:fragment />.

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

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

on:eventname

on:eventname={handler}
on:eventname|modifiers={handler}

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

<script>
	let count = 0;

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

<button on:click={handleClick}>
	count: {count}
</button>

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

<button on:click="{() => count += 1}">
	count: {count}
</button>

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

<form on:submit|preventDefault={handleSubmit}>
	<!-- the `submit` event's default is prevented,
	     so the page won't reload -->
</form>

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

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

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

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

<button on:click>
	The component itself will emit the click event
</button>

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

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

	function track(event) {
		trackEvent(event)
	}
</script>

<button on:click={increment} on:click={track}>Click me!</button>

bind:property

bind:property={variable}

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

Самые простые привязки отражают значение свойства, например, input.value.

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

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

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

<!-- These are equivalent -->
<input bind:value={value}>
<input bind:value>

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

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

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

<label for="avatar">Upload a picture:</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)}"
/>

Здесь мы привязывались к значению текстового поля ввода, которое использует событие input. Привязки к другим элементам могут использовать различные события, такие как change.

Привязка значения <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>
		Something small enough to escape casual notice.
	</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:played
	bind:seekable
	bind:seeking
	bind:ended
	bind:currentTime
	bind:playbackRate
	bind:paused
	bind:volume
	bind:muted
	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={variable}

Взаимодействующие элементы могут использовать bind:group.

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

<!-- grouped radio inputs are mutually exclusive -->
<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">

<!-- grouped checkbox inputs populate an array -->
<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_node}

Чтобы получить ссылку на узел 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:name

class:name={value}
class:name

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

<!-- These are equivalent -->
<div class="{active ? 'active' : ''}">...</div>
<div class:active={active}>...</div>

<!-- Shorthand, for when name and value match -->
<div class:active>...</div>

<!-- Multiple class toggles can be included -->
<div class:active class:inactive={!active} class:isAdmin>...</div>

style:свойство

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

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

<!-- These are equivalent -->
<div style:color="red">...</div>
<div style="color: red;">...</div>

<!-- Variables can be used -->
<div style:color={myColor}>...</div>

<!-- Shorthand, for when property and variable name match -->
<div style:color>...</div>

<!-- Multiple styles can be included -->
<div style:color style:width="12rem" style:background-color={darkMode ? "black" : "white"}>...</div>

<!-- Styles can be marked as important -->
<div style:color|important="red">...</div>

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

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

use:действие

use:action
use:action={parameters}
action = (node: HTMLElement, parameters: any) => {
	update?: (parameters: any) => void,
	destroy?: () => void
}

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

<script>
	function foo(node) {
		// the node has been mounted in the DOM

		return {
			destroy() {
				// the node has been removed from the DOM
			}
		};
	}
</script>

<div use:foo></div>

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

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

<script>
	export let bar;

	function foo(node, bar) {
		// the node has been mounted in the DOM

		return {
			update(bar) {
				// the value of `bar` has changed
			},

			destroy() {
				// the node has been removed from the DOM
			}
		};
	}
</script>

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

transition:функция

transition:fn
transition:fn={params}
transition:fn|local
transition:fn|local={params}
transition = (node: HTMLElement, params: any, options: { direction: 'in' | 'out' | 'both' }) => {
	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>
		fades in and out
	</div>
{/if}

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

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

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

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

{#if visible}
	<div transition:fade="{{ duration: 2000 }}">
		fades in and out over two seconds
	</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 in
	</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 }}">
		The quick brown fox jumps over the lazy dog
	</p>
{/if}

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

Функции переходов также получают третий аргумент, options, содержащий информацию о переходе.

Доступные значения в объекте options:

  • direction - одно из значений in, out или both в зависимости от типа перехода
События перехода

Элемент с переходами будет генерировать следующие события помимо стандартных событий DOM:

  • introstart
  • introend
  • outrostart
  • outroend
{#if visible}
	<p
		transition:fly="{{ y: 200, duration: 2000 }}"
		on:introstart="{() => status = 'intro started'}"
		on:outrostart="{() => status = 'outro started'}"
		on:introend="{() => status = 'intro ended'}"
		on:outroend="{() => status = 'outro ended'}"
	>
		Flies in and out
	</p>
{/if}

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

{#if x}
	{#if y}
		<p transition:fade>
			fades in and out when x or y change
		</p>

		<p transition:fade|local>
			fades in and out only when y changes
		</p>
	{/if}
{/if}

in:функция/out:функция

in:fn
in:fn={params}
in:fn|local
in:fn|local={params}
out:fn
out:fn={params}
out:fn|local
out:fn|local={params}

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

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

{#if visible}
	<div in:fly out:fade>
		flies in, fades out
	</div>
{/if}

animate:функция

animate:name
animate:name={params}
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
}

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

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

<!-- When `list` is reordered the animation will run-->
{#each list as item, index (item)}
	<li animate:flip>{item}</li>
{/each}
Параметры анимации

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

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

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

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

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

Аргумент 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:eventname

on:eventname={handler}

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

<SomeComponent on:whatever={handler}/>

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

<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 случайно не нацеливалась на него. Имейте в виду этот добавленный оберточный элемент при использовании этой функции.

Для пространства имён SVG вышеприведённый пример десугаривается, используя <g> вместо этого:

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

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

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

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

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

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

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

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

bind:property

bind:property={variable}

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

<Keypad bind:value={pin}/>

bind:this

bind:this={component_instance}

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

Обратите внимание, что мы не можем сделать {cart.empty}, так как cart является undefined, когда кнопка впервые отрисовывается, и это приводит к ошибке.

<ShoppingCart bind:this={cart}/>

<button on:click={() => cart.empty()}>
	Empty shopping cart
</button>

<slot>

<slot><!-- optional fallback --></slot>
<slot name="x"><!-- optional fallback --></slot>
<slot prop={value}></slot>

Компоненты могут содержать дочернее содержимое так же, как и элементы.

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

<!-- Widget.svelte -->
<div>
	<slot>
		this fallback content will be rendered when no content is provided, like in the first example
	</slot>
</div>

<!-- App.svelte -->
<Widget></Widget> <!-- this component will render the default content -->

<Widget>
	<p>this is some child content that will overwrite the default slot content</p>
</Widget>

<slot name="name">

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

<!-- Widget.svelte -->
<div>
	<slot name="header">No header was provided</slot>
	<p>Some content between header and footer</p>
	<slot name="footer"></slot>
</div>

<!-- App.svelte -->
<Widget>
	<h1 slot="header">Hello</h1>
	<p slot="footer">Copyright (c) 2019 Svelte Industries</p>
</Widget>

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

<!-- Widget.svelte -->
<div>
	<slot name="header">No header was provided</slot>
	<p>Some content between header and footer</p>
	<slot name="footer"></slot>
</div>

<!-- App.svelte -->
<Widget>
	<HeaderComponent slot="header" />
	<svelte:fragment slot="footer">
		<p>All rights reserved.</p>
		<p>Copyright (c) 2019 Svelte Industries</p>
	</svelte:fragment>
</Widget>

$$slots

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

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

<!-- Card.svelte -->
<div>
	<slot name="title"></slot>
	{#if $$slots.description}
		<!-- This <hr> and slot will render only if a slot named "description" is provided. -->
		<hr>
		<slot name="description"></slot>
	{/if}
</div>

<!-- App.svelte -->
<Card>
	<h1 slot="title">Blog Post Title</h1>
	<!-- No slot named "description" was provided so the optional slot will not be rendered. -->
</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}></slot>
		</li>
	{/each}
</ul>

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

<!-- App.svelte -->
<FancyList {items}>
	<div slot="item" let:item>{item.text}</div>
	<p slot="footer">Copyright (c) 2019 Svelte Industries</p>
</FancyList>

<svelte:self>

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

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

<script>
	export let count;
</script>

{#if count > 0}
	<p>counting down... {count}</p>
	<svelte:self count="{count - 1}"/>
{:else}
	<p>lift-off!</p>
{/if}

<svelte:component>

<svelte:component this={expression}/>

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

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

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

<svelte:element>

<svelte:element this={expression}/>

Элемент <svelte:element> позволяет отображать элемент динамически заданного типа. Это полезно, например, при отображении богатого текстового контента из CMS. Все свойства и обработчики событий будут применены к элементу.

Единственная поддерживаемая привязка — bind:this, так как специфичные для типа элемента привязки, которые Svelte выполняет на этапе сборки (например, bind:value для элементов input), не работают с динамическим типом тега.

Если this имеет нулевое значение, элемент и его дочерние элементы не будут отображены.

Если this — имя тега без содержимого (например, br) и <svelte:element> содержит дочерние элементы, в режиме разработки будет выброшена ошибка выполнения.

<script>
	let tag = 'div';
	export let handler;
</script>

<svelte:element this={tag} on:click={handler}>Foo</svelte:element>

<svelte:window>

<svelte:window on:event={handler}/>
<svelte:window bind:prop={value}/>

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

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

<script>
	function handleKeydown(event) {
		alert(`pressed the ${event.key} 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:event={handler}/>

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

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

<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 option={value}/>

Элемент <svelte:options> предоставляет место для указания опций компилятора для каждого компонента, которые подробно описаны в разделе компилятора. Возможные опции:

  • 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">No header was provided</slot>
	<p>Some content between header and footer</p>
	<slot name="footer"></slot>
</div>

<!-- App.svelte -->
<Widget>
	<h1 slot="header">Hello</h1>
	<svelte:fragment slot="footer">
		<p>All rights reserved.</p>
		<p>Copyright (c) 2019 Svelte Industries</p>
	</svelte:fragment>
</Widget>

Время выполнения

svelte

Пакет svelte предоставляет функции жизненного цикла и API контекста.

onMount

onMount(callback: () => void)
onMount(callback: () => () => void)

Функция onMount планирует вызов обратного вызова, который выполнится, как только компонент будет смонтирован в DOM. Она должна вызываться во время первоначальной инициализации компонента (но не обязательно внутри самого компонента; её можно вызвать из внешнего модуля).

onMount не выполняется внутри компонента на стороне сервера.

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

	onMount(() => {
		console.log('the component has mounted');
	});
</script>

Если из onMount возвращается функция, она будет вызвана при размонтировании компонента.

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

	onMount(() => {
		const interval = setInterval(() => {
			console.log('beep');
		}, 1000);

		return () => clearInterval(interval);
	});
</script>

Это поведение будет работать только тогда, когда функция, переданная в onMount, синхронно возвращает значение. Функции async всегда возвращают Promise и поэтому не могут синхронно вернуть функцию.

beforeUpdate

beforeUpdate(callback: () => void)

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

В первый раз обратный вызов выполнится до первоначального onMount

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

	beforeUpdate(() => {
		console.log('the component is about to update');
	});
</script>

afterUpdate

afterUpdate(callback: () => void)

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

В первый раз обратный вызов выполнится после первоначального onMount

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

	afterUpdate(() => {
		console.log('the component just updated');
	});
</script>

onDestroy

onDestroy(callback: () => void)

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

Из onMount, beforeUpdate, afterUpdate и onDestroy только этот выполняется внутри компонента на стороне сервера.

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

	onDestroy(() => {
		console.log('the component is being destroyed');
	});
</script>

tick

promise: Promise = tick()

Возвращает промис, который разрешается после применения всех ожидающих изменений состояния, или в следующей микрозадаче, если таковых нет.

<script>
	import { beforeUpdate, tick } from 'svelte';

	beforeUpdate(async () => {
		console.log('the component is about to update');
		await tick();
		console.log('the component just updated');
	});
</script>

setContext

setContext(key: any, context: any)

Связывает произвольный context объект с текущим компонентом и указанным key и возвращает этот объект. Контекст затем доступен для дочерних компонентов (включая вложенный контент) с помощью getContext.

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

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

	setContext('answer', 42);
</script>

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

getContext

context: any = getContext(key: any)

Извлекает контекст, который принадлежит ближайшему родительскому компоненту со специфицированным key. Необходимо вызывать во время первоначальной инициализации компонента.

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

	const answer = getContext('answer');
</script>

hasContext

hasContext: boolean = hasContext(key: any)

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

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

	if (hasContext('answer')) {
		// do something
	}
</script>

getAllContexts

contexts: Map<any, any> = getAllContexts()

Извлекает всю карту контекста, которая принадлежит ближайшему родительскому компоненту. Необходимо вызывать во время инициализации компонента. Полезно, например, если вы программно создаёте компонент и хотите передать ему существующий контекст.

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

	const contexts = getAllContexts();
</script>

createEventDispatcher

dispatch: ((name: string, detail?: any, options?: DispatchOptions) => boolean) = createEventDispatcher();

Создаёт диспетчер событий, который может использоваться для отправки событий компонентов. Диспетчеры событий являются функциями, которые могут принимать два аргумента: name и detail.

События компонентов, созданные с помощью createEventDispatcher, создают событие CustomEvent. Эти события не распространяются. Аргумент detail соответствует свойству CustomEvent.detail и может содержать любые данные.

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

	const dispatch = createEventDispatcher();
</script>

<button on:click="{() => dispatch('notify', 'detail value')}">Fire Event</button>

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

<script>
	function callbackFunction(event) {
		console.log(`Notify fired! Detail: ${event.detail}`)
	}
</script>

<Child on:notify="{callbackFunction}"/>

События можно отменить, передав третий параметр в функцию отправки. Функция возвращает false, если событие отменено с помощью event.preventDefault(), в противном случае возвращает true.

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

	const dispatch = createEventDispatcher();

	function notify() {
		const shouldContinue = dispatch('notify', 'detail value', { cancelable: true });
		if (shouldContinue) {
			// no one called preventDefault
		} else {
			// a listener called preventDefault
		}
	}
</script>

svelte/store

Модуль svelte/store экспортирует функции для создания читаемых, записываемых и производных хранилищ.

Помните, что вам не обязательно использовать эти функции, чтобы использовать синтаксис реактивных $store в ваших компонентах. Любой объект, который правильно реализует .subscribe, отмену подписки и (необязательно) .set, является допустимым хранилищем и будет работать как со специальным синтаксисом, так и с встроенными в Svelte derived хранилищами.

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

writable

store = writable(value?: any)
store = writable(value?: any, start?: (set: (value: any) => void) => () => void)

Функция, которая создаёт хранилище, значения которого можно устанавливать из «внешних» компонентов. Оно создаётся как объект с дополнительными методами set и update.

set - это метод, который принимает один аргумент — значение, которое нужно установить. Значение хранилища устанавливается в значение аргумента, если значение хранилища не равно ему.

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

import { writable } from 'svelte/store';

const count = writable(0);

count.subscribe(value => {
	console.log(value);
}); // logs '0'

count.set(1); // logs '1'

count.update(n => n + 1); // logs '2'

Если в качестве второго аргумента передана функция, она будет вызвана, когда количество подписчиков меняется с нуля на единицу (но не с единицы на две и т. д.). Эта функция получит функцию set, которая изменяет значение хранилища. Она должна вернуть функцию stop, которая вызывается, когда количество подписчиков меняется с единицы на ноль.

import { writable } from 'svelte/store';

const count = writable(0, () => {
	console.log('got a subscriber');
	return () => console.log('no more subscribers');
});

count.set(1); // does nothing

const unsubscribe = count.subscribe(value => {
	console.log(value);
}); // logs 'got a subscriber', then '1'

unsubscribe(); // logs 'no more subscribers'

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

readable

store = readable(value?: any, start?: (set: (value: any) => void) => () => void)

Создаёт хранилище, значение которого нельзя установить извне; первым аргументом является начальное значение хранилища, а второй аргумент для readable такой же, как и для writable.

import { readable } from 'svelte/store';

const time = readable(null, set => {
	set(new Date());

	const interval = setInterval(() => {
		set(new Date());
	}, 1000);

	return () => clearInterval(interval);
});

derived

store = derived(a, callback: (a: any) => any)
store = derived(a, callback: (a: any, set: (value: any) => void) => void | () => void, initial_value: any)
store = derived([a, ...b], callback: ([a: any, ...b: any[]]) => any)
store = derived([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) => void) => void | () => void, initial_value: any)

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

В простейшем варианте derived принимает одно хранилище, а обратный вызов возвращает вычисленное значение.

import { derived } from 'svelte/store';

const doubled = derived(a, $a => $a * 2);
END_OF_DOCUMENT_MARKER

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

В этом случае вы также можете передать третий аргумент в derived — начальное значение производного хранилища перед тем, как set будет вызван впервые.

import { derived } from 'svelte/store';

const delayed = derived(a, ($a, set) => {
	setTimeout(() => set($a), 1000);
}, 'one moment...');

Если вы вернете функцию из обратного вызова, она будет вызвана, когда а) обратный вызов выполнится снова или б) последний подписчик отпишется.

import { derived } from 'svelte/store';

const tick = derived(frequency, ($frequency, set) => {
	const interval = setInterval(() => {
	  set(Date.now());
	}, 1000 / $frequency);

	return () => {
		clearInterval(interval);
	};
}, 'one moment...');

В обоих случаях вместо одного хранилища можно передать массив аргументов в качестве первого аргумента.

import { derived } from 'svelte/store';

const summed = derived([a, b], ([$a, $b]) => $a + $b);

const delayed = derived([a, b], ([$a, $b], set) => {
	setTimeout(() => set($a + $b), 1000);
});

get

value: any = get(store)

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

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

import { get } from 'svelte/store';

const value = get(store);

svelte/motion

Модуль svelte/motion экспортирует две функции, tweened и spring, для создания изменяемых хранилищ, значения которых меняются со временем после set и update, а не сразу.

tweened

store = tweened(value: any, options)

Хранилища Tweened обновляют свои значения в течение фиксированного периода времени. Доступны следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды до старта
  • duration (number | function, по умолчанию 400) — миллисекунды, в течение которых длится анимация
  • easing (function, по умолчанию t => t) — функция сглаживания
  • interpolate (function) — см. ниже

store.set и store.update могут принимать второй аргумент — options, который переопределит параметры, переданные при инициализации.

Обе функции возвращают Promise, который разрешается, когда анимация завершается. Если анимация прервана, обещание никогда не разрешится.

По умолчанию Svelte интерполирует между двумя числами, двумя массивами или двумя объектами (пока массивы и объекты имеют одинаковую «форму», а их «листовые» свойства также являются числами).

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

	const size = tweened(1, {
		duration: 300,
		easing: cubicOut
	});

	function handleClick() {
		// this is equivalent to size.update(n => n + 1)
		$size += 1;
	}
</script>

<button
	on:click={handleClick}
	style="transform: scale({$size}); transform-origin: 0 0"
>embiggen</button>

Если начальное значение равно undefined или null, первое изменение значения вступит в силу немедленно. Это полезно, когда у вас есть значения tweened, основанные на параметрах, и вы не хотите никаких анимаций при первом рендеринге компонента.

const size = tweened(undefined, {
	duration: 300,
	easing: cubicOut
});

$: $size = big ? 100 : 10;

Параметр interpolate позволяет вам анимировать между любыми произвольными значениями. Он должен быть (a, b) => t => value функцией, где a — начальное значение, b — целевое значение, t — число от 0 до 1, а value — результат. Например, мы можем использовать пакет d3-interpolate для плавной интерполяции между двумя цветами.

<script>
	import { interpolateLab } from 'd3-interpolate';
	import { tweened } from 'svelte/motion';

	const colors = [
		'rgb(255, 62, 0)',
		'rgb(64, 179, 255)',
		'rgb(103, 103, 120)'
	];

	const color = tweened(colors[0], {
		duration: 800,
		interpolate: interpolateLab
	});
</script>

{#each colors as c}
	<button
		style="background-color: {c}; color: white; border: none;"
		on:click="{e => color.set(c)}"
	>{c}</button>
{/each}

<h1 style="color: {$color}">{$color}</h1>

spring

store = spring(value: any, options)

Хранилище spring постепенно изменяется на целевое значение, основанные на параметрах stiffness и damping. В то время как хранилища tweened изменяют свои значения в течение фиксированного периода времени, хранилища spring изменяются в течение периода времени, определяемого их текущей скоростью, что позволяет в многих ситуациях создавать более естественно выглядящие анимации. Доступны следующие параметры:

  • stiffness (number, по умолчанию 0.15) — значение от 0 до 1, где большее значение означает «более жёсткую» пружину
  • damping (number, по умолчанию 0.8) — значение от 0 до 1, где меньшее значение означает «более пружинистую» пружину
  • precision (number, по умолчанию 0.01) — определяет порог, при котором считается, что пружина «установилась», где меньшее значение означает более точную настройку

Все вышеперечисленные параметры можно изменить во время работы пружины, и они вступят в силу немедленно.

const size = spring(100);
size.stiffness = 0.3;
size.damping = 0.4;
size.precision = 0.005;

Как и хранилища tweened, set и update возвращают Promise, который разрешается, если пружина устанавливается.

И set, и update могут принимать второй аргумент — объект со свойствами hard или soft. { hard: true } устанавливает целевое значение немедленно; { soft: n } сохраняет существующий импульс на n секунды перед установкой. { soft: true } эквивалентно { soft: 0.5 }.

const coords = spring({ x: 50, y: 50 });
// updates the value immediately
coords.set({ x: 100, y: 200 }, { hard: true });
// preserves existing momentum for 1s
coords.update(
	(target_coords, coords) => {
		return { x: target_coords.x, y: coords.y };
	},
	{ soft: 1 }
);

См. полный пример в руководстве по пружинам.

<script>
	import { spring } from 'svelte/motion';

	const coords = spring({ x: 50, y: 50 }, {
		stiffness: 0.1,
		damping: 0.25
	});
</script>

Если начальное значение равно undefined или null, первое изменение значения вступит в силу немедленно, точно так же, как и для значений tweened (см. выше).

const size = spring();
$: $size = big ? 100 : 10;

svelte/transition

Модуль svelte/transition экспортирует семь функций: fade, blur, fly, slide, scale, draw и crossfade. Они предназначены для использования с Svelte transitions.

fade

transition:fade={params}
in:fade={params}
out:fade={params}

Анимирует непрозрачность элемента от 0 до текущей непрозрачности для переходов in и от текущей непрозрачности до 0 для переходов out.

fade принимает следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды до старта
  • duration (number, по умолчанию 400) — миллисекунды, в течение которых длится переход
  • easing (function, по умолчанию linear) — функция сглаживания

Вы можете увидеть переход fade в действии в руководстве по переходам.

<script>
	import { fade } from 'svelte/transition';
</script>

{#if condition}
	<div transition:fade="{{delay: 250, duration: 300}}">
		fades in and out
	</div>
{/if}

blur

transition:blur={params}
in:blur={params}
out:blur={params}

Анимирует фильтр blur вместе с непрозрачностью элемента.

blur принимает следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды до старта
  • duration (number, по умолчанию 400) — миллисекунды, в течение которых длится переход
  • easing (function, по умолчанию cubicInOut) — функция сглаживания
  • opacity (number, по умолчанию 0) - значение непрозрачности, до которого нужно анимировать и из которого
  • amount (number, по умолчанию 5) - размер размытия в пикселях
<script>
	import { blur } from 'svelte/transition';
</script>

{#if condition}
	<div transition:blur="{{amount: 10}}">
		fades in and out
	</div>
{/if}

fly

transition:fly={params}
in:fly={params}
out:fly={params}

Анимирует положение по осям x и y и непрозрачность элемента. in переходы анимируют изменение значений элемента с текущих (по умолчанию) на заданные в качестве параметров. out переходы анимируют изменение значений с заданных на значения по умолчанию элемента.

fly принимает следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды перед запуском
  • duration (number, по умолчанию 400) — миллисекунды, в течение которых длится переход
  • easing (function, по умолчанию cubicOut) — функция плавного изменения easing function
  • x (number, по умолчанию 0) - смещение по оси x, к которому осуществляется анимация
  • y (number, по умолчанию 0) - смещение по оси y, к которому осуществляется анимация
  • opacity (number, по умолчанию 0) - значение непрозрачности, к которому осуществляется анимация

Вы можете увидеть fly переход в действии в учебном пособии по переходам.

<script>
	import { fly } from 'svelte/transition';
	import { quintOut } from 'svelte/easing';
</script>

{#if condition}
	<div transition:fly="{{delay: 250, duration: 300, x: 100, y: 500, opacity: 0.5, easing: quintOut}}">
		flies in and out
	</div>
{/if}

slide

transition:slide={params}
in:slide={params}
out:slide={params}

Перемещает элемент влево и вправо.

slide принимает следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды перед запуском
  • duration (number, по умолчанию 400) — миллисекунды, в течение которых длится переход
  • easing (function, по умолчанию cubicOut) — функция плавного изменения easing function
<script>
	import { slide } from 'svelte/transition';
	import { quintOut } from 'svelte/easing';
</script>

{#if condition}
	<div transition:slide="{{delay: 250, duration: 300, easing: quintOut }}">
		slides in and out
	</div>
{/if}

scale

transition:scale={params}
in:scale={params}
out:scale={params}

Анимирует непрозрачность и масштаб элемента. in переходы анимируют изменение значений элемента с текущих (по умолчанию) на заданные в качестве параметров. out переходы анимируют изменение значений с заданных на значения по умолчанию элемента.

scale принимает следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды перед запуском
  • duration (number, по умолчанию 400) — миллисекунды, в течение которых длится переход
  • easing (function, по умолчанию cubicOut) — функция плавного изменения easing function
  • start (number, по умолчанию 0) - значение масштаба, к которому осуществляется анимация
  • opacity (number, по умолчанию 0) - значение непрозрачности, к которому осуществляется анимация
<script>
	import { scale } from 'svelte/transition';
	import { quintOut } from 'svelte/easing';
</script>

{#if condition}
	<div transition:scale="{{duration: 500, delay: 500, opacity: 0.5, start: 0.5, easing: quintOut}}">
		scales in and out
	</div>
{/if}

draw

transition:draw={params}
in:draw={params}
out:draw={params}

Анимирует обводку элемента SVG, как змею в трубе. in переходы начинаются с невидимой траектории и отображают её на экране со временем. out переходы начинаются в видимом состоянии и постепенно стирают траекторию. draw работает только с элементами, имеющими метод getTotalLength, например, <path> и <polyline>.

draw принимает следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды перед запуском
  • speed (number, по умолчанию undefined) - скорость анимации, см. ниже.
  • duration (number | function, по умолчанию 800) — миллисекунды, в течение которых длится переход
  • easing (function, по умолчанию cubicInOut) — функция плавного изменения easing function

Параметр speed задаёт продолжительность перехода относительно длины траектории. Это модификатор, применяемый к длине траектории: duration = length / speed. Для траектории длиной 1000 пикселей со скоростью 1 продолжительность составит 1000ms. Установка скорости на 0.5 удвоит эту продолжительность, а на 2 — уменьшит её вдвое.

<script>
	import { draw } from 'svelte/transition';
	import { quintOut } from 'svelte/easing';
</script>

<svg viewBox="0 0 5 5" xmlns="http://www.w3.org/2000/svg">
	{#if condition}
		<path transition:draw="{{duration: 5000, delay: 500, easing: quintOut}}"
					d="M2 1 h1 v1 h1 v1 h-1 v1 h-1 v-1 h-1 v-1 h1 z"
					fill="none"
					stroke="cornflowerblue"
					stroke-width="0.1px"
					stroke-linejoin="round"
		/>
	{/if}
</svg>

crossfade

Функция crossfade создаёт пару переходов под названием send и receive. Когда элемент «отправляется», он ищет соответствующий элемент «принятый» и генерирует переход, который преобразует элемент в позицию своего партнёра и затухает. Когда элемент «принимается», происходит обратное. Если соответствующего элемента нет, используется переход fallback.

crossfade принимает следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды перед запуском
  • duration (number | function, по умолчанию 800) — миллисекунды, в течение которых длится переход
  • easing (function, по умолчанию cubicOut) — функция плавного изменения easing function
  • fallback (function) — резервный переход для использования при отправке, когда нет соответствующего элемента приёма, и для приёма, когда нет элемента отправки.
<script>
	import { crossfade } from 'svelte/transition';
	import { quintOut } from 'svelte/easing';

	const [send, receive] = crossfade({
		duration:1500,
		easing: quintOut
	});
</script>

{#if condition}
	<h1 in:send={{key}} out:receive={{key}}>BIG ELEM</h1>
{:else}
	<small in:send={{key}} out:receive={{key}}>small elem</small>
{/if}

svelte/animate

Модуль svelte/animate экспортирует одну функцию для использования с Svelte анимациями.

flip

animate:flip={params}

Функция flip вычисляет начальную и конечную позицию элемента и анимирует переход между ними, транслируя значения x и y. flip означает First, Last, Invert, Play.

flip принимает следующие параметры:

  • delay (number, по умолчанию 0) — миллисекунды перед запуском
  • duration (number | function, по умолчанию d => Math.sqrt(d) * 120) — см. ниже
  • easing (function, по умолчанию cubicOut) — функция плавного изменения easing function

duration может быть предоставлена как:

  • число number, в миллисекундах.
  • функция distance: number => duration: number, получающая расстояние, которое элемент проедет в пикселях, и возвращающая продолжительность в миллисекундах. Это позволяет назначить продолжительность, относительную к пройденному расстоянию каждого элемента.

Вы можете увидеть полный пример на учебном пособии по анимациям

<script>
	import { flip } from 'svelte/animate';
	import { quintOut } from 'svelte/easing';

	let list = [1, 2, 3];
</script>

{#each list as n (n)}
	<div animate:flip="{{delay: 250, duration: 250, easing: quintOut}}">
		{n}
	</div>
{/each}

svelte/easing

Функции плавного изменения задают скорость изменения во времени и полезны при работе со встроенными переходами и анимациями Svelte, а также с утилитами tweened и spring. svelte/easing содержит 31 именованный экспорт, linear ease и 3 варианта 10 различных функций плавного изменения: in, out и inOut.

Вы можете изучить различные типы плавного изменения, используя визуализатор плавных изменений в разделе примеров.

ease in out inOut
back backIn backOut backInOut
bounce bounceIn bounceOut bounceInOut
circ circIn circOut circInOut
cubic cubicIn cubicOut cubicInOut
elastic elasticIn elasticOut elasticInOut
expo expoIn expoOut expoInOut
quad quadIn quadOut quadInOut
quart quartIn quartOut quartInOut
quint quintIn quintOut quintInOut
sine sineIn sineOut sineInOut

svelte/register

Для отрисовки компонентов Svelte в Node.js без объединения используйте require('svelte/register'). После этого можно использовать require для включения любого файла .svelte.

require('svelte/register');

const App = require('./App.svelte').default;

...

const { html, css, head } = App.render({ answer: 42 });

.default необходим, потому что мы конвертируем модули нативного JavaScript в модули CommonJS, распознаваемые Node.js. Обратите внимание, что если ваш компонент импортирует модули JavaScript, они не будут загружаться в Node.js, и вам потребуется использовать инструмент объединения.

Для установки параметров компиляции или использования пользовательского расширения файла вызовите метод register как функцию:

require('svelte/register')({
  extensions: ['.customextension'], // defaults to ['.html', '.svelte']
	preserveComments: true
});

API компонента клиентской стороны

Создание компонента

const component = new Component(options)

Компонент клиентской стороны — то есть компонент, скомпилированный с помощью generate: 'dom' (или параметр generate не указан) — это класс JavaScript.

import App from './App.svelte';

const app = new App({
	target: document.body,
	props: {
		// assuming App.svelte contains something like
		// `export let answer`:
		answer: 42
	}
});

Можно задать следующие параметры инициализации:

Параметр Значение по умолчанию Описание
target нет Элемент или фрагмент DOM для отрисовки. Этот параметр обязателен.
anchor null Дочерний элемент target для отрисовки компонента непосредственно перед ним.
props {} Объект свойств, которые нужно передать компоненту.
context new Map() Объект пар «ключ-значение» контекста корневого уровня для передачи компоненту.
hydrate false См. ниже
intro false Если true, переходы будут активированы при начальной отрисовке, а не ожидая последующих изменений состояния.

Существующие дочерние элементы target остаются на своих местах.

Параметр hydrate инструктирует Svelte обновить существующий DOM (обычно из рендеринга на стороне сервера), а не создавать новые элементы. Он будет работать только в том случае, если компонент был скомпилирован с параметром hydratable: true. Гидратация элементов <head> работает правильно только в том случае, если код рендеринга на стороне сервера также был скомпилирован с hydratable: true, который добавляет метку к каждому элементу в <head>, чтобы компонент знал, какие элементы нужно удалить во время гидратации.

В то время как дочерние элементы target обычно остаются без изменений, hydrate: true приведет к удалению всех дочерних элементов. По этой причине параметр anchor нельзя использовать вместе с hydrate: true.

Существующий DOM не должен соответствовать компоненту — Svelte будет «исправлять» DOM по мере необходимости.

import App from './App.svelte';

const app = new App({
	target: document.querySelector('#server-rendered-html'),
	hydrate: true
});

$set

component.$set(props)

Программно устанавливает свойства экземпляра. component.$set({ x: 1 }) эквивалентно x = 1 внутри блока <script> компонента.

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

component.$set({ answer: 42 });

$on

component.$on(event, callback)

Вызывает функцию callback всякий раз, когда компонент отправляет событие event.

Возвращается функция, которая удалит обработчик события при её вызове.

const off = app.$on('selected', event => {
	console.log(event.detail.selection);
});

off();

$destroy

component.$destroy()

Удаляет компонент из DOM и вызывает все обработчики onDestroy.

Свойства компонента

component.prop
component.prop = value

Если компонент скомпилирован с accessors: true, каждый экземпляр будет иметь геттеры и сеттеры, соответствующие каждому свойству компонента. Установка значения вызовет синхронное обновление, а не стандартное асинхронное обновление, вызываемое component.$set(...).

По умолчанию, accessors — false, если только вы не компилируете его как пользовательский элемент.

console.log(app.count);
app.count += 1;

API пользовательских элементов

Компоненты Svelte также можно скомпилировать в пользовательские элементы (также известные как веб-компоненты) с помощью параметра компилятора customElement: true. Для компонента необходимо указать имя тега с помощью элемента <svelte:options> element.

<svelte:options tag="my-element" />

<script>
	export let name = 'world';
</script>

<h1>Hello {name}!</h1>
<slot></slot>

В качестве альтернативы, используйте tag={null}, чтобы указать, что потребитель пользовательского элемента должен назвать его.

import MyElement from './MyElement.svelte';

customElements.define('my-element', MyElement);

После определения пользовательского элемента его можно использовать как обычный DOM-элемент:

document.body.innerHTML = `
	<my-element>
		<p>This is some slotted content</p>
	</my-element>
`;

По умолчанию пользовательские элементы компилируются с accessors: true, что означает, что все свойства экспонируются как свойства DOM-элемента (а также читабельны/записываемы как атрибуты, где это возможно).

Чтобы предотвратить это, добавьте accessors={false} в <svelte:options>.

const el = document.querySelector('my-element');

// get the current value of the 'name' prop
console.log(el.name);

// set a new value, updating the shadow DOM
el.name = 'everybody';

Пользовательские элементы могут быть полезным способом для упаковки компонентов для использования в приложении, не использующем Svelte, поскольку они будут работать с обычным HTML и JavaScript, а также с большинством фреймворков. Однако есть некоторые важные отличия:

  • Стили капсулированы, а не просто ограничены. Это означает, что любые стили, не относящиеся к компоненту (такие, как те, которые могут быть в файле global.css), не будут применяться к пользовательскому элементу, включая стили с модификатором :global(...)
  • Вместо того, чтобы быть извлечёнными в отдельный файл .css, стили встраиваются в компонент в виде строки JavaScript.
  • Пользовательские элементы обычно не подходят для рендеринга на стороне сервера, так как домен тени невидим до загрузки JavaScript.
  • В Svelte вложенный контент рендерится лениво. В DOM он рендерится немедленно. Другими словами, он всегда будет создан, даже если элемент компонента <slot> находится внутри блока {#if ...}. Аналогично, включение <slot> в блок {#each ...} не приведет к многократному рендерингу вложенного контента.
  • Директива let: не действует.
  • Для поддержки старых браузеров требуются полифилы.

API компонента серверной стороны

const result = Component.render(...)

В отличие от компонентов клиентской стороны, компоненты серверной стороны не имеют жизненного цикла после рендеринга — их единственная задача создать HTML и CSS. По этой причине API немного отличается.

Компонент серверной стороны предоставляет метод render, который можно вызвать с необязательными свойствами. Он возвращает объект со свойствами head, html и css, где head содержит содержимое любых элементов <svelte:head>, встреченных при рендеринге.

Вы можете импортировать компонент Svelte напрямую в Node с помощью svelte/register.

require('svelte/register');

const App = require('./App.svelte').default;

const { head, html, css } = App.render({
	answer: 42
});

Метод .render() принимает следующие параметры:

Параметр Значение по умолчанию Описание
props {} Объект свойств, которые нужно передать компоненту
options {} Объект опций

Объект options принимает следующие опции:

Параметр Значение по умолчанию Описание
context new Map() Объект пар «ключ-значение» контекста корневого уровня для передачи компоненту
const { head, html, css } = App.render(
	// props
	{ answer: 42 },
	// options
	{
		context: new Map([['context-key', 'context-value']])
	}
);
END_OF_DOCUMENT_MARKER

Время компиляции

Как правило, вы не будете взаимодействовать с компилятором Svelte напрямую, а вместо этого интегрируете его в свою систему сборки с помощью плагина сборки. Плагин сборки, который команда Svelte наиболее рекомендует и поддерживает, — это vite-plugin-svelte. Фреймворк SvelteKit предоставляет настройку, использующую vite-plugin-svelte для построения приложений, а также инструмент для паковки библиотек компонентов Svelte. Svelte Society поддерживает список других плагинов сборки для дополнительных инструментов, таких как Rollup и Webpack.

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

svelte.compile

result: {
	js,
	css,
	ast,
	warnings,
	vars,
	stats
} = svelte.compile(source: string, options?: {...})

Здесь происходит магия. svelte.compile принимает ваш исходный код компонента и преобразует его в JavaScript-модуль, который экспортирует класс.

const svelte = require('svelte/compiler');

const result = svelte.compile(source, {
	// options
});

Следующие параметры можно передать компилятору. Ни один из них не является обязательным:

Параметр Значение по умолчанию Описание
filename null string используется для подсказок отладки и sourcemap. Ваш плагин сборки установит его автоматически.
name "Component" string, устанавливающий имя результирующего JavaScript-класса (хотя компилятор переименует его, если это необходимо, чтобы избежать конфликта с другими переменными в области видимости). Обычно он выводится из filename.
format "esm" Если "esm", создаёт JavaScript-модуль (с import и export). Если "cjs", создаёт модуль CommonJS (с require и module.exports), что полезно в некоторых ситуациях с рендерингом на стороне сервера или для тестирования.
generate "dom" Если "dom", Svelte генерирует JavaScript-класс для монтирования в DOM. Если "ssr", Svelte генерирует объект с методом render, подходящим для рендеринга на стороне сервера. Если false, JavaScript и CSS не возвращаются; возвращаются только метаданные.
errorMode "throw" Если "throw", Svelte выбрасывает ошибку при возникновении ошибки компиляции. Если "warn", Svelte будет рассматривать ошибки как предупреждения и добавлять их в отчет о предупреждениях.
varsReport "strict" Если "strict", Svelte возвращает отчет о переменных, содержащий только переменные, которые не являются глобальными или внутренними. Если "full", Svelte возвращает отчет о переменных, содержащий все обнаруженные переменные. Если false, отчет о переменных не возвращается.
dev false Если true, добавляет дополнительный код в компоненты, которые будут выполнять проверки во время выполнения и предоставлять отладочную информацию во время разработки.
immutable false Если true, сообщает компилятору, что вы гарантируете, что не будете изменять какие-либо объекты. Это позволяет ему быть менее консервативным при проверке изменений значений.
hydratable false Если true при генерации кода DOM, включает опцию runtime hydrate: true, которая позволяет компоненту обновлять существующий DOM, а не создавать новый DOM с нуля. При генерации кода SSR добавляет маркеры к элементам <head>, чтобы регидрация знала, какие нужно заменить.
legacy false Если true, генерирует код, который будет работать в IE9 и IE10, которые не поддерживают такие вещи, как element.dataset.
accessors false Если true, создаются геттеры и сеттеры для свойств компонента. Если false, они создаются только для экспортируемых значений только для чтения (т.е. тех, которые объявлены с помощью const, class и function). При компиляции с customElement: true этот параметр по умолчанию равен true.
customElement false Если true, сообщает компилятору сгенерировать конструктор пользовательского элемента вместо обычного компонента Svelte.
tag null Строка, указывающая Svelte имя тега для регистрации пользовательского элемента. Должна быть строкой с нижним регистром, содержащей только буквенно-цифровые символы и, по крайней мере, один дефис, например, "my-element".
css 'injected' Если 'injected' (ранее true), стили будут включены в JavaScript-класс и внедрены во время выполнения для реально отрисованных компонентов. Если 'external' (ранее false), CSS будет возвращен в поле css результата компиляции. Большинство плагинов сборки Svelte установят это значение в 'external' и будут использовать статически сгенерированный CSS для лучшей производительности, так как это приведет к меньшим JavaScript-пакетам, а вывод можно будет обслуживать как кешируемые файлы .css. Если 'none', стили полностью игнорируются, и CSS-вывод не генерируется.
cssHash См. справа Функция, которая принимает аргумент { hash, css, name, filename } и возвращает строку, используемую в качестве имени класса для отформатированных стилей. По умолчанию возвращает svelte-${hash(css)}
loopGuardTimeout 0 Число, указывающее Svelte прервать цикл, если он блокирует поток более чем на loopGuardTimeout мс. Это полезно для предотвращения бесконечных циклов. Доступно только при dev: true
preserveComments false Если true, ваши HTML-комментарии сохранятся при рендеринге на стороне сервера. По умолчанию они удаляются.
preserveWhitespace false Если true, пробелы внутри и между элементами сохраняются так, как вы их ввели, а не удаляются или сводятся к одному пробелу, где это возможно.
sourcemap object | string Исходный sourcemap, который будет объединен в конечный выходной sourcemap. Обычно это sourcemap препроцессора.
enableSourcemap boolean | { js: boolean; css: boolean; } Если true, Svelte генерирует sourcemap для компонентов. Используйте объект с js или css для более точного управления генерацией sourcemap. По умолчанию это true.
outputFilename null Sourcemap для JavaScript-кода.
cssOutputFilename null Sourcemap для CSS-кода.
sveltePath "svelte" Расположение пакета svelte. Все импорты из svelte или svelte/[module] будут изменены соответственно.
namespace "html" Пространство имён элемента; например, "mathml", "svg", "foreign".

Возвращаемый result объект содержит код вашего компонента вместе с полезными метаданными.

const {
	js,
	css,
	ast,
	warnings,
	vars,
	stats
} = svelte.compile(source);
  • js и css — объекты со следующими свойствами:
    • code — строка JavaScript
    • map — карта исходных позиций с дополнительными удобными методами toString() и toUrl()
  • ast — абстрактное синтаксическое дерево, представляющее структуру вашего компонента.
  • warnings — массив объектов предупреждений, сгенерированных во время компиляции. Каждое предупреждение имеет несколько свойств:
    • code — строка, определяющая категорию предупреждения
    • message — описание проблемы в удобочитаемой форме
    • start и end, если предупреждение относится к определённому месту, — объекты со свойствами line, column и character
    • frame, применимо, — строка, выделяющая проблемный код с номерами строк
  • vars — массив деклараций компонента, используемый, например, eslint-plugin-svelte3. Каждая переменная имеет несколько свойств:
    • name — очевидно
    • export_name — имя, под которым значение экспортируется, если оно экспортировано (должно совпадать с name, если вы не используете export...as)
    • injected — true, если декларация вставлена Svelte, а не написана вами
    • module — true, если значение объявлено в блоке скрипта context="module"
    • mutated — true, если свойства значения присваиваются внутри компонента
    • reassigned — true, если значение переопределяется внутри компонента
    • referenced — true, если значение используется в шаблоне
    • referenced_from_script — true, если значение используется в <script> вне объявления
    • writable — true, если значение объявлено с использованием let или var (но не const, class или function)
  • stats — объект, используемый командой разработчиков Svelte для диагностики компилятора. Не полагайтесь на его неизменность!

svelte.parse

ast: object = svelte.parse(
	source: string,
	options?: {
		filename?: string,
		customElement?: boolean
	}
)

Функция parse парсит компонент, возвращая только его абстрактное синтаксическое дерево. В отличие от компиляции с опцией generate: false, она не будет выполнять никакой валидации или другого анализа компонента, кроме его разбора. Обратите внимание, что возвращаемое АСД не считается общедоступным API, поэтому могут произойти изменения в любой момент.

const svelte = require('svelte/compiler');

const ast = svelte.parse(source, { filename: 'App.svelte' });

svelte.preprocess

Доступно множество поддерживаемых сообществом плагинов предобработки, позволяющих использовать Svelte с инструментами, такими как TypeScript, PostCSS, SCSS и Less.

Вы можете написать свой собственный препроцессор, используя API svelte.preprocess.

result: {
	code: string,
	dependencies: Array<string>
} = await svelte.preprocess(
	source: string,
	preprocessors: Array<{
		markup?: (input: { content: string, filename: string }) => Promise<{
			code: string,
			dependencies?: Array<string>
		}>,
		script?: (input: { content: string, markup: string, attributes: Record<string, string>, filename: string }) => Promise<{
			code: string,
			dependencies?: Array<string>
		}>,
		style?: (input: { content: string, markup: string, attributes: Record<string, string>, filename: string }) => Promise<{
			code: string,
			dependencies?: Array<string>
		}>
	}>,
	options?: {
		filename?: string
	}
)

Функция preprocess предоставляет удобные средства для произвольного преобразования исходного кода компонента. Например, она может использоваться для преобразования блока <style lang="sass"> в обычный CSS.

Первый аргумент — исходный код компонента. Второй — массив препроцессоров (или один препроцессор, если у вас только один), где препроцессор — это объект со свойствами markup, script и style, каждое из которых необязательно.

Каждая функция markup, script или style должна возвращать объект (или обещание, разрешающее объект) со свойством code, представляющим преобразованный исходный код, и необязательным массивом dependencies.

Функция markup получает весь текст исходного кода компонента вместе с filename, если он был указан в третьем аргументе.

Функции препроцессора должны дополнительно возвращать объект map вместе с code и dependencies, где map — карта исходных позиций, представляющая преобразование.

const svelte = require('svelte/compiler');
const MagicString = require('magic-string');

const { code } = await svelte.preprocess(source, {
	markup: ({ content, filename }) => {
		const pos = content.indexOf('foo');
		if(pos < 0) {
			return { code: content }
		}
		const s = new MagicString(content, { filename })
		s.overwrite(pos, pos + 3, 'bar', { storeName: true })
		return {
			code: s.toString(),
			map: s.generateMap()
		}
	}
}, {
	filename: 'App.svelte'
});

Функции script и style получают содержимое элементов <script> и <style> соответственно (content), а также весь исходный текст компонента (markup). В дополнение к filename, они получают объект атрибутов элемента.

Если возвращается массив dependencies, он будет включён в результирующий объект. Это используется пакетами, такими как rollup-plugin-svelte, для отслеживания дополнительных файлов на предмет изменений в случае, если у вашего тега <style> есть атрибут @import (например).

const svelte = require('svelte/compiler');
const sass = require('node-sass');
const { dirname } = require('path');

const { code, dependencies } = await svelte.preprocess(source, {
	style: async ({ content, attributes, filename }) => {
		// only process <style lang="sass">
		if (attributes.lang !== 'sass') return;

		const { css, stats } = await new Promise((resolve, reject) => sass.render({
			file: filename,
			data: content,
			includePaths: [
				dirname(filename),
			],
		}, (err, result) => {
			if (err) reject(err);
			else resolve(result);
		}));

		return {
			code: css.toString(),
			dependencies: stats.includedFiles
		};
	}
}, {
	filename: 'App.svelte'
});

Несколько препроцессоров могут использоваться вместе. Выход первого становится входом для второго. Функции markup выполняются первыми, затем script и style.

const svelte = require('svelte/compiler');

const { code } = await svelte.preprocess(source, [
	{
		markup: () => {
			console.log('this runs first');
		},
		script: () => {
			console.log('this runs third');
		},
		style: () => {
			console.log('this runs fifth');
		}
	},
	{
		markup: () => {
			console.log('this runs second');
		},
		script: () => {
			console.log('this runs fourth');
		},
		style: () => {
			console.log('this runs sixth');
		}
	}
], {
	filename: 'App.svelte'
});

svelte.walk

walk(ast: Node, {
	enter(node: Node, parent: Node, prop: string, index: number)?: void,
	leave(node: Node, parent: Node, prop: string, index: number)?: void
})

Функция walk предоставляет способ обхода абстрактных синтаксических деревьев, сгенерированных парсером, используя собственный встроенный экземпляр estree-walker.

Обходник принимает абстрактное синтаксическое дерево для обхода и объект с двумя необязательными методами: enter и leave. Для каждого узла вызывается enter (если присутствует). Затем, если this.skip() не вызывается во время enter, каждый из дочерних узлов просматривается, а затем вызывается leave для узла.

const svelte = require('svelte/compiler');
svelte.walk(ast, {
	enter(node, parent, prop, index) {
		do_something(node);
		if (should_skip_children(node)) {
			this.skip();
		}
	},
	leave(node, parent, prop, index) {
		do_something_else(node);
	}
});

svelte.VERSION

Текущая версия, установленная в package.json.

const svelte = require('svelte/compiler');
console.log(`running svelte version ${svelte.VERSION}`);
END_OF_DOCUMENT_MARKER

Предупреждения по обеспечению доступности

Обеспечение доступности (сокращенно a11y) не всегда легко реализовать, но Svelte поможет, предупреждая вас во время компиляции, если вы создаете разметку с проблемами доступности. Однако помните, что многие проблемы доступности можно определить только во время выполнения, используя другие автоматизированные инструменты, а также путем ручного тестирования вашего приложения.

Ниже приведен список проверок доступности, которые выполнит Svelte.

a11y-accesskey

Запрещено использование accesskey на элементе. Кодовые клавиши — это атрибуты HTML, которые позволяют веб-разработчикам назначать ярлыки для элементов. Несоответствия между кодовыми клавишами и командами клавиатуры, используемыми программами-скринридерами и пользователями, работающими только с клавиатурой, создают проблемы с доступностью. Чтобы избежать проблем, следует воздержаться от использования кодовых клавиш.

<!-- A11y: Avoid using accesskey -->
<div accessKey='z'></div>

a11y-aria-attributes

Некоторые зарезервированные элементы DOM не поддерживают ARIA-роли, состояния и свойства. Это часто связано с тем, что они не отображаются, например, meta, html, script, style. Это правило требует, чтобы эти элементы DOM не содержали aria-* атрибутов.

<!-- A11y: <meta> should not have aria-* attributes -->
<meta aria-hidden="false">

a11y-autofocus

Запрещено использование autofocus на элементах. Автофокусировка элементов может вызвать проблемы с удобством использования как для пользователей с нормальным зрением, так и для пользователей с нарушениями зрения.

<!-- A11y: Avoid using autofocus -->
<input autofocus>

a11y-click-events-have-key-events

Требуется, чтобы on:click сопровождались по крайней мере одним из следующих: onKeyUp, onKeyDown, onKeyPress. Кодирование с учётом клавиатуры важно для пользователей с физическими ограничениями, которые не могут использовать мышь, для совместимости с средствами доступности и для пользователей, использующих программы-скринридеры.

Это не относится к интерактивным или скрытым элементам.

<!-- A11y: visible, non-interactive elements with an on:click event must be accompanied by an on:keydown, on:keyup, or on:keypress event. -->
<div on:click={() => {}} />

a11y-distracting-elements

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

К визуально отвлекающим элементам относятся: <marquee> и <blink>.

<!-- A11y: Avoid <marquee> elements -->
<marquee />

a11y-hidden

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

<!-- A11y: <h2> element should not be hidden -->
<h2 aria-hidden="true">invisible header</h2>

a11y-img-redundant-alt

Требуется, чтобы атрибут alt тега img не содержал слова image, picture или photo. Программы-скринридеры уже объявляют элементы img как изображение. Нет необходимости использовать такие слова, как изображение, фото и/или картинка.

<img src="foo" alt="Foo eating a sandwich." />

<!-- aria-hidden, won't be announced by screen reader -->
<img src="bar" aria-hidden="true" alt="Picture of me taking a photo of an image" />

<!-- A11y: Screen readers already announce <img> elements as an image. -->
<img src="foo" alt="Photo of foo being weird." />

<!-- A11y: Screen readers already announce <img> elements as an image. -->
<img src="bar" alt="Image of me at a bar!" />

<!-- A11y: Screen readers already announce <img> elements as an image. -->
<img src="foo" alt="Picture of baz fixing a bug." />

a11y-incorrect-aria-attribute-type

Требуется использование только правильного типа значения для атрибутов aria. Например, aria-hidden должен принимать только булево значение.

<!-- A11y: The value of 'aria-hidden' must be exactly one of true or false -->
<div aria-hidden="yes"/>

a11y-invalid-attribute

Требуется, чтобы атрибуты, важные для доступности, имели допустимое значение. Например, href не должен быть пустым, '#' или javascript:.

<!-- A11y: '' is not a valid href attribute -->
<a href=''>invalid</a>

a11y-label-has-associated-control

Требуется, чтобы тег label имел текстовую метку и связанный элемент управления.

Существует два поддерживаемых способа связывания метки с элементом управления:

  • Оборачивание элемента управления в тег label.
  • Добавление for к тегу label и присвоение ему идентификатора входного элемента на странице.
<label for="id">B</label>

<label>C <input type="text" /></label>

<!-- A11y: A form label must be associated with a control. -->
<label>A</label>

a11y-media-has-caption

Обеспечение субтитров для медиаконтента очень важно для глухих пользователей, чтобы они могли следить за происходящим. Субтитры должны представлять собой транскрипцию или перевод диалога, звуковых эффектов, соответствующих музыкальных фрагментов и другой релевантной аудиоинформации. Это важно не только для доступности, но и может быть полезно для всех пользователей в случае, если медиаконтент недоступен (аналогично alt тексту на изображении, если изображение не загружается).

Субтитры должны содержать всю важную и релевантную информацию для понимания соответствующего медиаконтента. Это может означать, что субтитры не являются точным отображением диалога в медиаконтенте. Однако субтитры не нужны для видеокомпонентов с атрибутом muted.

<video><track kind="captions"/></video>

<audio muted></audio>

<!-- A11y: Media elements must have a <track kind=\"captions\"> -->
<video></video>

<!-- A11y: Media elements must have a <track kind=\"captions\"> -->
<video><track /></video>

a11y-misplaced-role

Некоторые зарезервированные элементы DOM не поддерживают ARIA-роли, состояния и свойства. Это часто связано с тем, что они не отображаются, например, meta, html, script, style. Это правило требует, чтобы эти элементы DOM не содержали role атрибутов.

<!-- A11y: <meta> should not have role attribute -->
<meta role="tooltip">

a11y-misplaced-scope

Атрибут scope следует использовать только для элементов <th>.

<!-- A11y: The scope attribute should only be used with <th> elements -->
<div scope="row" />

a11y-missing-attribute

Требуется, чтобы на элементе присутствовали атрибуты, необходимые для доступности. Это включает в себя следующие проверки:

  • <a> должен иметь href (если это не тег, определяющий фрагмент)
  • <area> должен иметь alt, aria-label или aria-labelledby
  • <html> должен иметь lang
  • <iframe> должен иметь title
  • <img> должен иметь alt
  • <object> должен иметь title, aria-label или aria-labelledby
  • <input type="image"> должен иметь alt, aria-label или aria-labelledby
<!-- A11y: <input type=\"image\"> element should have an alt, aria-label or aria-labelledby attribute -->
<input type="image">

<!-- A11y: <html> element should have a lang attribute -->
<html></html>

<!-- A11y: <a> element should have an href attribute -->
<a>text</a>

a11y-missing-content

Требуется, чтобы заголовки (h1, h2 и т.д.) и ссылки имели содержимое, доступное для программ-скринридеров.

<!-- A11y: <a> element should have child content -->
<a href='/foo'></a>

<!-- A11y: <h1> element should have child content -->
<h1></h1>

a11y-mouse-events-have-key-events

Требуется, чтобы on:mouseover и on:mouseout сопровождались on:focus и on:blur соответственно. Это помогает гарантировать, что любая функциональность, запускаемая этими событиями мыши, также доступна пользователям клавиатуры.

<!-- A11y: on:mouseover must be accompanied by on:focus -->
<div on:mouseover={handleMouseover} />

<!-- A11y: on:mouseout must be accompanied by on:blur -->
<div on:mouseout={handleMouseout} />

a11y-no-redundant-roles

У некоторых элементов HTML есть стандартные ARIA-роли. Присвоение этим элементам ARIA-роли, которая уже задана браузером не оказывает никакого эффекта и является избыточным.

<!-- A11y: Redundant role 'button' -->
<button role="button" />

<!-- A11y: Redundant role 'img' -->
<img role="img" src="foo.jpg" />

a11y-no-interactive-element-to-noninteractive-role

WAI-ARIA роли не должны использоваться для преобразования интерактивного элемента в неинтерактивный. Неинтерактивные ARIA роли включают article, banner, complementary, img, listitem, main, region и tooltip.

<!-- A11y: <textarea> cannot have role 'listitem' -->
<textarea role="listitem" />

a11y-no-noninteractive-tabindex

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

<!-- A11y: noninteractive element cannot have nonnegative tabIndex value -->
<div tabindex='0' />

a11y-positive-tabindex

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

<!-- A11y: avoid tabindex values above zero -->
<div tabindex='1'/>

a11y-role-has-required-aria-props

Элементы с ARIA-ролями должны иметь все необходимые атрибуты для этой роли.

<!-- A11y: A11y: Elements with the ARIA role "checkbox" must have the following attributes defined: "aria-checked" -->
<span role="checkbox" aria-labelledby="foo" tabindex="0"></span>

a11y-structure

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

<!-- A11y: <figcaption> must be an immediate child of <figure> -->
<div>
	<figcaption>Image caption</figcaption>
</div>

Предупреждения об удобочитаемости: неизвестный атрибут ARIA

Требуется, чтобы использовались только известные атрибуты ARIA. Основано на спецификации WAI-ARIA Состояния и свойства.

<!-- A11y: Unknown aria attribute 'aria-labeledby' (did you mean 'labelledby'?) -->
<input type="image" aria-labeledby="foo">

Предупреждения об удобочитаемости: неизвестная роль ARIA

Элементы с ролью ARIA должны использовать действительную, не абстрактную роль ARIA. Справочник по определениям ролей можно найти на сайте WAI-ARIA.

<!-- A11y: Unknown role 'toooltip' (did you mean 'tooltip'?) -->
<div role="toooltip"></div>

© 2016–2022 Rich Harris and contributors
Licensed under the MIT License.
https://svelte.dev/docs

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API