Skip to main content

模板语法

元素指令

除了属性之外,元素还可以具有指令,它们以某种方式控制元素的行为。

As well as attributes, elements can have directives, which control the element's behaviour in some way.

on:事件名称(on:eventname)

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

使用 on: 指令来监听 DOM 事件。

Use the on: directive to listen to DOM events.

App.svelte
<script>
	let count = 0;

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

<button on:click={handleClick}>
	count: {count}
</button>
App.svelte
<script lang="ts">
	let count = 0;
	
	function handleClick(event: MouseEvent) {
		count += 1;
	}
</script>

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

可以将处理程序声明为内联,而不会造成性能损失。 与属性一样,为了语法高亮,可以引用指令值。

Handlers can be declared inline with no performance penalty. As with attributes, directive values may be quoted for the sake of syntax highlighters.

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

使用 | 字符向 DOM 事件添加修饰符。

Add modifiers to DOM events with the | character.

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

可以使用以下修饰符:

The following modifiers are available:

  • preventDefault — 在运行处理程序之前调用 event.preventDefault()
  • stopPropagation — 调用 event.stopPropagation(),阻止事件到达下一个元素
  • stopImmediatePropagation - 调用 event.stopImmediatePropagation(),防止同一事件的其他监听器被触发。
  • passive — 提高了触摸/滚轮事件的滚动性能(Svelte 会在安全的情况下自动添加它)
  • nonpassive — 显式设置 passive: false
  • capture — 在捕获阶段而不是冒泡阶段触发处理程序
  • once — 第一次运行后删除处理程序
  • self — 仅当 event.target 是元素本身时才触发处理程序
  • trusted — 仅当 event.isTrustedtrue 时才触发处理程序。 IE。 如果事件是由用户操作触发的。

修饰符可以链接在一起,例如 on:click|once|capture={...}

Modifiers can be chained together, e.g. on:click|once|capture={...}.

如果使用不带值的 on: 指令,组件将转发事件,这意味着组件的使用者可以监听该事件。

If the on: directive is used without a value, the component will forward the event, meaning that a consumer of the component can listen for it.

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

同一个事件可以有多个事件监听器:

It's possible to have multiple event listeners for the same event:

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

	/** @param {MouseEvent} event */
	function track(event) {
		trackEvent(event);
	}
</script>

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

bind:属性(bind:property)

bind:property={variable}

数据通常从父级向下流动到子级。 bind: 指令允许数据以另一种方式流动,从子级流向父级。 大多数绑定特定于特定元素。

Data ordinarily flows down, from parent to child. The bind: directive allows data to flow the other way, from child to parent. Most bindings are specific to particular elements.

最简单的绑定反映属性的值,例如 input.value

The simplest bindings reflect the value of a property, such as input.value.

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

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

如果名称与值匹配,则可以使用简写。

If the name matches the value, you can use a shorthand.

<input bind:value />
<!-- equivalent to
<input bind:value={value} />
-->

数字输入值被强制; 即使 input.value 就 DOM 而言是一个字符串,Svelte 也会将其视为数字。 如果输入为空或无效(在 type="number" 的情况下),则值为 undefined

Numeric input values are coerced; even though input.value is a string as far as the DOM is concerned, Svelte will treat it as a number. If the input is empty or invalid (in the case of type="number"), the value is undefined.

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

在带有 type="file"<input> 元素上,你可以使用 bind:files 来获取 所选文件的 FileList。 它是只读的。

On <input> elements with type="file", you can use bind:files to get the FileList of selected files. It is readonly.

<label for="avatar">Upload a picture:</label>
<input accept="image/png, image/jpeg" bind:files id="avatar" name="avatar" type="file" />

如果将 bind: 指令与 on: 指令一起使用,则它们的定义顺序会影响调用事件处理程序时绑定变量的值。

If you're using bind: directives together with on: directives, the order that they're defined in affects the value of the bound variable when the event handler is called.

<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

Here we were binding to the value of a text input, which uses the input event. Bindings on other elements may use different events such as change.

绑定 <select> 值(Binding <select> value)

<select> 值绑定对应于所选 <option> 上的 value 属性,该属性可以是任何值(不仅仅是字符串,如 DOM 中通常的情况)。

A <select> value binding corresponds to the value property on the selected <option>, which can be any value (not just strings, as is normally the case in the DOM).

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

