惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyberwarzone
Cyberwarzone
F
Full Disclosure
V
Visual Studio Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
有赞技术团队
有赞技术团队
J
Java Code Geeks
博客园 - 【当耐特】
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 叶小钗
L
LINUX DO - 最新话题
T
Threatpost
S
SegmentFault 最新的问题
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
C
Cyber Attacks, Cyber Crime and Cyber Security
Google DeepMind News
Google DeepMind News
Know Your Adversary
Know Your Adversary
S
Schneier on Security
V
Vulnerabilities – Threatpost
D
DataBreaches.Net
G
GRAHAM CLULEY
Latest news
Latest news
P
Privacy International News Feed
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
Scott Helme
Scott Helme
L
Lohrmann on Cybersecurity
T
The Exploit Database - CXSecurity.com
Security Latest
Security Latest
G
Google Developers Blog
L
LangChain Blog
MyScale Blog
MyScale Blog
Project Zero
Project Zero
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
阮一峰的网络日志
阮一峰的网络日志
N
News | PayPal Newsroom
www.infosecurity-magazine.com
www.infosecurity-magazine.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
SecWiki News
SecWiki News
T
Tor Project blog
C
Check Point Blog
Google Online Security Blog
Google Online Security Blog
GbyAI
GbyAI
The Last Watchdog
The Last Watchdog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
WordPress大学
WordPress大学

Leon.D’s Blog

Howdz起始页开发记录 利用G渲染器实现的音频可视化方案 Vue3实现自定义右键菜单 Dashboard自定义面板项目介绍 开发Online Code Editor过程的一些记录 Howdyjs组件库迁移Vue3设计与总结 使用D3.js将离散的点形成平滑曲线及其应用 使用Taro-next将个人网盘功能扩展到微信小程序 Vue3上手, 使用vite实现一个简单的Todolist应用 断点续传与个人网盘系统的前后端设计 个人组件库展示站点搭建总结 Github Webhooks与Koa2实现简单的前端自动化部署 浏览器导航首页设计 CSS实现判断鼠标进入方向 简易电商系统开发记录(Nuxtjs+Koa) 考试系统设计总结
使用Element.animate添加文字与图片动画
2021-12-01 · via Leon.D’s Blog

在网页添加一些简单的切换动画一般使用 CSS3 的 animation 或者 transition 实现,而 Element.animate 是新的原生 Javascript Api,能使用 JS 快速为 Dom 添加动画。

前言

为了增加网站的用户体验,在很多场景下一般可以为元素的切换添加一下转场动画。

最简单的方法,一般可以使用 CSS 的transition或者animation实现。当前也有很多 CSS 动画库,例如animate.css,它与wow.js搭配使用经常用于很多产品宣传首页。

当然我们也可以使用一些主流的 JS 动画库操作某些元素的单独动画,例如:VelocityAnime.js等。或者更传统的Jquery也有提供.animate操作动画的方案。

而本文则介绍一下原生较新的 Javascript Api: Element.animate()

关于 Element.animate

Element.animate()Web Animations API提供的使用 Javascript 操作元素动画的解决方案。

参数

Element.animate(keyframes, options)方法接收 2 个参数,第一个为keyframes,第二个为options

keyframes:与 CSS3 的 keyframes 的概念是一致的,代表关键帧的集合。它可以接收一个关键帧数组,也可以简写成一个对象。它支持所有 CSS 动画支持的属性,另简写写法添加offset, float, easing等关键字 。具体写法请参考Keyframe Formats (MDN)或下文的案例使用。

options: 动画的相关配置。其接收delay, duration, easing, iterations等配置参数,可配置动画的延迟执行时间、执行持续时间、缓动曲线、执行次数等,其与 CSS 动画属性也保持一致,更多参数请参考KeyframeEffect (MDN)

这个方法会返回一个Animation实例,通过这个实例我们可以对动画进行暂停、取消、读取执行状态等。或者通过.finished返回 Promise 来对执行完动画进行下一步操作。

兼容性

因为该 API 较新,所以对传统的浏览器支持并不友好,所有 IE 浏览器都不支持。在Can I use上查询如下:

兼容性

但是只要简单使用if (dom.animate) {}包裹即可向下兼容,对一些不支持的浏览器不执行动画就可以。

使用案例

文字动画特效

简单写了三种文字动画特效:

  • FadeIn:渐变进入
  • FadeUpInOut: 旧文本先淡出新文本再淡入
  • Typewriter: 打字机特效

文字切换特效

淡入淡出

Effect1Effect2是更改opactitytranslate属性实现的文字淡入淡出动画。

