Skip to main content
基本 Svelte
介绍
反应性
属性
逻辑
事件
绑定
类和样式
动作
转换
高级 Svelte
高级反应性
重用内容
运动
高级绑定
高级转换
上下文 API
特殊元素
<script module>
后续步骤
基本 SvelteKit
介绍
路由
加载数据
标题和 cookie
共享模块
表单
API 路由
$app/state
错误和重定向
高级 SvelteKit
钩子
页面选项
链接选项
高级路由
高级加载
环境变量
结论

svelte/transition 模块有一些内置转换,但创建自己的转换非常容易。例如,这是 fade 转换的来源:

¥The svelte/transition module has a handful of built-in transitions, but it’s very easy to create your own. By way of example, this is the source of the fade transition:

function fade(node, { delay = 0, duration = 400 }) {
	const o = +getComputedStyle(node).opacity;

	return {
		delay,
		duration,
		css: (t) => `opacity: ${t * o}`
	};
}

该函数接受两个参数 — 应用转换的节点以及传入的任何参数 — 并返回一个转换对象,该对象可以具有以下属性:

¥The function takes two arguments — the node to which the transition is applied, and any parameters that were passed in — and returns a transition object which can have the following properties:

  • delay — 过渡开始前的毫秒数

    ¥delay — milliseconds before the transition begins

  • duration — 转换长度(以毫秒为单位)

    ¥duration — length of the transition in milliseconds

  • easingp => t 缓和函数(参见 tweening 章节)

    ¥easing — a p => t easing function (see the chapter on tweening)

  • css(t, u) => css 函数,其中 u === 1 - t

    ¥css — a (t, u) => css function, where u === 1 - t

  • tick — 对节点有一定影响的 (t, u) => {...} 函数

    ¥tick — a (t, u) => {...} function that has some effect on the node

在介绍的开头或结尾的结尾处,t 的值是 0,在介绍的结尾或结尾的开头处,t 的值是 1

¥The t value is 0 at the beginning of an intro or the end of an outro, and 1 at the end of an intro or beginning of an outro.

大多数情况下,你应该返回 css 属性而不是 tick 属性,因为 CSS 动画在主线程之外运行,以尽可能防止卡顿。Svelte ‘simulates’ 过渡并构建 CSS 动画,然后让它运行。

¥Most of the time you should return the css property and not the tick property, as CSS animations run off the main thread to prevent jank where possible. Svelte ‘simulates’ the transition and constructs a CSS animation, then lets it run.

例如,fade 转换会生成类似这样的 CSS 动画:

¥For example, the fade transition generates a CSS animation somewhat like this:

0% { opacity: 0 }
10% { opacity: 0.1 }
20% { opacity: 0.2 }
/* ... */
100% { opacity: 1 }

不过,我们可以更有创意。让我们做一些真正无偿的事情:

¥We can get a lot more creative though. Let’s make something truly gratuitous:

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

	let visible = $state(true);

	function spin(node, { duration }) {
		return {
			duration,
			css: (t, u) => {
				const eased = elasticOut(t);

				return `
					transform: scale(${eased}) rotate(${eased * 1080}deg);
					color: hsl(
						${Math.trunc(t * 360)},
						${Math.min(100, 1000 * u)}%,
						${Math.min(50, 500 * u)}%
					);`
			}
		};
	}
</script>
<script lang="ts">
	import { fade } from 'svelte/transition';
	import { elasticOut } from 'svelte/easing';

	let visible = $state(true);

	function spin(node, { duration }) {
		return {
			duration,
			css: (t, u) => {
				const eased = elasticOut(t);

				return `
					transform: scale(${eased}) rotate(${eased * 1080}deg);
					color: hsl(
						${Math.trunc(t * 360)},
						${Math.min(100, 1000 * u)}%,
						${Math.min(50, 500 * u)}%
					);`
			}
		};
	}
</script>

记住:能力越大,责任越大。

¥Remember: with great power comes great responsibility.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<script>
	import { fade } from 'svelte/transition';
 
	let visible = $state(true);
 
	function spin(node, { duration }) {
		return {
			duration,
			css: (t, u) => ``
		};
	}
</script>
 
<label>
	<input type="checkbox" bind:checked={visible} />
	visible
</label>
 
{#if visible}
	<div
		class="centered"
		in:spin={{ duration: 8000 }}
		out:fade
	>
		<span>transitions!</span>
	</div>
{/if}
 
<style>
	.centered {
		position: absolute;
		left: 50%;
		top: 50%;
		transform: translate(-50%, -50%);
	}
 
	span {
		position: absolute;
		transform: translate(-50%, -50%);
		font-size: 4em;
	}
</style>