Svelte 最新中文文档翻译(11)—— 动画相关语法 transition、in、out、animate

冴羽
• 阅读 51

前言

Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1

Svelte 最新中文文档翻译(11)—— 动画相关语法 transition、in、out、animate

Svelte 以其独特的编译时优化机制著称,具有轻量级高性能易上手等特性,非常适合构建轻量级 Web 项目,也是我做个人项目的首选技术栈。

目前 Svelte 基于 Svelte 5 发布了最新的官方文档,但却缺少对应的中文文档。为了帮助大家学习 Svelte,为爱发电翻译了官方文档。

我同时搭建了 Svelte 最新的中文文档站点:https://svelte.yayujs.com ,如果需要辅助学习,也可以入手我的小册《Svelte 开发指南》,语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!

虽说是翻译,但个人并不喜欢严格遵守原文,为了保证中文阅读流畅,会删减部分语句,对难懂的部分也会另做补充解释,希望能给大家带来一个好的中文学习体验。

欢迎围观我的“网页版朋友圈”、加入“低调务实优秀中国好青年”前端社群,分享技术,带你成长。

transition:

当元素由于状态变化而进入或离开 DOM 时,会触发*transition(过渡)*效果。

当一个块(比如 {#if ...} 块)正在过渡退出时,其中的所有元素,包括那些没有自己的过渡效果的元素,都会保留在 DOM 中,直到该块中的所有过渡都完成。

transition: 指令表示 双向 过渡,这意味着在过渡进行过程中可以平滑地反向执行。

<script>
  +++import { fade } from 'svelte/transition';+++

  let visible = $state(false);
</script>

<button onclick={() => visible = !visible}>toggle</button>

{#if visible}
  <div +++transition:fade+++>淡入淡出效果</div>
{/if}

内置过渡

可以从 svelte/transition 模块导入一系列内置的过渡效果。

局部 vs 全局

过渡默认是局部的。局部过渡只在它们所属的块被创建或销毁时播放,而 不会 在父块被创建或销毁时播放。

{#if x}
  {#if y}
    <p transition:fade>仅在 y 变化时淡入淡出</p>

    <p transition:fade|global>在 x 或 y 变化时淡入淡出</p>
  {/if}
{/if}

过渡参数

过渡可以有参数。

(双 {{大括号}} 不是特殊语法;这是表达式标签内的对象字面量。)

{#if visible}
  <div transition:fade={{ duration: 2000 }}>在两秒内淡入淡出</div>
{/if}

自定义过渡函数

/// copy: false
// @noErrors
transition = (node: HTMLElement, params: any, options: { direction: 'in' | 'out' | 'both' }) => {
  delay?: number,
  duration?: number,
  easing?: (t: number) => number,
  css?: (t: number, u: number) => string,
  tick?: (t: number, u: number) => void
}

过渡可以使用自定义函数。如果返回的对象有 css 函数,Svelte 将为 Web 动画 生成关键帧。

传递给 css 的参数 t 是一个介于 01 之间的值,这个值已经经过 easing 函数处理。入场 过渡从 01退场 过渡从 10 —— 换句话说,1 是元素的自然状态,就像没有应用过渡一样。参数 u 等于 1 - t

该函数会在过渡开始 之前 被反复调用,每次调用时都会传入不同的 tu 参数。

<!--- file: App.svelte --->
<script>
  import { elasticOut } from 'svelte/easing';

  /** @type {boolean} */
  export let visible;

  /**
   * @param {HTMLElement} node
   * @param {{ delay?: number, duration?: number, easing?: (t: number) => number }} params
   */
  function whoosh(node, params) {
    const existingTransform = getComputedStyle(node).transform.replace('none', '');

    return {
      delay: params.delay || 0,
      duration: params.duration || 400,
      easing: params.easing || elasticOut,
      css: (t, u) => `transform: ${existingTransform} scale(${t})`
    };
  }
</script>

{#if visible}
  <div in:whoosh>呼啸而入</div>
{/if}

自定义过渡函数还可以返回一个 tick 函数,该函数会在过渡 过程中 被调用,同样会传入 tu 参数。

[!NOTE] 如果可以使用 css 而不是 tick,那就尽可能使用 css —— Web 动画可以在主线程之外运行,防止在性能较低的设备上出现卡顿。

<!--- file: App.svelte --->
<script>
  export let visible = false;

  /**
   * @param {HTMLElement} node
   * @param {{ speed?: number }} params
   */
  function typewriter(node, { speed = 1 }) {
    const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE;

    if (!valid) {
      throw new Error(`此过渡效果只适用于具有单个文本节点子元素的元素`);
    }

    const text = node.textContent;
    const duration = text.length / (speed * 0.01);

    return {
      duration,
      tick: (t) => {
        const i = ~~(text.length * t);
        node.textContent = text.slice(0, i);
      }
    };
  }
</script>

{#if visible}
  <p in:typewriter={{ speed: 1 }}>敏捷的棕色狐狸跳过了懒狗</p>
{/if}

如果过渡返回一个函数而不是过渡对象,该函数将在下一个微任务中被调用。这允许多个过渡进行协调,使 交叉淡入淡出效果 成为可能。

过渡函数还会接收第三个参数 options,其中包含有关过渡的信息。

options 对象中可用的值为:

  • direction - 过渡的类型,可以是 inoutboth 之一

过渡事件

具有过渡效果的元素除了标准的 DOM 事件外,还会触发以下事件:

  • introstart(入场开始)
  • introend(入场结束)
  • outrostart(退场开始)
  • outroend(退场结束)
{#if visible}
  <p
    transition:fly={{ y: 200, duration: 2000 }}
    onintrostart={() => (status = '入场开始')}
    onoutrostart={() => (status = '退场开始')}
    onintroend={() => (status = '入场结束')}
    onoutroend={() => (status = '退场结束')}
  >
    飞入飞出
  </p>
{/if}

in: 和 out:

in:out: 指令与 transition: 相同,只是产生的过渡不是双向的 — 如果在过渡进行过程中块被移出,in 过渡将继续与 out 过渡一起"播放",而不是反向运行。如果 out 过渡被中止,过渡将从头开始。

<script>
  import { fade, fly } from 'svelte/transition';

  let visible = $state(false);
</script>

<label>
  <input type="checkbox" bind:checked={visible}>
  可见
</label>

{#if visible}
  <div in:fly={{ y: 200 }} out:fade>飞入,淡出</div>
{/if}

animate:

带键的 each 块的内容重新排序时,会触发动画。动画不会在元素添加或删除时运行,只会在 each 块内现有数据项的索引发生变化时运行。animate 指令必须在带键的 each 块的直接子元素上使用。

动画可以与 Svelte 的内置动画函数自定义动画函数一起使用。

<!-- 当 `list` 重新排序时动画将会运行 -->
{#each list as item, index (item)}
  <li animate:flip>{item}</li>
{/each}

动画参数

与 actions 和过渡一样,动画也可以有参数。

(双重 {{大括号}} 不是特殊语法;这是表达式标签内的对象字面量。)

{#each list as item, index (item)}
  <li animate:flip={{ delay: 500 }}>{item}</li>
{/each}

自定义动画函数

/// copy: false
// @noErrors
animation = (node: HTMLElement, { from: DOMRect, to: DOMRect } , params: any) => {
  delay?: number,
  duration?: number,
  easing?: (t: number) => number,
  css?: (t: number, u: number) => string,
  tick?: (t: number, u: number) => void
}

动画可以使用自定义函数,这些函数接收 nodeanimation 对象和任何 parameters 作为参数。

animation 参数是一个包含 fromto 属性的对象,每个属性都包含一个 DOMRect,描述元素在其 开始结束 位置的几何形状。

from 属性是元素在其起始位置的 DOMRect,而 to 属性是列表重新排序且 DOM 更新后元素在其最终位置的 DOMRect。

如果返回的对象有 css 方法,Svelte 将创建一个在元素上播放的web 动画

传递给 csst 参数是一个在应用 easing 函数后从 01 的值。u 参数等于 1 - t

该函数会在动画开始之前被反复调用,并传入不同的 tu 参数。

<!--- file: App.svelte --->
<script>
  import { cubicOut } from 'svelte/easing';

  /**
   * @param {HTMLElement} node
   * @param {{ from: DOMRect; to: DOMRect }} states
   * @param {any} params
   */
  function whizz(node, { from, to }, params) {
    const dx = from.left - to.left;
    const dy = from.top - to.top;

    const d = Math.sqrt(dx * dx + dy * dy);

    return {
      delay: 0,
      duration: Math.sqrt(d) * 120,
      easing: cubicOut,
      css: (t, u) => `transform: translate(${u * dx}px, ${u * dy}px) rotate(${t * 360}deg);`
    };
  }
</script>

{#each list as item, index (item)}
  <div animate:whizz>{item}</div>
{/each}

自定义动画函数还可以返回一个 tick 函数,该函数会在动画期间被调用,并带有相同的 tu 参数。

[!NOTE] 如果可以使用 css 而不是 tick,那就尽可能使用 css — web 动画可以在主线程之外运行,防止在较慢的设备上出现卡顿。

<!--- file: App.svelte --->
<script>
  import { cubicOut } from 'svelte/easing';

  /**
   * @param {HTMLElement} node
   * @param {{ from: DOMRect; to: DOMRect }} states
   * @param {any} params
   */
  function whizz(node, { from, to }, params) {
    const dx = from.left - to.left;
    const dy = from.top - to.top;

    const d = Math.sqrt(dx * dx + dy * dy);

    return {
      delay: 0,
      duration: Math.sqrt(d) * 120,
      easing: cubicOut,
      tick: (t, u) => Object.assign(node.style, { color: t > 0.5 ? 'Pink' : 'Blue' })
    };
  }
</script>

{#each list as item, index (item)}
  <div animate:whizz>{item}</div>
{/each}

Svelte 中文文档

本篇已收录在掘金专栏 《Svelte 中文文档》,该系列预计 40 篇。

系统学习 Svelte,欢迎入手小册《Svelte 开发指南》。语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!

此外我还写过 JavaScript 系列TypeScript 系列React 系列Next.js 系列冴羽答读者问等 14 个系列文章, 全系列文章目录:https://github.com/mqyqingfeng/Blog

通过文字建立交流本身就是一种缘分,欢迎围观我的“网页版朋友圈”、加入“低调务实优秀中国好青年”前端社群,分享技术,带你成长。

点赞
收藏
评论区
推荐文章
冴羽 冴羽
4星期前
Svelte 最新中文文档翻译(1)—— 概述与入门指南
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
4星期前
Svelte 最新中文文档翻译(2)—— .svelte、.svelte.js 和 .svelte.ts 文件
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
4星期前
Svelte 最新中文文档翻译(3)—— 符文(Runes)上
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
4星期前
Svelte 最新中文文档翻译(4)—— 符文(Runes)下
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
1星期前
Svelte 最新中文文档翻译(5)—— 基础标记
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
1星期前
Svelte 最新中文文档翻译(6)—— if、each、key、await 逻辑区块
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
3天前
Svelte 最新中文文档翻译(7)—— snippet 与 @render
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
3天前
Svelte 最新中文文档翻译(8)—— @html、@const、@debug 模板语法
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
3天前
Svelte 最新中文文档翻译(9)—— bind: 模板语法
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽 冴羽
3天前
Svelte 最新中文文档翻译(10)—— use: 与 Actions
前言Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上
冴羽
冴羽
Lv1
男 · 淘宝 · 前端工程师
分享技术,也分享人生。GitHub 中国区 Top 30,掘金签约作者,掘金前端领域关注数 Top 1。至今写过 14 个系列、几百篇技术文章,全网千万阅读。
文章
45
粉丝
16
获赞
67