Before we begin

临时说明:本文档正在进行中。可能并不完善以及存在文档,积极地在 Discord 聊天室寻求帮助。 教程 是比较完整的,尝试从那里开始。

译者注:由于译者时间匆忙以及水平有限,该翻译没有校对审核,如果你发现有歧义以及过时的地方,请第一时间在翻译文档的GitHub issues中提出,我将尽快修复。

此页面包含详细的API参考文档。它旨在为已经对Svelte有所了解的人们提供资源。

如果你还不是(尚未)对Svelte有所了解,则在参考本参考资料之前,你先访问 交互式教程实例 会得到更多帮助。

Component 格式

Components 是Svelte构建程序的基础。.svelte文件使用超集将它们写入HTML文件中。

.svelte文件中,这三个部分( script, styles和元素标签)都是可选的。

<script>
	//代码文件
</script>

<style>
	/* 样式文件*/
</style>

<!-- 此处一般放置元素标签(多个或者为空) -->

<script>

<script> 块包含创建 component 实例时运行的JavaScript。从组件的标记“可见”在内部声明(或导入)的变量。还有四个附加规则:

1. 使用export 创建 component prop 属性

Svelte 使用export关键字将变量声明标记为 属性prop, 这意味着component 的使用者可以访问它 (更多详见 prop属性部分 )。

<script>
	export let foo;

	// 作为props传入的值
	// 是即时生效的
	console.log({ foo });
</script>

你可以指定一个默认值,如果component的使用者未指定prop属性值,则使用该默认值。

在开发模式中 (请参阅 编译器选项), 如果未提供默认值且使用者未指定值,则将打印警告。要避免此警告,请确保已指定默认值,即便它是 undefined

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

如果将constclassfunction导出到component外部,那它们将会变成只读属性,然而只有函数表达式是有效的props。

<script>
	// 这些是只读的
	export const thisIs = 'readonly';

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

	//这是一个prop
	export let format = n => n.toFixed(2);
</script>

你可以使用保留字作为 prop 名。

<script>
	let className;

	// 创建“class”属性名
	// 即使它是保留字
	export { className as class };
</script>
2. '反应性(reactive)' 分配

要更改component state并触发重新渲染,只需将其指定给本地声明的变量即可。

更新表达式 (count += 1) 和属性分配 (obj.x = y) 具有相同的效果。

由于Svelte的反应性是基于分配的,因此使用.push().splice()和这样的数组方法不会自动触发更新。解决此问题的选项可以在 此教程中找到。

<script>
	let count = 0;

	function handleClick () {
		// 如果元素标签引用'count'
		// 调用此函数将触发更新
		count = count + 1;
	}
</script>
3. $: 声明反应性

通过使用$: JS label 语法作为前缀。可以让任何位于 top-level 的语句(即不在块或函数内部)具有反应性。每当它们依赖的值发生更改时,它们都会在 component 更新之前立即运行。

<script>
	export let title;

	// 这将在“title”的prop属性更改时
	// 更新“document.title”
	$: document.title = title;

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

如果语句完全由未声明变量的赋值组成,则Svelte替你将 let插入声明。

<script>
	export let num;

	// 我们不需要声明“squared”和“cubed”
	// — Svelte帮我们自动声明
	$: squared = num * num;
	$: cubed = squared * num;
</script>
4. 用 $前缀来存储store值

store 是一个对象,允许通过简单的值的反应性访问 store contract。该 svelte/store 模块 包含满足此 contract 的最小store实现。

每当引用 store时,都可以通过在其前面加上$字符来访问其在component内部的值,这会使Svelte自动声明前缀变量,并设置将在适当时取消store subscription(订阅)。

$为前缀的变量要求store变量值是可更改的,以确保 store的.set 方法是可调用的。

注意, 不能在“if”块或函数中,必须在component的顶层声明store,例如,局部变量(不包含store值) 一定不能带有$前缀。

<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 contract
store = { subscribe: (subscription: (value: any) => void) => () => void, set?: (value: any) => void }

你可以通过store contract来实现自己的store,而无需依赖 svelte/store

  1. 一个store 必须包含一个 .subscribe方法,该方法必须接受subscription 函数作为其参数,在调用时,必须使用 store 当前值通过.subscribe方法来使用subscription 函数。每当store值更改时,都必须同步调用store的所有活动subscription 函数。
  2. .subscribe 方法必须返回一个unsubscribe 函数。调用 unsubscribe 函数会停止subscription功能,并且subscription 函数不会再被store调用。
  3. store 可以选择包含一个 .set 方法, 该方法必须接受store的新值作为其参数,,并且该方法将同步调用store的所有活动的 subscription 函数。 这样的 store调用了一个可写 store

为了与RxJS Observables互操作, .subscribe 方法还允许该方法与.unsubscribe方法一起返回对象,而不是直接返回 unsubscription 函数。但是请注意,除非 .subscribe同步调用subscription(Observable规范不需要),否则Svelte会将存储的值视为“undefined”,直到它看到为止。

<script context="module">

一个<script> 标签具有一个context="module"熟悉,在模块首次 evaluates 时运行一次,而不是针对每个组件实例运行一次。 此块中声明的值可以在常规的 <script>代码块中访问 (和 component 的标签), 反之亦然。

你可以使用export绑定到该块,它们将作为已编译模块导出。

