API Docs
开始之前
此页面包含详细的 API 参考文档。旨在成为已经熟悉 Svelte 的同学的一份参考资源。
如果你还不熟悉 Svelte,那么在参考本手册之前,请先查看 交互式教程 或 示例。
不要羞于在 Discord chatroom 中寻求帮助。
还是使用旧版本的 Svelte 吗?这里是 v2 版本的文档。
Component 格式
Components 是Svelte构建程序的基础。.svelte
文件使用超集将它们写入HTML文件中。
在.svelte
文件中,这三个部分( script, styles和元素标签)都是可选的。
<script>
//代码文件
</script>
<style>
/* 样式文件*/
</style>
<!-- 此处一般放置元素标签(多个或者为空) -->
<script>
<script>
块包含创建 component 实例时运行的JavaScript。从组件的标记“可见”在内部声明(或导入)的变量。还有四个附加规则:
export
创建 component prop 属性
1. 使用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>
如果将const
、 class
或 function
导出到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>
$
前缀来存储store值
4. 用 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
:
- 一个store 必须包含一个
.subscribe
方法,该方法必须接受subscription 函数作为其参数,在调用时,必须使用 store 当前值通过.subscribe
方法来使用subscription 函数。每当store值更改时,都必须同步调用store的所有活动subscription 函数。 .subscribe
方法必须返回一个unsubscribe 函数。调用 unsubscribe 函数会停止subscription功能,并且subscription 函数不会再被store调用。- 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 内的值被称为 properties 或 props ,因此称之为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}>
<select>
value
Binding <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>
标签较之还有多出了只读属性videoWidth
和videoHeight
的属性。
<video
src={clip}
bind:duration
bind:buffered
bind:seekable
bind:seeking
bind:played
bind:ended
bind:currentTime
bind:paused
bind:volume
bind:videoWidth
bind:videoHeight
></video>
块级标签绑定
块级元素具有4个只读属性的绑定,使用像这样 的方法进行尺寸监听:
clientWidth
clientHeight
offsetWidth
offsetHeight
<div
bind:offsetWidth={width}
bind:offsetHeight={height}
>
<Chart {width} {height}/>
</div>
组绑定
bind:group={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
,取值范围是0
到1
,继而应用到easing函数。入(In) transitions 运行是 0
到 1
, 出(out) transitions运行是 1
到 0
。 换句话说, 1
表示标签的基础状态,好像没有transition一般。u
参数取值范围 1 - t
。
该函数在transition开始之前,以不同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}
自定义 transition 函数还可以返回一个名为tick
的函数,该函数在transition过程中调用同样的t
和 u
的参数。
如果可以,务必使用
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 块的子项的标签上。
<!-- 当`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
是一个对象包含from
和to
属性,每个属性都包含一个 DOMRect用于描述标签的块状 start
和 end
位置。from
属性是标签的DOMRect对象的起始位置 to
属性是标签经列表遍历和DOM渲染完成后的DOMRect对象的结束位置。
如果返回对象具有 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}
自定义animation函数还可以返回一个名为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}
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的别名
除了 scrollX
和 scrollY
是只读的。
<svelte:window bind:scrollY={y}/>
<svelte:body>
<svelte:body on:event={handler}/>
和<svelte:window>
相同,你可以通过本标签添加监听事件到 document.body
中,例如mouseenter
和 mouseleave
并且不会触发window
。
<svelte:body
on:mouseenter={handleMouseenter}
on:mouseleave={handleMouseleave}
/>
<svelte:head>
<svelte:head>...</svelte:head>
通过该标签可以将元素插入到document.head
中。在服务端渲染时, 内容将插入到html
的head
中。
<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卸载后运行的回调。
相对于 onMount
、 beforeUpdate
、 afterUpdate
和 onDestroy
,它唯一可以运行在服务端渲染组件内部。
<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事件的事件分发器。事件分发器是一个函数,接受两个参数: name
和 detail
。
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 值的函数。它被创建为带有set
和update
方法的对象。
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
模块导出两个函数: tweened
和 spring
。用于创建writable(可写)store,其值会在set
和 update
之后更新,而不是立即更新。
tweened
store = tweened(value: any, options)
Tweened(补间) store 值会在固定时间内更新,可选参数:
delay
(number
, 默认值: 0) — 开始(单位毫秒)。duration
(number
, 默认值:400) — 持续时间(单位毫秒)。easing
(function
, 默认值:t => t
) — easing 函数interpolate
(function
) — 参见下文
store.set
和 store.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>
如果初始化的值是undefined
或null
,第一个值更改将立即生效,当你具有基于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通过stiffness
和 damping
参数逐步变更到目标值,而tweened
store在改变一个固定时间变更其值。store在由它们现有速度决定的持续时间长短,从而实现更自然的运动效果。可选选项:
stiffness
(number
, 默认值:0.15
) — 取值:0-1,数值越大效果越生硬(例,灵敏度)。damping
(number
, 默认值:0.8
) — 取值:0-1,数值越小阻尼越小(例,惯性)。precision
(number
, 默认值:0.001
) — 粒度。用于控制上面两个参数的运动幅度大小。
与tweened
store一样,,set
和 update
在弹性动画完成时返回一个Promise resolves。 其中 store.stiffness
和 store.damping
属性可以立即改变其弹性运动特性。
set
和 update
两者可以用 hard
或soft
属性对象作为第二个参数来表示弹性动画柔度,{ 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>
如果初始值为 undefined
或 null
,则第一个值更改将立即生效,就像使用 tweened
值一样(参阅上文)。
const size = spring();
$: $size = big ? 100 : 10;
svelte/transition
svelte/transition (过渡)
模块具有六个函数: fade
, fly
, slide
, scale
, draw
和 crossfade
。 它与 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
函数计算标签的开始和结束位置并在它们之间进行动画效果,并翻转x
和 y
的值,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(线性)
缓动使用in
, out
和 inOut
轻松生成10种不同的缓动函数:
你可以结合 ease visualiser 和 examples 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(...)
触发默认的异步更新。
默认情况下, accessors
为 false
,除非你要将其作为自定义标签来编译。
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
方法作为可选方法调用。他返回一个具有head
、 html
和 css
属性的对象,其中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编译器进行交互,而是使用捆绑程序插件将其集成到构建系统中
- 如果使用Rollup,请使用rollup-plugin-svelte。
- 如果使用webpack请使用svelte-loader。
- 或者 社区维护的 plugins
尽管如此,了解打包器的用法还是很有用的,因为捆绑程序插件通常向您提供编译器选项。
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" ,则创建一个带有import 和 export 的JavaScript模块,如果是 "cjs" ,创建一个带有require 和module.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 , 则仅为只读导出值创建(即用const 、 class 和 function 声明的值)。如果编译的带有 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 包位置,所有引入来自svelte 或 svelte/[module] 的路径都将被修改。 |
返回的result
对象包含component的代码以及所使用的元数据字节。
const {
js,
css,
ast,
warnings,
vars,
stats
} = svelte.compile(source);
js
和css
是具有以下属性的对象:code
:为JavaScript 字符串。map
:是具有toString()
和toUrl()
的源映射方法。
ast
:是用于表示component结构的抽象(abstract)语法树(syntax tree)。warnings
是在编译期间生成的警告对象的数组。每个警告都有几个属性:code
使用其来说明警告类别的字符串。message
描述问题信息使其易于理解。start
和end
,,如果警告需要指定到特定位置,请使其为一个具备line
、column
和character
属性的对象。frame
,如果含有,是用于标记代码行号突出有问题代码的字符串。Each
vars
是一个component 声明数组, 例如 eslint-plugin-svelte3般使用,每个变量都有几个属性:name
顾名思义。export_name
指定其值导出的名称(如果它需要导出) (除非已指定其name
,负责将使用export...as
导出其name)injected
是true
,声明是由Svelte注入(true)还是由你编写的代码注入(false)。module
为true
且表示在脚本中声明context="module"
。mutated
为true
且将值的属性分配到component内部。reassigned
为true
且表示重新分配值到component内部。referenced
为true
且表示值在声明之外使用值。writable
为true
如果值使用let
或var
(不是const
、class
或function
)来声明。
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对象可以使用 markup
, script
和 style
作为可选函数。
各个 markup
、script
或 style
函数必须返回一个对象 (或以Promise 的 resolves来作为对象返回)和 code
属性来表示改动后的源代码, 以及一个dependencies
数组(可选)。
该markup
将接收到 component 原文本,以及在第三个参数中指定了component的filename
值对应的原文本。
Preprocessor函数可能还会返回一个
map
对象以及对应的code
和dependencies
, 其中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'
});
该 script
和 style
函数接收 <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
函数首先运行, 然后运行 script
和 style
。
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来遍历时,需传入一个带有两种可选方法的对象: enter
和 leave
。其中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}`);