<div class="text-wrapper" id="Effect1"></div>
<div class="text-wrapper" id="Effect2"></div>
<script>
  // ...省略事件绑定等代码
  function animateEffect1(text) {
    const target = document.querySelector("#Effect1");
    target.innerText = text;
    // 使用对象简写写法opactiy from 0, to 1, 执行时间600ms
    target.animate({ opacity: [0, 1] }, 600);
  }
  async function animateEffect2(text) {
    const target = document.querySelector("#Effect2");
    // finished返回Promise,可等待文本淡出动画执行完再执行新文本淡入动画
    await target.animate(
      {
        opacity: [1, 0],
        transform: ["translateY(0)", "translateY(-20px)"],
      },
      300
    ).finished;
    target.innerText = text; // 当旧文本动画执行完再开始替换文本
    target.animate(
      {
        opacity: [0, 1],
        transform: ["translateY(20px)", "translateY(0)"],
      },
      300
    );
  }
</script>

打字机

Effect3实现了一个文字打字机特效,该特效需要确保文字是等宽字体,而且文本不能为多行文本。

<div class="text-wrapper" id="Effect3"></div>
<script>
  // ...省略事件绑定等代码
  async function animateEffect3(text) {
    const target = document.querySelector("#Effect3");
    const beforeWidth = target.offsetWidth; // 计算旧文本宽度
    const textBeforeLength = target.innerText.length; // 计算文本字数
    if (textBeforeLength > 0) {
      // 使用数组参数方式执行宽度减少阶跃动画
      await target.animate([{ width: `${beforeWidth}px` }, { width: 0 }], {
        duration: textBeforeLength * 100,
        easing: `steps(${textBeforeLength})`, // step是阶跃函数,表示动画按多少步执行完
      }).finished;
    }
    target.innerText = text; // 切换新文本
    const afterWidth = target.offsetWidth; // 计算新文本宽度
    const textAfterLength = target.innerText.length; // 计算文本字数
    target.animate([{ width: 0 }, { width: `${afterWidth}px` }], {
      duration: textAfterLength * 100,
      easing: `steps(${textAfterLength})`,
    });
  }
</script>

easing属性中使用了steps阶跃函数,它表示动画需要按多少步执行完,每一步状态里面是属性是一致的,每步属性变化是跳跃的,没有过渡。这里使得文本每次减少一个字符的宽度,构造出打字机的效果。

以上文字特效的实现已上传到codepen,请参考此处: https://codepen.io/leon-kfd/pen/vYJbodr

图片切换特效

在使用 CSS 实现元素动画,一般通过添加类名、移出类名来实现。因为图片无法准确知道需要加载的时间,一般情况是监听图片的 load 事件回调进行判断,所以基本无法使用纯 CSS 来实现切换动画。

本次使用原生Element.animate()API 实现了一个简单的图片切换特效。

图片切换动画特效

这个特效主要原理:

  • 点击切换时,调用函数切换图片路径,这时候图片会异步加载
  • 在新图片加载过程中,旧图片执行一个高斯模糊叠加的渐变淡出动画,并把这个 Animation 对象记录下来
  • 为图片元素添加 load 事件监听,当图片加载完成,把旧图片淡出动画cancel(因为无法确保旧图片淡出动画执行完前新图片已经加载完成,需要Cancel掉旧动画防止重复执行)
  • 执行新图片的高斯模糊淡入动画,动画执行后修改元素 CSS 最终状态

Demo 代码如下:

<button id="btn">Random Img</button>
<p class="img-wrapper">
  <img id="img" />
</p>

<script>
  let leaveAnimation = null; // 用于记录Animation对象
  btn.addEventListener("click", () => {
    randomPhoto();
  });

  async function randomPhoto(first) {
    const target = `https://source.unsplash.com/random/512x512/?nature,${+new Date()}`;
    img.src = target;
    // 切换图片路径后,执行图片淡出动画,此时新图片在后台加载
    if (!first) {
      try {
        leaveAnimation = img.animate(
          [
            { filter: "blur(20px)", tarnsform: "scale(1,1)" },
            { filter: "blur(60px)" },
          ],
          400
        );
        await leaveAnimation.finished;
        img.style.filter = "blur(60px)";
      } catch {
        console.log("Cancel animation");
      }
    }
  }

  img.addEventListener("load", async () => {
    img.style.opacity = 1; // 用于防止首次加载闪图
    if (leaveAnimation) leaveAnimation.cancel(); // cancel掉淡出动画,防止重复执行
    const changeAnimation = img.animate(
      [
        { filter: "blur(20px)", tarnsform: "scale(1,1)" },
        { filter: "blur(0)", tarnsform: "scale(1)" },
      ],
      400
    );
    await changeAnimation.finished;
    img.style.filter = "blur(0)"; // 等待动画执行完后更改最终状态
  });

  randomPhoto(true); // 页面加载立即执行一遍
</script>

以上图片特效的实现已上传到codepen,请参考此处: https://codepen.io/leon-kfd/pen/ZEXYKLR

Demo 中使用了 unsplash 的随机图片接口, https://source.unsplash.com/random

另因当前Element.animate()仍属于实验特性,并不保证将来 api 会进行改动或添加新的特性。