是否可以手动取消并重新触发 Svelte 动画?

Is it possible to manually cancel and retrigger a Svelte animation?

我有一个动画取决于可写存储的值。

例如:

{#if $isWorking}
    <span in:fade="{{duration: 200, delay: 750}}">Working...</span>
{/if}

问题是如果存储的值变化足够快,转换将不会重新开始。 Here's is a REPL that demonstrates this behavior.

我想这是因为 Svelte 非常高效。我的猜测是,如果 $isWorking 的值在下一帧开始时相同,Svelte 将决定它没有改变,并将继续进行过渡。

这似乎是一个很好的默认行为,但有没有办法避免这种情况并手动重置动画?在这种情况下,要在 $isWorking 存储更改时重新启动延迟?

我想出了一个技巧来避免使用过渡的 delay 属性 并使用 setTimeout:

自己实现它
let show = false;
let timeout;

isWorking.subscribe((value) => {
    show = false;
    if (timeout) clearTimeout(timeout);

    timeout = setTimeout(() => {
        showState = true;
    }, 750);
});

{#if show}
    <span in:fade="{{duration: 200}}">Working</span>
{/if}

是否有更 Svelty 的方法来解决这个问题?

您可以为此使用 tick

<script>
    import { fade } from 'svelte/transition';
    import { tick } from 'svelte';
    let show = false;
    
    async function onInput () {
        show = false;
        await tick();
        show = true;
    }
</script>

<input on:input={onInput}>

{#if show}
    <span in:fade="{{duration: 200, delay: 500}}">working...</span>
{/if}

Svelte 会收集所有的前奏和结尾,并等待下一帧来批量更新视图。如果你的状态在同一个微任务中发生变化,那么 Svelte 将不会注意到它。在这种情况下,您可以使用 tick 强制 Svelte 更新视图。