你不能使用 export default来绑定,因为组件本身就是默认导出(export default)。

带有 module 声明的 <script> 内代码不具有反应性。虽然变量自身会更新,但重新分配它们不会触发重新渲染,对于多个组件之间共享的值,请考虑使用 store.

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

	// 此处允许执行import操作,例如
	// `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>

<style> 标签块中的样式仅仅生效于component内部。

这是通过将一个class添加到受影响的标签而实现的,该class基于component样式(例如 svelte-123xyz)。

<style>
	p {
		/* 这只会影响此组件中的<p>标签 */
		color: burlywood;
	}
</style>

你可以选择使用 :global(...) 修饰符来添加全局样式。

<style>
	:global(body) {
		/* 这里样式全局应用于 <body>内都 */
		margin: 0;
	}

	div :global(strong) {
		/* 这里表示全局应用于被<div>包裹的<strong>标签 */
		color: goldenrod;
	}
</style>

模板语法

标签

小写标签诸如<div>之类,表示常规的HTML标签,大写标签例如 <Widget><Namespace.Widget>,表示这是一个 component

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

<div>
	<Widget/>
</div>

props 属性

默认情况下,属性的使用方式与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>

表达式可能会包含导致常规HTML语法高亮失效,使之不能正常显示语法高亮,因此有必要使用引号来避免此情况:

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

当出现属性名和值一样时 (name={name}),可以简写为{name}

<!-- 两者是等价的 -->
<button disabled={disabled}>...</button>
<button {disabled}>...</button>

一般来说,传递到 components 内的值被称为 propertiesprops ,因此称之为props属性以便于区分:

与常规标签一样,name={name} 可以用 {name} 来简写。

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

Spread 属性 允许将多个或单个属性一同传递到标签或component。

标签或component允许使用多个 spread 属性,或者和常规属性一同使用。

<Widget {...things}/>

$$props 可以传递所有 props 属性到一个 component 中,包含未使用export声明的 props 属性。它在特殊情况下很有用,但通常不推荐使用,因为Svelte难以优化。

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

文本表达式

{expression}

文本内还可以穿插 JavaScript 表达式:

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

注释

你可以在 components 内部使用 HTML注释。

<!-- 这是一句注释! -->
<h1>Hello world</h1>

svelte-ignore 开始的内容会被注释掉,直到位于注释闭合标签结束注释。 一般来说,被注释的内容包含accessibility(a11y,一些对提高可访问性有帮助的信息)信息,所以请在有充足理由时才使用它。

<!-- 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, 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 还可以指定一个 index 作为索引, 该 index 会成为 array.map(...) 回调的第二参数:

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

如果一个 key(键) 是一个表达式,必须确保它其具有唯一性,能标识在列表内的每一个列表项,以便 Svelte 在列表中任意位置改变数据,而不是仅在数据末尾新增或删除。key 可以是任何对象,但是建议使用字符串和数字,因为它们允许在对象本身更改时保留身份。

