在 上一章 中,我们使用延迟转换来创建运动的幻觉,因为元素从一个待办事项列表移动到另一个待办事项列表。
¥In the previous chapter, we used deferred transitions to create the illusion of motion as elements move from one todo list to the other.
为了完成幻觉,我们还需要对未过渡的元素应用运动。为此,我们使用 animate
指令。
¥To complete the illusion, we also need to apply motion to the elements that aren’t transitioning. For this, we use the animate
directive.
首先,将 flip
函数(flip 代表 ‘第一个、最后一个、反转、播放’)从 svelte/animate
导入到 TodoList.svelte
:
¥First, import the flip
function — flip stands for ‘First, Last, Invert, Play’ — from svelte/animate
into TodoList.svelte
:
<script>
import { flip } from 'svelte/animate';
import { send, receive } from './transition.js';
let { todos, remove } = $props();
</script>
<script lang="ts">
import { flip } from 'svelte/animate';
import { send, receive } from './transition.js';
let { todos, remove } = $props();
</script>
然后将其添加到 <li>
元素中:
¥Then add it to the <li>
elements:
<li
class={{ done: todo.done }}
in:receive={{ key: todo.id }}
out:send={{ key: todo.id }}
animate:flip
>
在这种情况下,移动有点慢,所以我们可以添加一个 duration
参数:
¥The movement is a little slow in this case, so we can add a duration
parameter:
<li
class={{ done: todo.done }}
in:receive={{ key: todo.id }}
out:send={{ key: todo.id }}
animate:flip={{ duration: 200 }}
>
duration
也可以是d => milliseconds
函数,其中d
是元素必须行进的像素数¥[!NOTE]
duration
can also be ad => milliseconds
function, whered
is the number of pixels the element has to travel
请注意,所有过渡和动画都是使用 CSS 而不是 JavaScript 应用的,这意味着它们不会阻止(或被)主线程阻止。
¥Note that all the transitions and animations are being applied with CSS, rather than JavaScript, meaning they won’t block (or be blocked by) the main thread.
<script>
import TodoList from './TodoList.svelte';
const todos = $state([
{ id: 1, done: false, description: 'write some docs' },
{ id: 2, done: false, description: 'start writing blog post' },
{ id: 3, done: true, description: 'buy some milk' },
{ id: 4, done: false, description: 'mow the lawn' },
{ id: 5, done: false, description: 'feed the turtle' },
{ id: 6, done: false, description: 'fix some bugs' }
]);
let uid = todos.length + 1;
function remove(todo) {
const index = todos.indexOf(todo);
todos.splice(index, 1);
}
</script>
<div class="board">
<input
placeholder="what needs to be done?"
onkeydown={(e) => {
if (e.key !== 'Enter') return;
todos.push({
id: uid++,
done: false,
description: e.currentTarget.value
});
e.currentTarget.value = '';
}}
/>
<div class="todo">
<h2>todo</h2>
<TodoList todos={todos.filter((t) => !t.done)} {remove} />
</div>
<div class="done">
<h2>done</h2>
<TodoList todos={todos.filter((t) => t.done)} {remove} />
</div>
</div>
<style>
.board {
display: grid;
grid-template-columns: 1fr 1fr;
grid-column-gap: 1em;
max-width: 36em;
margin: 0 auto;
}
.board > input {
font-size: 1.4em;
grid-column: 1/3;
padding: 0.5em;
margin: 0 0 1rem 0;
}
h2 {
font-size: 2em;
font-weight: 200;
}
</style>