svelte/motion 模块导出了两个函数:tweenedspring,用于创建可写存储,这些存储的值在 setupdate 之后随时间变化,而不是立即变化。

tweened

  1. function tweened<T>(
  2. value?: T | undefined,
  3. defaults?: TweenedOptions<T> | undefined
  4. ): Tweened<T>;

Tweened 存储会在固定持续时间内更新它们的值。以下是可用的选项:

  • delaynumber,默认为 0)— 开始之前的毫秒数
  • durationnumber | function,默认为 400)— tween 持续的毫秒数
  • easingfunction,默认为 t => t)— 一个 easing 函数
  • interpolatefunction)— 见下文

store.setstore.update 可以接受第二个 options 参数,该参数将覆盖在实例化时传入的选项。

两个函数都返回一个 Promise,当 tween 完成时解决。如果 tween 被中断,promise 将永远不会解决。

Svelte 可以开箱即用地在两个数字、两个数组或两个对象(只要数组和对象的形状相同,它们的“叶子”属性也是数字)之间进行插值。

  1. <script>
  2. import { tweened } from 'svelte/motion';
  3. import { cubicOut } from 'svelte/easing';
  4. const size = tweened(1, {
  5. duration: 300,
  6. easing: cubicOut
  7. });
  8. function handleClick() {
  9. // 这等同于 size.update(n => n + 1)
  10. $size += 1;
  11. }
  12. </script>
  13. <button on:click={handleClick} style="transform: scale({$size}); transform-origin: 0 0">
  14. embiggen
  15. </button>

如果初始值为 undefinednull,则第一次值更改将立即生效。这在你有基于 props 的 tweened 值,并且不希望在组件首次渲染时有任何运动时非常有用。

  1. import { tweened } from 'svelte/motion';
  2. import { cubicOut } from 'svelte/easing';
  3. const size = tweened(undefined, {
  4. duration: 300,
  5. easing: cubicOut
  6. });
  7. $: $size = big ? 100 : 10;

interpolate 选项允许你在 任何 任意值之间进行 tween。它必须是一个 (a, b) => t => value 函数,其中 a 是起始值,b 是目标值,t 是 0 到 1 之间的数字,value 是结果。例如,我们可以使用 d3-interpolate 包在两种颜色之间平滑插值。

  1. <script>
  2. import { interpolateLab } from 'd3-interpolate';
  3. import { tweened } from 'svelte/motion';
  4. const colors = ['rgb(255, 62, 0)', 'rgb(64, 179, 255)', 'rgb(103, 103, 120)'];
  5. const color = tweened(colors[0], {
  6. duration: 800,
  7. interpolate: interpolateLab
  8. });
  9. </script>
  10. {#each colors as c}
  11. <button style="background-color: {c}; color: white; border: none;" on:click={(e) => color.set(c)}>
  12. {c}
  13. </button>
  14. {/each}
  15. <h1 style="color: {$color}">{$color}</h1>

spring

  1. function spring<T = any>(
  2. value?: T | undefined,
  3. opts?: SpringOpts | undefined
  4. ): Spring<T>;

spring 存储根据其 stiffnessdamping 参数逐渐变为其目标值。与 tweened 存储在固定持续时间内更改其值不同,spring 存储的更改时间由其现有速度决定,允许在许多情况下更自然地运动。以下是可用的选项:

  • stiffnessnumber,默认为 0.15)— 0 到 1 之间的值,数值越高意味着 ‘更紧’ 的弹簧
  • dampingnumber,默认为 0.8)— 0 到 1 之间的值,数值越低意味着 ‘更有弹性’ 的弹簧
  • precisionnumber,默认为 0.01)— 确定弹簧被认为 ‘稳定’ 的阈值,数值越低意味着更精确

上述所有选项都可以在弹簧运动时更改,并会立即生效。

  1. import { spring } from 'svelte/motion';
  2. const size = spring(100);
  3. size.stiffness = 0.3;
  4. size.damping = 0.4;
  5. size.precision = 0.005;

tweened 存储一样,setupdate 返回一个 Promise,如果弹簧稳定则解决。

setupdate 都可以接受第二个参数 —— 一个具有 hardsoft 属性的对象。{ hard: true } 立即设置目标值;{ soft: n }n 秒内保留现有动量然后稳定。{ soft: true } 等同于 { soft: 0.5 }

  1. import { spring } from 'svelte/motion';
  2. const coords = spring({ x: 50, y: 50 });
  3. // 立即更新值
  4. coords.set({ x: 100, y: 200 }, { hard: true });
  5. // 保留 1s 的现有动量
  6. coords.update(
  7. (target_coords, coords) => {
  8. return { x: target_coords.x, y: coords.y };
  9. },
  10. { soft: 1 }
  11. );

在弹簧教程中查看完整示例。

  1. <script>
  2. import { spring } from 'svelte/motion';
  3. const coords = spring(
  4. { x: 50, y: 50 },
  5. {
  6. stiffness: 0.1,
  7. damping: 0.25
  8. }
  9. );
  10. </script>

如果初始值是 undefinednull,第一次值更改将立即生效,就像 tweened 值一样(见上文)。

  1. import { spring } from 'svelte/motion';
  2. const size = spring();
  3. $: $size = big ? 100 : 10;

类型

Spring

  1. interface Spring<T> extends Readable<T> {…}
  1. set: (new_value: T, opts?: SpringUpdateOpts) => Promise<void>;
  1. update: (fn: Updater<T>, opts?: SpringUpdateOpts) => Promise<void>;
  1. precision: number;
  1. damping: number;
  1. stiffness: number;

Tweened

  1. interface Tweened<T> extends Readable<T> {…}
  1. set(value: T, opts?: TweenedOptions<T>): Promise<void>;
  1. update(updater: Updater<T>, opts?: TweenedOptions<T>): Promise<void>;