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 beginsduration
— 转换长度(以毫秒为单位)¥
duration
— length of the transition in millisecondseasing
—p => t
缓和函数(参见 tweening 章节)¥
easing
— ap => t
easing function (see the chapter on tweening)css
—(t, u) => css
函数,其中u === 1 - t
¥
css
— a(t, u) => css
function, whereu === 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:
<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.
<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>