Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • HTML

    • 常用meta整理
    • Particles.js粒子效果库
    • Vanta.js3D背景库
    • lorem 乱数假文
    • 图片裁剪插件cropper.js
    • scrollIntoView 用法
    • 视图过渡动画
      • canvas自定义实现粒子动画
      • 一张图理解浏览器的位置和尺寸
      • HTML5 全屏讲解
      • 获取元素的宽高
      • 零宽字符
    • CSS

    • 浏览器

    • 页面
    • HTML
    东流
    2024-06-06
    目录

    视图过渡动画

    # 概述

    网站的主题切换无非就是文字、背景图片或者颜色,我们可以先来看下 Element UI 官网的切换主题的动效:

    # 实现的两种方式

    # CSS 为主

    <script setup>
    const changeTheme = (e) => {
      if (document.startViewTransition) {
        document.startViewTransition(() => {
          document.documentElement.classList.toggle("dark");
        });
      } else {
        document.documentElement.classList.toggle("dark");
      }
    };
    
    onMounted(() => {
      const target = document.querySelector(".target1");
      const { x, y } = target.getBoundingClientRect();
      document.documentElement.style.setProperty("--x", x + "px");
      document.documentElement.style.setProperty("--y", y + "px");
    });
    </script>
    <style>
    ::view-transition-old(root) {
      animation: none;
    }
    ::view-transition-new(root) {
      mix-blend-mode: normal;
      animation: clip 1s ease-in;
    }
    
    @keyframes clip {
      from {
        clip-path: circle(0% at var(--x) var(--y));
      }
      to {
        clip-path: circle(100% at var(--x) var(--y));
      }
    }
    </style>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    # JS 实现

    <script setup>
    const changeTheme = (e) => {
      if (document.startViewTransition) {
        const transition = document.startViewTransition(() => {
          document.documentElement.classList.toggle("dark");
        });
        transition.ready.then(() => {
          const target = document.querySelector(".target");
          const { x, y } = target.getBoundingClientRect();
    
          const radius = Math.hypot(
            Math.max(innerWidth - x, x),
            Math.max(innerHeight - y, y)
          );
    
          const clipPath = [
            `circle(0px at ${x}px ${y}px)`,
            `circle(${radius}px at ${x}px ${y}px)`,
          ];
    
          const isDark = !document.documentElement.classList.contains("dark");
    
          document.documentElement.animate(
            { clipPath: isDark ? clipPath : clipPath.reverse() },
            {
              duration: 1500,
              pseudoElement: isDark
                ? "::view-transition-new(root)"
                : "::view-transition-old(root)",
            }
          );
        });
      } else {
        document.documentElement.classList.toggle("dark");
      }
    };
    </script>
    <style>
    ::view-transition-old(root) {
      animation: none;
    }
    </style>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42

    # 总结

    第一种方式就是定义了一个帧景动画,然后通过 startViewTransition 方法来触发动画。而第二种则是在startViewTransition的ready阶段,通过document.documentElement.animate自定义动画实现 startViewTransition`是View Transition API 的一部分,它允许我们定义一个动画,然后让浏览器来执行这个动画。

    # View Transition API

    View Transition API 提供了一种机制,可以在更新 DOM 内容的同时,轻松过地创建不同 DOM 状态之间地动画过渡,同时还可以在单个步骤中更新 DOM 内容.

    以往在 SPA 中,状态之间的过渡编写较多的代码来解决几个问题:

    • 处理新旧内容的加载和定位
    • 为新旧状态添加动画以创建过渡
    • 防止用户与旧内容的意外交互而导致的问题
    • 完成过渡后删除旧内容

    而View Transition API就提供了一种更简单的方法来处理必须的 DOM 更新和过渡动画

    视图过渡过程

    • 调用document.startViewTransition(),API 会截取当前页面的屏幕截图
    • 执行startViewTransition()中的回调函数,这会导致 DOM 发生更改,当回调函数成功运行时,updateCallbackDone API 兑现,可以响应 DOM 更新
    • API 会捕获页面的新状态并实时展示
    • API 构造一个具有以下结构的伪元素树
    ::view-transition // 视图过渡叠加层的根元素,它包含所有试图过渡且位于所有页面内容的顶部
    └─ ::view-transition-group(root) // 视图过渡分组元素,它包含所有视图过渡元素
       └─ ::view-transition-image-pair(root) // 视图过渡图像对元素,它包含两个子元素,分别表示旧页面和新页面
          ├─ ::view-transition-old(root) // 视图过渡旧元素,它表示旧页面的屏幕截图
          └─ ::view-transition-new(root) // 视图过渡新元素,它表示新页面
    
    1
    2
    3
    4
    5

    当过渡动画即将运行时,ready Promise 兑现,可以执行某些操作,比如自定义动画

    • 旧页面视图到新页面的视图过渡动画
    • 当过渡动画结束时,finished Promise 兑现,可以响应某些操作

    # document.documentElement.animate

    Element接口的animate方法是创建一个Animation的便捷方法并将其应用于元素,然后运行动画。另外该方法会将Animation对象实例返回,该实例可以控制动画的播放、暂停、停止等。

    用法如下:

    element.animate(keyframes, options);
    
    1

    参数说明:

    • keyframes: 动画关键帧,可以是一个对象数组,也可以是一个KeyframeEffect对象
    • options: 动画选项,可以是一个对象,也可以是一个数字,数字表示动画持续时间
    编辑 (opens new window)
    上次更新: 2024/08/24, 14:18:38
    scrollIntoView 用法
    canvas自定义实现粒子动画

    ← scrollIntoView 用法 canvas自定义实现粒子动画→

    最近更新
    01
    GeoJSON
    05-08
    02
    Circle
    04-15
    03
    CircleMarker
    04-15
    更多文章>
    Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式