<select multiple> 元素的行为与复选框组类似。 绑定变量是一个数组,其中的条目对应于每个选定的 <option>value 属性。

A <select multiple> element behaves similarly to a checkbox group. The bound variable is an array with an entry corresponding to the value property of each selected <option>.

<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> 的值与其文本内容匹配时,可以省略该属性。

When the value of an <option> matches its text content, the attribute can be omitted.

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

具有 contenteditable 属性的元素支持以下绑定:

Elements with the contenteditable attribute support the following bindings:

其中每一个之间都存在细微差别,请阅读有关它们的更多信息 here

There are slight differences between each of these, read more about them here.

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

<details> 元素支持绑定到 open 属性。

<details> elements support binding to the open property.

<details bind:open={isOpen}>
	<summary>Details</summary>
	<p>Something small enough to escape casual notice.</p>
</details>

媒体元素绑定(Media element bindings)

媒体元素(<audio><video>)有自己的一组绑定 — 七个只读...

Media elements (<audio> and <video>) have their own set of bindings — seven readonly ones...

  • duration (只读) — 视频的总时长(以秒为单位)
  • buffered (只读) — {start, end} 对象的数组
  • played (只读) — ditto
  • seekable (只读) — ditto
  • seeking (只读) — boolean
  • ended (只读) — boolean
  • readyState (只读) — 0 到 4(含)之间的数字

...和五个双向绑定:

...and five two-way bindings:

  • currentTime — 视频当前播放时间,以秒为单位
  • playbackRate — 播放视频的速度有多快或多慢,其中 1 是 'normal'
  • paused — 这个应该是不言自明的
  • volume — 0 到 1 之间的值
  • muted — 指示玩家是否静音的布尔值

视频还具有只读 videoWidthvideoHeight 绑定。

Videos additionally have readonly videoWidth and videoHeight bindings.

<video
	src={clip}
	bind:duration
	bind:buffered
	bind:played
	bind:seekable
	bind:seeking
	bind:ended
	bind:readyState
	bind:currentTime
	bind:playbackRate
	bind:paused
	bind:volume
	bind:muted
	bind:videoWidth
	bind:videoHeight
/>

图片元素绑定(Image element bindings)

图片元素 (<img>) 有两个只读绑定:

Image elements (<img>) have two readonly bindings:

  • naturalWidth (只读) — 图片的原始宽度,图片加载后可用
  • naturalHeight (只读) — 图片的原始高度,图片加载后可用
<img
	bind:naturalWidth
	bind:naturalHeight
></img>

块级元素绑定(Block-level element bindings)

块级元素有 4 个只读绑定,使用类似于 这个 的技术进行测量:

Block-level elements have 4 read-only bindings, measured using a technique similar to this one:

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

bind:group

bind:group={variable}

一起工作的输入可以使用 bind:group

Inputs that work together can use bind:group.

<script>
	let tortilla = 'Plain';

	/** @type {Array<string>} */
	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)" />

仅当输入位于同一 Svelte 组件中时,bind:group 才有效。

bind:this

bind:this={dom_node}

要获取对 DOM 节点的引用,请使用 bind:this

To get a reference to a DOM node, use bind:this.

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

	/** @type {HTMLCanvasElement} */
	let canvasElement;

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

<canvas bind:this={canvasElement} />

class:名称(class:name)

class:name={value}
class:name

class: 指令提供了一种在元素上切换类的更短方法。

A class: directive provides a shorter way of toggling a class on an element.

<!-- These are equivalent -->
<div class={isActive ? 'active' : ''}>...</div>
<div class:active={isActive}>...</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)

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

style: 指令提供了在元素上设置多种样式的简写。

The style: directive provides a shorthand for setting multiple styles on an element.

<!-- 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 属性组合时,指令将优先:

When style: directives are combined with style attributes, the directives will take precedence:

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

use:动作(use:action)

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

操作是创建元素时调用的函数。 它们可以使用 destroy 方法返回一个对象,该方法在卸载元素后调用:

Actions are functions that are called when an element is created. They can return an object with a destroy method that is called after the element is unmounted:

<script>
	/** @type {import('svelte/action').Action}  */
	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 />

一个动作可以有一个参数。 如果返回值具有 update 方法,则只要该参数发生更改,即在 Svelte 对标记应用更新后,就会立即调用该方法。

An action can have a parameter. If the returned value has an update method, it will be called whenever that parameter changes, immediately after Svelte has applied updates to the markup.

