Svelte延时过渡

Svelte 延时过渡

Svelte 过渡引擎其中一项特别强大的功能就是可以设置延时(defer) 过渡,以便多个效果之间协调。以这todo lists为例, 在其中更换todo将其发送到相对的列表中。在真实世界中,物体的移动不是这般生硬,它们是有其运动轨迹,而不像这般突然出现。给程序添加运动效果能更好的帮助用户了解程序界面变化。我们可以使用crossfade 函数来实现此效果,该函数创建一对称名为 send 和receive. 当一个标签被 'sent'时, 它会寻找一个被'received'的标签,并赋予一个过渡效果,反之同理。如果没有对应的接收方,过渡效果将会设置为fallback 。在65行找到 <label>标签, 给它添加send 和 receive 过渡:<label

in:receive="{{key: todo.id}}"

out:send="{{key: todo.id}}"

>对下一个 <label> 标签执行相同的操作:<label

class="done"

in:receive="{{key: todo.id}}"

out:send="{{key: todo.id}}"

>现在,当您切换列表项时,它们会平滑移动到新位置,没有添加过渡效果的标签仍然笨拙地跳来跳去,我们将下一章中解决它。示例代码App.svelte<script>

import { quintOut } from 'svelte/easing';

import { crossfade } from 'svelte/transition';

const [send, receive] = crossfade({

duration: d =&gt; Math.sqrt(d * 200),

fallback(node, params) {

const style = getComputedStyle(node);

const transform = style.transform === 'none' ? '' : style.transform;

return {

duration: 600,

easing: quintOut,

css: t =&gt; `

transform: ${transform} scale(${t});

opacity: ${t}

`

};

}

});

let uid = 1;

let todos = [

{ id: uid++, done: false, description: 'write some docs' },

{ id: uid++, done: false, description: 'start writing blog post' },

{ id: uid++, done: true, description: 'buy some milk' },

{ id: uid++, done: false, description: 'mow the lawn' },

{ id: uid++, done: false, description: 'feed the turtle' },

{ id: uid++, done: false, description: 'fix some bugs' },

];

function add(input) {

const todo = {

id: uid++,

done: false,

description: input.value

};

todos = [todo, ...todos];

input.value = '';

}

function remove(todo) {

todos = todos.filter(t =&gt; t !== todo);

}

function mark(todo, done) {

todo.done = done;

remove(todo);

todos = todos.concat(todo);

}

</script>

<div class='board'>

<input

placeholder="what needs to be done?"

on:keydown={e => e.which === 13 && add(e.target)}

>

&lt;div class='left'&gt;

&lt;h2&gt;todo&lt;/h2&gt;

{#each todos.filter(t =&gt; !t.done) as todo (todo.id)}

&lt;label

in:receive="{{key: todo.id}}"

out:send="{{key: todo.id}}"

&gt;

&lt;input type=checkbox on:change={() =&gt; mark(todo, true)}&gt;

{todo.description}

&lt;button on:click="{() =&gt; remove(todo)}"&gt;remove&lt;/button&gt;

&lt;/label&gt;

{/each}

&lt;/div&gt;

&lt;div class='right'&gt;

&lt;h2&gt;done&lt;/h2&gt;

{#each todos.filter(t =&gt; t.done) as todo (todo.id)}

&lt;label

class="done"

in:receive="{{key: todo.id}}"

out:send="{{key: todo.id}}"

&gt;

&lt;input type=checkbox checked on:change={() =&gt; mark(todo, false)}&gt;

{todo.description}

&lt;button on:click="{() =&gt; remove(todo)}"&gt;remove&lt;/button&gt;

&lt;/label&gt;

{/each}

&lt;/div&gt;

</div>

<style>

.board {

display: grid;

grid-template-columns: 1fr 1fr;

grid-gap: 1em;

max-width: 36em;

margin: 0 auto;

}

.board &gt; input {

font-size: 1.4em;

grid-column: 1/3;

}

h2 {

font-size: 2em;

font-weight: 200;

user-select: none;

margin: 0 0 0.5em 0;

}

label {

position: relative;

line-height: 1.2;

padding: 0.5em 2.5em 0.5em 2em;

margin: 0 0 0.5em 0;

border-radius: 2px;

user-select: none;

border: 1px solid hsl(240, 8%, 70%);

background-color:hsl(240, 8%, 93%);

color: #333;

}

input[type="checkbox"] {

position: absolute;

left: 0.5em;

top: 0.6em;

margin: 0;

}

.done {

border: 1px solid hsl(240, 8%, 90%);

background-color:hsl(240, 8%, 98%);

}

button {

position: absolute;

top: 0;

right: 0.2em;

width: 2em;

height: 100%;

background: no-repeat 50% 50% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23676778' d='M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M17,7H14.5L13.5,6H10.5L9.5,7H7V9H17V7M9,18H15A1,1 0 0,0 16,17V10H8V17A1,1 0 0,0 9,18Z'%3E%3C/path%3E%3C/svg%3E");

background-size: 1.4em 1.4em;

border: none;

opacity: 0;

transition: opacity 0.2s;

text-indent: -9999px;

cursor: pointer;

}

label:hover button {

opacity: 1;

}

</style>