{#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}子句,如果列表为空,则显示{: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 块,你可以使用表示 Promise 状态的三个分支 pending、 fulfilled 和 rejected。

{#await promise}
	<!-- promise 状态是“未决” -->
	<p>waiting for the promise to resolve...</p>
{:then value}
	<!-- promise 状态是 “完成” -->
	<p>The value is {value}</p>
{:catch error}
	<!-- promise 状态是“被拒绝” -->
	<p>Something went wrong: {error.message}</p>
{/await}

catch 块表示你在请求被拒绝时需要渲染的内容,没有则可忽略该块。

{#await promise}
	<!-- promise 状态是“未决” -->
	<p>waiting for the promise to resolve...</p>
{:then value}
	<!-- promise 状态是 “完成” -->
	<p>The value is {value}</p>
{/await}

如果你不关心“未决”状态,也可以省略该块。

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

{@html ...} HTML内容插入

{@html expression}

在文本表达式中,诸如<> 都将被转义,但HTML表达式不会。

HTML表达式应该是有效且完整的,{@html "<div>"}content{@html "</div>"} 将不会生效,因为 </div> 是无效的HTML标签。

Svelte不会在注入HTML之前转义表达式。如果数据来源不受信任,则必须对其进行转义,否则将用户暴露于XSS漏洞之中。

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

{@debug ...} 调试模式

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

可与使用 {@debug ...} 替换 console.log(...) 来使用。每当指定变量的值更改时,它都会记录这些变量的值,如果您打开了devtools,则会在{@debug ...} 语句位置 暂停代码执行。

它接受单个变量名:

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

{@debug user}

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

或被 comma-separated (逗号分隔的)的多个变量名(表达式除外)。

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

<!-- 不被编译 -->
{@debug user.firstname}
{@debug myArray[0]}
{@debug !isReady}
{@debug typeof user === 'object'}

{@debug}标签在没有任何参数时将会插入一条 debugger 语句,该语句在任何状态(state )发生变化时都会被触发,这与指定变量名时恰恰相反。

标签指令

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

on:事件名

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会在合适的地方自动加上它)
  • capture:表示在 capture阶段而不是bubbling触发其程序
  • once :程序运行一次后删除自身

修饰符可以串联在一起,比如on:click|once|capture={...}

如果所使用的 on: 指令事件没有指定具体值,则表示 component 将会负责转发事件,这意味着组件的使用者可以侦听该事件。

<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:属性

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框声明值类型为数字时, input.value 即使在DOM中键入的值时字符串, Svelte也会视其为数字, 如果输入的值为空或者是无效的值, (对于type="number"而言),其值将会为 undefined

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

<select> 绑定值对应的所选择项 <option>value,值可以是任何类型(一般在DOM中不仅是字符串类型)。

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

<select multiple> 标签类似于一个 checkbox 组。

<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>
媒体标签绑定

媒体标签 (<audio><video>) 也有一组绑定属性。 其中 6 个只读属性:

  • duration (readonly) :表示视频的总时长,以秒为单位。
  • buffered (readonly) :数组,包含{start, end} 对象。
  • seekable (readonly) :同上。
  • played (readonly) :同上。
  • seeking (readonly) :布尔值。
  • ended (readonly) :布尔值。

以及四个双向绑定:

  • currentTime :视频中的当前点,以秒为单位。
  • playbackRate :播放视频的倍速, 1 为 '正常'。
  • paused :暂停。
  • volume :音量,0到1之间的值。

<video> 标签较之还有多出了只读属性videoWidthvideoHeight的属性。

<video
	src={clip}
	bind:duration
	bind:buffered
	bind:seekable
	bind:seeking
	bind:played
	bind:ended
	bind:currentTime
	bind:paused
	bind:volume
	bind:videoWidth
	bind:videoHeight
></video>
块级标签绑定

块级元素具有4个只读属性的绑定,使用像这样 的方法进行尺寸监听:

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

组绑定

bind:group={variable}

多个input值可以使用bind:group进行绑定。

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

<!-- radio inputs 是互斥的 -->
<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">

<!-- checkbox inputs 键入的值将会填入其数组 -->
<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: 指令可以以其简写形式绑定其标签的class。

<!-- 它们是等价的 -->
<div class="{active ? 'active' : ''}">...</div>
<div class:active={active}>...</div>

<!-- 简写 -->
<div class:active>...</div>

<!-- 可以包含多个class状态 -->
<div class:active class:inactive={!active} class:isAdmin>...</div>

use action

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

Action 作为一个方法用于标签被创建时调用。调用destroy函数返回表示标签被销毁。

<script>
	function foo(node) {
		// node已挂载在DOM中

		return {
			destroy() {
				// node已从DOM中移除
			}
		};
	}
</script>

<div use:foo></div>

Action 可以含有参数。如果返回的值含有update 方法, 在对 Svelte 标记的内容更新之后,只要update指定的参数发生变更,它都会立即应用变更。

不必担心为每个componet实例重新声明foo函数,Svelte会自动提升所有compoent definition内不依赖于局部状态(local state)的函数的作用范围。

<script>
	export let bar;

	function foo(node, bar) {
		// node已挂载在DOM中

		return {
			update(bar) {
				// `bar` 已发生变更
			},

			destroy() {
				// node已从DOM中移除
			}
		};
	}
</script>

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

transition:fn

transition:fn
transition:fn={params}
transition:fn|local
transition:fn|local={params}
transition = (node: HTMLElement, params: any) => {
	delay?: number,
	duration?: number,
	easing?: (t: number) => number,
	css?: (t: number, u: number) => string,
	tick?: (t: number, u: number) => void
}

Transition的触发条件:状态更改、元素进入或离开DOM。

临时(outroing)块中的标签会一直保留在DOM中,直到当前所有transitions完成为止。

transition: 指令支持 双向(bidirectional) 切换, 这意味着 transition 过程中可以支持逆转。(例如显示与隐藏的双向切换)

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

默认情况下,component 在首次渲染时不会播放 transitions。你可以在创建 component时设置intro: true 来更改此行为。

Transition 参数

像actions一样,transitions 可以带有参数。

(这里的两层花括号 {{curlies}}并非特殊语法,这是表达式标记内的对象字面量(object literal)。

{#if visible}
	<div transition:fade="{{ duration: 2000 }}">
		flies in, fades out over two seconds
	</div>
{/if}
自定义 transition 函数

Transitions 可以试用自定义函数。如果返回的对象具有 css 函数,Svelte将创建一个在标签上播放的CSS动画。

t参数传递给css,取值范围是01,继而应用到easing函数。入(In) transitions 运行是 01出(out) transitions运行是 10。 换句话说, 1 表示标签的基础状态,好像没有transition一般。u 参数取值范围 1 - t

该函数在transition开始之前,以不同tu的参数重复调用。

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

自定义 transition 函数还可以返回一个名为tick的函数,该函数在transition过程中调用同样的tu 的参数。

如果可以,务必使用 css 代替 tick,因为 CSS 动画可以在主线程上运行,从而防止运行在性能较差的的设备上出现混乱。

<script>
	export let visible = false;

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

		if (!valid) return {};

		const text = node.textContent;
		const duration = text.length * speed;

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

{#if visible}
	<p in:typewriter="{{ speed: 20 }}">
		The quick brown fox jumps over the lazy dog
	</p>
{/if}

如果 transition 返回的是一个方法而不是一个 transition 对象,则该函数将在下一个微任务中调用。这样可以协调多个 transitions。 使 淡入淡出效果 成为可能。

Transition 事件

除了所有标准DOM事件外,具有transitions功能的标签还可以调用以下事件:

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

局部 transitions 仅在创建或销毁它们所属的块时播放,而创建或销毁其父级时不会。

{#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:fn/out:fn

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:应用的转换不是双向的,就算在过渡期间块超出范围,in的过渡效果也会继续“播放”对立的out过渡效果,而不是反转。如果out过渡效果中止,过渡将从头开始。

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

animate:fn

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
}

动画触发在当内容 each 块重新遍历时。当标签被移除时不会运行动画。只有在重新遍历each块的数据时才运行。 Animate 指令必须放在当前 each 块的子项的标签上。

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

<!-- 当`list`重新遍历时,动画将运行-->
{#each list as item, index (item)}
	<li animate:flip>{item}</li>
{/each}
Animation 参数

与 actions 和 transitions一样,动画同样具有参数。

(这里的两层花括号 {{curlies}}并非特殊语法,这是表达式标记内的对象字面量(object literal)。

{#each list as item, index (item)}
	<li animate:flip="{{ delay: 500 }}">{item}</li>
{/each}
自定义animation函数

动画可以使用“node”、 animation 对象和任何 paramaters作为参数来定义自定义函数。该 animation 是一个对象包含fromto属性,每个属性都包含一个 DOMRect用于描述标签的块状 startend 位置。from 属性是标签的DOMRect对象的起始位置 to 属性是标签经列表遍历和DOM渲染完成后的DOMRect对象的结束位置。

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

t 参数传递到 css 方法并以 01 为值的形式应用给 easing 函数。 u 的参数取值范围: 1 - t

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

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

自定义animation函数还可以返回一个名为tick的函数,该函数在动画过程中调用同样的tu 的参数。

如果可以,务必使用 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}

Component 指令

on:event名称

on:eventname={handler}

Components 可以使用 createEventDispatcher来发出事件,或者进行DOM事件转发。监听component事件看来和监听DOM事件相同。

<SomeComponent on:whatever={handler}/>

与DOM事件一样,如果该指令on:不带有值,则component会转发外部事件,也就意味着component的使用者可以监听它。

<SomeComponent on:whatever/>

bind:property

bind:property={variable}

你可以使用与标签相同的语法绑定到component props。

<Keypad bind:value={pin}/>

bind:this

bind:this={component_instance}

Components 还支持 bind:this,允许你编程操作component实例进行交互。

注意不要使用{cart.empty}这样的实行, 因为cart 值是undefined,将在首次渲染button 时报错。

<ShoppingCart bind:this={cart}/>

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

<slot> 组件插值

<slot><!-- 可选回调 --></slot>
<slot name="x"><!-- 可选回调 --></slot>
<slot prop={value}></slot>

Components 可以和标签一样含有子内容。

Component内使用<slot>标签将component内内容暴露给外部,该标签内的内容将作为默认内容暴露给外部。

<!-- App.svelte -->
<Widget></Widget>

<Widget>
	<p>本段文本将会替代slot标签内的默认内容。</p>
</Widget>

<!-- Widget.svelte -->
<div>
	<slot>
	默认内容,component外部没有内容传入时显示本段文本。
	</slot>
</div>

<slot name="name">

给slot命名可以将外部内容指定给特定区域,component内部命名未被指定的内容将会作为默认内容暴露。

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

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

<slot let:name={value}>

Slot可以零次或多次渲染,并且可以通过prop属性将值传回父级,父级使用let:指令将值暴露到slot模板。

通常适用的速记规则:let:item 等效于let:item={item},并且 <slot {item}> 等效于<slot item={item}>

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

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

命名的slot也可以暴露值。该 let:指令位于具有slot属性的标签上。

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

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

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

<svelte:self>

<svelte:self>标签允许component递归自身。

它不能出现在标签的顶层;它必须在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> 标签动态渲染component,被指定的 component 具有一个 this 属性。每当标签上的属性发生变化,该 component 将会销毁并重新创建渲染。

如果this 指向的值为false则不会呈现任何内容。

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

<svelte:window>

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

<svelte:window> 标签允许你添加事件监听到window 对象,从而不用担心移除它时component 被毁,或者在服务端渲染时检查是否存在于 window

<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的别名

除了 scrollXscrollY 是只读的。

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

<svelte:body>

<svelte:body on:event={handler}/>

<svelte:window>相同,你可以通过本标签添加监听事件到 document.body中,例如mouseentermouseleave 并且不会触发window

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

<svelte:head>

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

通过该标签可以将元素插入到document.head中。在服务端渲染时, 内容将插入到htmlhead中。

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

<svelte:options>

<svelte:options option={value}/>

<svelte:options> 标签为component 提供编译器选项,有关详细信息请参见 compiler section。可选的选项有:

  • immutable={true} — 你从不使用可变数据,因此编译器可简易相等性检查以确定值是否变更。
  • immutable={false} — 默认选项。Svelte对于可变对象的值更改的处理会趋向保守。
  • accessors={true} — 给 component 的 prop 添加getter和setter。
  • accessors={false} — 默认。
  • namespace="..." — 让component的使用名称空间,最常见的是"svg"。
  • tag="..." — 将此组件编译为自定义标签时使用的名称。
<svelte:options tag="my-custom-element"/>

运行时

svelte

svelte包含有 生命周期函数context API

onMount

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

onMount函数作为将component挂载到DOM后立即执行的回调。它必须在component初始化期间被调用(但不必位于component内部;可以从外部模块调用它)。

onMount 不在 服务端 component内部运行。

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

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

如果需要onMount返回一个函数,则在卸载 component 时调用该函数。

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

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

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

beforeUpdate

beforeUpdate(callback: () => void)

给所有state变更安排一个回调函数运行在 component渲染之前。

首次回调运行在onMount初始化之前。

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

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

afterUpdate

afterUpdate(callback: () => void)

安排一个回调函数运行在 component渲染之后。

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

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

onDestroy

onDestroy(callback: () => void)

计划在component卸载后运行的回调。

相对于 onMountbeforeUpdateafterUpdateonDestroy,它唯一可以运行在服务端渲染组件内部。

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

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

tick

promise: Promise = tick()

返回一个promise,该promise将在应用state变更后返回resolves,或者在下一个微任务中(如果没有)更改。

<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对象与当前component同指定的key关联。然后,该context通过getContext函数应用到component的子级(包含带slot的内容)。 像生命周期函数一样,必须在component初始化期间调用它。

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

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

Context 本身并不具有响应性。如果你需要在 context 中的值具有响应性,你需要将store传递到context中。

getContext

context: any = getContext(key: any)

如果你检索父组件含有的指定最近component 的 key,则必须在component初始化期间调用。

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

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

createEventDispatcher

dispatch: ((name: string, detail?: any) => void) = createEventDispatcher();

创建一个可用于分发component事件的事件分发器。事件分发器是一个函数,接受两个参数: namedetail

Component 创建一个与 createEventDispatcher创建一个 CustomEvent(自定义事件).。该事件不会 bubble ,也无法取消使用 event.preventDefault()。该 detail 参数对应CustomEvent.detail 属性,并且可以包含任何数据类型。

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

	const dispatch = createEventDispatcher();
</script>

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

子component 分发的事件可以在其父子component中监听。调度事件时提供的任何数据都可以在事件对象上获取detail属性。

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

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

svelte/store

svelte/store 模块导出函数可用于创建 readable(可读), writable(可写)derived(派生) 的store。

记住,你不具备使用这些函数并使用响应性 $store 语法在你的 component 中。所有对象正确实现.subscribe、 unsubscribe和 .set(可选)成为一个有效store就可以使用特殊语法以及Svelte内置 derived(派生) store

这使得Svelte可以包含几乎所有其他响应式state处理库,阅读更多关于store contract,以了解正确使用方式。

writable

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

它提供一个给外部组件创建 store 值的函数。它被创建为带有setupdate 方法的对象。

set是一种接收一个参数的设置值方法。如果store值与参数值不相等,则将其设置为新参数的值。

update是一种接收一个参数的回调方法。回调将现有store值作为其参数,并返回要设置为store 的新值。

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'

如果将函数作为第二个参数传递,则在subscriber数从0变为1(但不是从1变为2)时将调用该函数。该函数将被传递一个set更改store值的函数。它必须返回一个stop 函数在subscriber数从1变为0时调用的函数。

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'

readable

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

创建一个无法从“外部”设置其值的store ,第一个参数是store 的初始值。

第二个参数的readable与的第二个参数writable相同,不同的是必须使用readable(否则将无法更新store值)。

import { readable } from 'svelte/store';

const time = readable(new Date(), set => {
	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(派生)一个源于一个或多个其他 store的store,只要这些依赖项发生变更,就会执行回调。

在简易版本中,derived只拥有一个store且回调返回一个派生值。

import { derived } from 'svelte/store';

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

该回调可以以set作为第二个参数,并在适当的时候调用它来异步设置一个值。

在这种情况下,你还可以将第三个参数传递到derived,即在首次调用set之前派生 store 的初始值。

import { derived } from 'svelte/store';

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

右侧实例中,如果你的回调函数返回的是一个函数,则会在“a”被回调运行(或当“b”的最后一个subscriber【订阅】被unsubscribes【取订】)时被调用。

import { derived } from 'svelte/store';

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

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

在这两种情况下,数组参数都将作为首个参数传递,而不是作为单一的store。

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)

通常,你可以通过subscribing(订阅) store 并随时使用它来读取store值。但是当store的值是未被subscribed的,这时候你就可以通过get来完成。

这可以通过创建subscription读取值,然后通过unsubscribing(取订)来取订。但是,在热更新代码路径(hot code paths)中不建议这样做。

import { get } from 'svelte/store';

const value = get(store);

svelte/motion

svelte/motion模块导出两个函数: tweenedspring。用于创建writable(可写)store,其值会在setupdate之后更新,而不是立即更新。

tweened

store = tweened(value: any, options)

Tweened(补间) store 值会在固定时间内更新,可选参数:

  • delay (number, 默认值: 0) — 开始(单位毫秒)。
  • duration (number, 默认值:400) — 持续时间(单位毫秒)。
  • easing (function, 默认值: t => t) — easing 函数
  • interpolate (function) — 参见下文

store.setstore.update 可以作为第二个 options 的参数,该参数将覆盖实例化时传递的选项。

这两个函数都返回一个Promise,并在tweened完成时返回resolves,如果tweened中断,则 promise 将不会返回resolves。

开箱即用,使用Svelte在两个数字、两个数组或两个对象之间进行插值(只要数组和对象是相同的'shape',并且它们的'leaf'属性也是number)。

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

如果初始化的值是undefinednull,第一个值更改将立即生效,当你具有基于component的tweened值并且在component首次渲染时不希望任何运动时,此功能很有用。

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

$: $size = big ? 100 : 10;

interpolate(插入) 选项允许你在任意值作为tweened值,它必须是一个(a, b) => t => value结构的函数 其中a 是起始值,, b 是结束值, t 必须是一个数字(取值:0-1),例如,我们可以使用 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(弹性) store通过stiffnessdamping参数逐步变更到目标值,而tweenedstore在改变一个固定时间变更其值。store在由它们现有速度决定的持续时间长短,从而实现更自然的运动效果。可选选项:

  • stiffness (number, 默认值: 0.15) — 取值:0-1,数值越大效果越生硬(例,灵敏度)。
  • damping (number, 默认值: 0.8) — 取值:0-1,数值越小阻尼越小(例,惯性)。
  • precision (number, 默认值: 0.001) — 粒度。用于控制上面两个参数的运动幅度大小。

tweened store一样,,setupdate 在弹性动画完成时返回一个Promise resolves。 其中 store.stiffnessstore.damping 属性可以立即改变其弹性运动特性。

setupdate 两者可以用 hardsoft属性对象作为第二个参数来表示弹性动画柔度,{ hard: true } 表示无弹性, { soft: n } 表示运动曲线柔度。{ soft: true } 等效于 { soft: 0.5 }

更多请参阅弹性教程

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

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

如果初始值为 undefinednull,则第一个值更改将立即生效,就像使用 tweened 值一样(参阅上文)。

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

svelte/transition

svelte/transition (过渡) 模块具有六个函数: fade, fly, slide, scale, drawcrossfade。 它与 svelte transitions一起使用。

fade(淡入淡出)

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

通过对标签透明度添加动画实现淡入淡出效果,in表示入,out表示出。

fade 接收以下两个参数:

  • delay (number, 默认值: 0) — 起始时间点(毫秒)。
  • duration (number, 默认值: 400) — 持续时间(毫秒)。

你可以查看 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) — easing 函数
  • opacity (number, 默认值 0) - 不透明度(取值0-1)。
  • amount (number, 默认值 5) - 模糊范围(单位是px,这里不加单位)。
<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 函数
  • x (number, 默认值 0) - 往x轴方向偏移量。
  • y (number, 默认值 0) - 往y轴方向偏移量。
  • opacity (number, 默认值 0) - 移入/移出时的目标不透明度(如果移入/移出时不同的话)动画(取值0-1)。

你可以查看 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 函数
<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) — aeasing 函数
  • start (number, 默认值 0) - in / out时的目标比例(取值0-1)。
  • opacity (number, 默认值 0) - in / out时的目标不透明度(取值0-1)。
<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 函数

speed 参数是一种设置相对于路径长度的过渡持续时间的方法。它是应用于路径长度的修饰符: duration = length / speed。速度为1的1000像素路径的持续时间为 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>

svelte/animate

svelte/animate 模块导出一个函数 与 svelte animations一起使用。

flip(翻转)

animate:flip={params}

flip 函数计算标签的开始和结束位置并在它们之间进行动画效果,并翻转xy的值,flip初始, 最终, 翻转, Play(FLIP)支持。 The flip function calculates the start and end position of an element and animates between them, translating the x and y values. flip stands for First, Last, Invert, Play.

flip 接收以下参数:

  • delay (number, 默认值 0) — 起始点(毫秒)
  • duration (number | function, 默认值 d => Math.sqrt(d) * 120) — 细节参见下文。
  • easing (function, 默认值 cubicOut) — an easing 函数

duration 可接收参数:

  • 一个number, 单位毫秒
  • 一个函数,结构 distance: number => duration: number,接收标签将以像素为单位移动的距离,并以毫秒为单位返回持续时间。这使您可以分配一个持续时间,该持续时间与每个标签的移距离有关。

查看 animations 教程查看示例。

<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

Easing 函数可指定根据时间变化的速率,在使用Svelte的内置transition和animation以及tweened和spring程序时非常有用。 svelte/easing 包含31个导出命名,, 一个linear(线性)缓动使用inoutinOut轻松生成10种不同的缓动函数:

你可以结合 ease visualiserexamples section示例了解更多。

缓动样式 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

要在 Node.js 环境中使用 Svelte 组件无需捆绑,请使用require('svelte/register')。 之后,你可以使用 require 来包含任何.svelte 文件。

require('svelte/register');

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

...

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

为什么要加.default ,是因为我们正在将原生JavaScript模块转换为Node可以识别的CommonJS模块。请注意,如果您的组件导入了JavaScript模块, 则它们将无法在Node中加载,而你也需要使用捆绑器。

要设置编译选项或使用自定义文件扩展名,请调用register 作为钩子函数:

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

客户端 component API

创建 component

const component = new Component(options)

客户端 component 使用 generate: 'dom' (或 generate 选项不指定)编译的component是JavaScript类。

import App from './App.svelte';

const app = new App({
	target: document.body,
	props: {
		// 类似于 App.svelte 这样
		// `export let answer`:
		answer: 42
	}
});

可以提供以下初始化选项:

选项 默认值 描述
target none 指定HTMLElement(HTML标签) 来渲染。此选项是必需的。
anchor null target(目标)子级之前即将渲染的component。
props {} 提供给component的属性对象。
hydrate false 见下文。
intro false 如果为 true,在初始渲染时播放transition,而不是等待后续更改。

target目标)的现有子级留在他们所在的地方。

hydrate选项指示Svelte更新现有DOM标签(通常从服务端渲染)而不是创建新标签。只有在使用hydratable: true 选项编译component时,它才起作用,也唯有使用编译component时,它才起作用。只有当服务器渲染代码也使用hydratable: true编译时,标签的hydrate才起作用,这将为中的每个标签添加一个标记,以便component知道它在hydrate过程中负责移除哪些标签。

仅当target目标)只有一个子级,其子级hydrate: true才会生效。因此,anchor不能与hydrate: true一起使用。

现有DOM不需要匹配component,Svelte会自动纠正它。

import App from './App.svelte';

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

$set

component.$set(props)

以编程方式在实例上设置 prop , 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中删除component并触发所有onDestroy 处理程序。

Component props

component.prop
component.prop = value

如果设置accessors: true编译组件,则每实例将具有该component每个prop对应的getter 和 setter。设置值将导致同步更新,请勿使用component.$set(...)触发默认的异步更新。

默认情况下, accessorsfalse,除非你要将其作为自定义标签来编译。

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

自定义 element API

Svelte component也可以使用customElement: true来告诉编译器将component编译为自定义标签。使用<svelte:options> 标签为组件指定标签名。

<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后,也就意味着将所有component的 props 属性暴露给 DOM 标签 (有时也可以将 readable/writable 作为作为属性)。

为防止这种情况,请添加 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';

自定义标签将component打包在非Svelte应用中使用的最有效方法,因为自定义元素将与原生HTML 和 JavaScript以及大部分框架一同使用,但需要注意一些重要的差异:

  • 样式是被 encapsulated(封装)的,而不仅仅是scoped(局部)范围内。这也就意味着任何非component样式(例如你可能在global.css中含有样式),都将不适用于自定义标签, 包括带有:global(...)修饰符的样式。
  • 样式不是作为单独的.css文件提取出来的,而是作为JavaScript字符串内联到组件中的
  • 自定义标签通常不适合服务端渲染,因为在加载JavaScript之前,shadow DOM是不可见的
  • Svelte中, slotted(插值) 内容属于 lazily(懒)渲染。在DOM中,它是 eagerly(勤)渲染。换句话说,即使component的<slot>标签在{#if ...} 也始终创建它,同样,<slot> 在一个 {#each ...}块中包含不会导致分段显示的内容被多次渲染。
  • let: 指令将会报废。
  • 需要Polyfills来支持较旧的浏览器

服务端 component API

const result = Component.render(...)

与客户端 component 不同,服务端component在渲染后没有生命周期,它们的全部工作就是创建一些HTML 和 CSS。因此,API有所不同。

服务端component暴露一个render 方法作为可选方法调用。他返回一个具有headhtmlcss属性的对象,其中head包含<svelte:head>标签中设置的所有内容。

你可以通过 svelte/register导入Svelte component到Node.js。

require('svelte/register');

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

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

Compile time

通常,您不会直接与Svelte编译器进行交互,而是使用捆绑程序插件将其集成到构建系统中

尽管如此,了解打包器的用法还是很有用的,因为捆绑程序插件通常向您提供编译器选项。

svelte.compile

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

svelte.compile 施加魔法般获取component源代码,并将其转换为JavaScript模块来到出class。

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

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

没有一个required,即可将以下选学校传递给编译器:

选项 默认 描述
filename null string, 用于调试提示和源映射。你的捆绑插件会自动进行设置。
name "Component" string ,它设置为一个JavaScript类的名称(不过,如果它与作用域中的其他变量冲突,编译器将对它进行重命名)。它通常是从filename中推断出来的。
format "esm" 如果为"esm",则创建一个带有importexport的JavaScript模块,如果是 "cjs",创建一个带有requiremodule.exports的CommonJS模块该模块在一些用于服务端渲染或测试的场景下很有用。
generate "dom" 如果为 "dom", 则Svelte会发出一个JavaScript 类来挂载到DOM。如果为"ssr",Svelte 会用render方法发出一个适用于服务端渲染中对象,如果为 false,则无JavaScript 或 CSS 返回,只返回元数据。
dev false 如果为 true,则会将额外代码添加到组件中,这些代码在执行运行时检查并在开发过程中提供调试信息。
immutable false 如果为true,则告诉编译器你保证不会后续改变任何对象。这使它在检查值是否已更改时不那么严格。
hydratable false 如果为 true, 启用hydrate: true 运行时选项,运行component 升级现有 DOM,而不是从头开始创建新DOM。生成SSR代码时,这会向<head>标签添加标记,以便hydration知道要替换的元素。
legacy false 如果为 true, 则生成可在IE9和IE10中使用的代码,不支持类似于element.dataset的这些代码。
accessors false 如果为true,将为component的porp创建getter和setter。如果为 false, 则仅为只读导出值创建(即用constclassfunction声明的值)。如果编译的带有 customElement: true 选项则默认为 true
customElement false 如果为 true,告诉编译器生成自定义标签构造函数,而不是常规的 Svelte component。
tag null string,告诉编译器指定一个tag名作为自定义标签名,它必须含有且是一个小写连字字符串,类似于"my-element"
css true 如果是 true,样式将包含在JavaScript类中并在运行时注入。建议您将其设置为false,并使用静态生成的CSS,因为它会使JavaScript包更小以及性能会更好。
loopGuardTimeout 0 number, 告诉Svelte如果线程阻塞时长超过 loopGuardTimeout设置的时间时终止循环, 这对防止无限循环很有效。 仅在dev: true情况下生效
preserveComments false 如果为 true,你的HTML注释将在服务端渲染中保留;当然默认情况下是会被删除。
preserveWhitespace false 如果为true,标签内的空格将会被保留,而不会被Svelte删除或折叠成单个空格。
outputFilename null string,用于你的 JavaScript 源映射。
cssOutputFilename null string ,用于你的CSS 源映射。
sveltePath "svelte" svelte 包位置,所有引入来自sveltesvelte/[module] 的路径都将被修改。

返回的result对象包含component的代码以及所使用的元数据字节。

const {
	js,
	css,
	ast,
	warnings,
	vars,
	stats
} = svelte.compile(source);
  • jscss 是具有以下属性的对象:
    • code :为JavaScript 字符串。
    • map :是具有 toString()toUrl() 的源映射方法。
  • ast :是用于表示component结构的抽象(abstract)语法树(syntax tree)。
  • warnings 是在编译期间生成的警告对象的数组。每个警告都有几个属性:
    • code使用其来说明警告类别的字符串。
    • message 描述问题信息使其易于理解。
    • startend,,如果警告需要指定到特定位置,请使其为一个具备 linecolumncharacter属性的对象。
    • frame,如果含有,是用于标记代码行号突出有问题代码的字符串。Each
  • vars 是一个component 声明数组, 例如 eslint-plugin-svelte3般使用,每个变量都有几个属性:
    • name 顾名思义。
    • export_name 指定其值导出的名称(如果它需要导出) (除非已指定其name ,负责将使用 export...as导出其name)
    • injectedtrue,声明是由Svelte注入(true)还是由你编写的代码注入(false)。
    • moduletrue 且表示在脚本中声明context="module"
    • mutatedtrue 且将值的属性分配到component内部。
    • reassignedtrue 且表示重新分配值到component内部。
    • referencedtrue 且表示值在声明之外使用值。
    • writabletrue 如果值使用 letvar (不是 constclassfunction)来声明。
  • stats 是Svelte开发团队用来诊断编译器的对象,请保持其不做变动。
compiled: {
	// `map` is a v3 sourcemap with toString()/toUrl() methods
	js: { code: string, map: {...} },
	css: { code: string, map: {...} },
	ast: {...}, // ESTree-like syntax tree for the component, including HTML, CSS and JS
	warnings: Array<{
		code: string,
		message: string,
		filename: string,
		pos: number,
		start: { line: number, column: number },
		end: { line: number, column: number },
		frame: string,
		toString: () => string
	}>,
	vars: Array<{
		name: string,
		export_name: string,
		injected: boolean,
		module: boolean,
		mutated: boolean,
		reassigned: boolean,
		referenced: boolean,
		writable: boolean
	}>,
	stats: {
		timings: { [label]: number }
	}
} = svelte.compile(source: string, options?: {...})

svelte.parse

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

parse 解析一个 component,仅返回其抽象语法树。 与使用generate: false 选项进行编译不同,它不会对component进行任何验证或额外解析, 只会解析其自身。

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

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

svelte.preprocess

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

preprocess 函数为所有改动component源代码提供一个方便的钩子,例如,它可以用于将<style lang="sass">块转换为原生CSS。

首个参数为component源代码,第二个参数为 preprocessors (预处理器)数组(如果仅有一个可为单个preprocessors),preprocessors对象可以使用 markupscriptstyle 作为可选函数。

各个 markupscriptstyle 函数必须返回一个对象 (或以Promise 的 resolves来作为对象返回)和 code 属性来表示改动后的源代码, 以及一个dependencies数组(可选)。

markup 将接收到 component 原文本,以及在第三个参数中指定了component的filename值对应的原文本。

Preprocessor函数可能还会返回一个map 对象以及对应的codedependencies, 其中 map 表示改动的源映射。在当前Svelte版本中,它将会被忽略, 但是将来的Svelte版本可能会考虑预处理器源映射。

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

const { code } = svelte.preprocess(source, {
	markup: ({ content, filename }) => {
		return {
			code: content.replace(/foo/g, 'bar')
		};
	}
}, {
	filename: 'App.svelte'
});

scriptstyle函数接收 <script><style> 标签内的内容。除了filename以外, 还可以获取标签的属性对象。

如果返回的是一个 dependencies 数组,它将被包含在结果对象中。 它使用类似于 rollup-plugin-svelte 来监听其他文件变更, 例如监听<style>标签中带有 @import 语句。

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

const { code, dependencies } = 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'
});

多个 preprocessors 可以同时使用。第一个的输出成为第二个的输入。 markup函数首先运行, 然后运行 scriptstyle

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

const { code } = 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实例来遍历解析器生成的抽象语法树。

使用一个抽象语法树walker来遍历时,需传入一个带有两种可选方法的对象: enterleave。其中enter会调用 (被parent包含)每个node。 除非在调用enter期间使用 this.skip()来跳过,否则每个node的子级都会被遍历到,继而再在node中调用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}`);