不要担心我们为每个组件实例重新声明 foo 函数 — Svelte 会将任何不依赖于本地状态的函数提升到组件定义之外。

<script>
	export let bar;

	/** @type {import('svelte/action').Action}  */
	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} />

请阅读 svelte/action 页了解更多信息。

Read more in the svelte/action page.

transition:函数(transition:fn)

transition:fn
transition:fn={params}
transition:fn|global
transition:fn|global={params}
transition:fn|local
transition:fn|local={params}
ts
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,从而触发转换。

A transition is triggered by an element entering or leaving the DOM as a result of a state change.

当块转场出去时,块内的所有元素(包括那些没有自己的转场的元素)都会保留在 DOM 中,直到块中的每个转场完成为止。

When a block is transitioning out, all elements inside the block, including those that do not have their own transitions, are kept in the DOM until every transition in the block has been completed.

transition: 指令表示双向转换,这意味着在转换过程中可以平滑地反转。

The transition: directive indicates a bidirectional transition, which means it can be smoothly reversed while the transition is in progress.

{#if visible}
	<div transition:fade>fades in and out</div>
{/if}

默认情况下,转场是局部的(在 Svelte 3 中,默认情况下它们是全局的)。 局部转场仅在创建或销毁它们所属的块时播放,而不是在创建或销毁父块时播放。

Transitions are local by default (in Svelte 3, they were global by default). Local transitions only play when the block they belong to is created or destroyed, not when parent blocks are created or destroyed.

{#if x}
	{#if y}
		<!-- Svelte 3: <p transition:fade|local> -->
		<p transition:fade>fades in and out only when y changes</p>

		<!-- Svelte 3: <p transition:fade> -->
		<p transition:fade|global>fades in and out when x or y change</p>
	{/if}
{/if}

默认情况下,介绍转场不会在第一次渲染时播放。 你可以通过在 创建一个组件 时设置 intro: true 并将转换标记为 global 来修改此行为。

转场参数(Transition parameters)

与动作一样,转换也可以有参数。

Like actions, transitions can have parameters.

(双 {{curlies}} 不是特殊语法;这是表达式标记内的对象字面量。)

(The double {{curlies}} aren't a special syntax; this is an object literal inside an expression tag.)

{#if visible}
	<div transition:fade={{ duration: 2000 }}>fades in and out over two seconds</div>
{/if}

自定义转场函数(Custom transition functions)

转换可以使用自定义函数。 如果返回的对象具有 css 函数,Svelte 将创建在元素上播放的 CSS 动画。

Transitions can use custom functions. If the returned object has a css function, Svelte will create a CSS animation that plays on the element.

应用 easing 函数后,传递给 csst 参数是 01 之间的值。 在转换中从 0 运行到 1,输出转换从 1 运行到 0 — 换句话说,1 是元素的自然状态,就好像没有应用任何转换一样。 u 参数等于 1 - t

The t argument passed to css is a value between 0 and 1 after the easing function has been applied. In transitions run from 0 to 1, out transitions run from 1 to 0 — in other words, 1 is the element's natural state, as though no transition had been applied. The u argument is equal to 1 - t.

在转换开始之前,使用不同的 tu 参数重复调用该函数。

The function is called repeatedly before the transition begins, with different t and u arguments.

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

	/** @type {boolean} */
	export let visible;

	/**
	 * @param {HTMLElement} node
	 * @param {{ delay?: number, duration?: number, easing?: (t: number) => number }} params
	 */
	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 函数,该函数在转换期间使用相同的 tu 参数调用。

A custom transition function can also return a tick function, which is called during the transition with the same t and u arguments.

如果可以使用 css 代替 tick,请这样做 — CSS 动画可以脱离主线程运行,从而防止在速度较慢的设备上出现卡顿。

App.svelte
<script>
	export let visible = false;

	/**
	 * @param {HTMLElement} node
	 * @param {{ speed?: number }} params
	 */
	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}
App.svelte
<script lang="ts">
	export let visible = false;
	
	function typewriter(node: HTMLElement, { speed = 1 }: { speed?: number }) {
		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}

如果转换返回一个函数而不是转换对象,则该函数将在下一个微任务中调用。 这允许多个转换进行协调,从而使 交叉淡入淡出效果 成为可能。

If a transition returns a function instead of a transition object, the function will be called in the next microtask. This allows multiple transitions to coordinate, making crossfade effects possible.

转换函数还接收第三个参数 options,其中包含有关转换的信息。

Transition functions also receive a third argument, options, which contains information about the transition.

options 对象中的可用值为:

Available values in the options object are:

  • direction - inoutboth 之一,具体取决于转换类型

转场事件(Transition events)

除了任何标准 DOM 事件之外,具有转换的元素还将调度以下事件:

An element with transitions will dispatch the following events in addition to any standard DOM events:

  • 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}

in:fn/out:fn

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

transition: 类似,但仅适用于进入 (in:) 或离开 (out:) DOM 的元素。

Similar to transition:, but only applies to elements entering (in:) or leaving (out:) the DOM.

transition: 不同,in:out: 所应用的转换不是双向的 — 如果在转换过程中块被淘汰,则转换中的内容将与输出转换一起继续到 'play',而不是反转。 如果输出转换被中止,转换将从头开始重新开始。

Unlike with transition:, transitions applied with in: and out: are not bidirectional — an in transition will continue to 'play' alongside the out transition, rather than reversing, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch.

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

animate:函数(animate:fn)

animate:name
animate:name={params}
ts
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
}
ts
DOMRect {
bottom: number,
height: number,
​​left: number,
right: number,
top: number,
width: number,
x: number,
y: number
}

锁定每个块 的内容重新排序时会触发动画。 添加或删除元素时动画不会运行,仅当每个块中现有数据项的索引发生更改时才会运行。 Animate 指令必须位于作为键控每个块的直接子元素的元素上。

An animation is triggered when the contents of a keyed each block are re-ordered. Animations do not run when an element is added or removed, only when the index of an existing data item within the each block changes. Animate directives must be on an element that is an immediate child of a keyed each block.

动画可以与 Svelte 的 内置动画函数自定义动画函数 一起使用。

Animations can be used with Svelte's built-in animation functions or custom animation functions.

<!-- When `list` is reordered the animation will run-->
{#each list as item, index (item)}
	<li animate:flip>{item}</li>
{/each}

动画参数(Animation Parameters)

与动作和转场一样,动画也可以有参数。

As with actions and transitions, animations can have parameters.

(双 {{curlies}} 不是特殊语法;这是表达式标记内的对象字面量。)

(The double {{curlies}} aren't a special syntax; this is an object literal inside an expression tag.)

{#each list as item, index (item)}
	<li animate:flip={{ delay: 500 }}>{item}</li>
{/each}

自定义动画函数(Custom animation functions)

动画可以使用提供 nodeanimation 对象和任何 parameters 作为参数的自定义函数。 animation 参数是一个包含 fromto 属性的对象,每个属性都包含一个 DOMRect,描述元素在其 startend 位置的几何形状。 from 属性是元素在其起始位置的 DOMRect,to 属性是元素在列表重新排序和 DOM 更新后在其最终位置的 DOMRect。

Animations can use custom functions that provide the node, an animation object and any parameters as arguments. The animation parameter is an object containing from and to properties each containing a DOMRect describing the geometry of the element in its start and end positions. The from property is the DOMRect of the element in its starting position, and the to property is the DOMRect of the element in its final position after the list has been reordered and the DOM updated.

如果返回的对象具有 css 方法,Svelte 将创建在元素上播放的 CSS 动画。

If the returned object has a css method, Svelte will create a CSS animation that plays on the element.

传递给 csst 参数是应用 easing 函数后来自 01 的值。 u 参数等于 1 - t

The t argument passed to css is a value that goes from 0 and 1 after the easing function has been applied. The u argument is equal to 1 - t.

在动画开始之前,使用不同的 tu 参数重复调用该函数。

The function is called repeatedly before the animation begins, with different t and u arguments.

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

	/**
	 * @param {HTMLElement} node
	 * @param {{ from: DOMRect; to: DOMRect }} states
	 * @param {any} params
	 */
	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 函数,该函数在动画期间使用相同的 tu 参数调用。

A custom animation function can also return a tick function, which is called during the animation with the same t and u arguments.

如果可以使用 css 代替 tick,请这样做 — CSS 动画可以脱离主线程运行,从而防止在速度较慢的设备上出现卡顿。

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

	/**
	 * @param {HTMLElement} node
	 * @param {{ from: DOMRect; to: DOMRect }} states
	 * @param {any} params
	 */
	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}
上一页 特殊标签
下一页 组件指令