我用最蹩脚的方式写了一个「序列帧动画」 🍂

简介: 我用最蹩脚的方式写了一个「序列帧动画」 🍂

前言


前几天隔壁组的同事问我们 leader 做没做过序列帧动画,我亲爱的 leader 直接把我推了出去:“寒草会!”,事后给我发了一张她俩对话的截图,并对我表示信任。


我一脸懵逼,心想:“诶?我没做过啊!”。


随后我开始了谷歌生涯,搜了一搜,随后便开始了我的序列帧动画编码之路。


实现


animation

我最开始办法肯定还是用 animation 做了一个 demo。


其中注意 animation 中 steps 这个属性,帧动画也是靠它实现。


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    @keyframes demo {
      0% {
        background-position: 0px 0;
      }
      10% {
        background-position: -20px 0;
      }
      20% {
        background-position: -40px 0;
      }
      30% {
        background-position: -60px 0;
      }
      40% {
        background-position: -80px 0;
      }
      50% {
        background-position: -100px 0;
      }
      60% {
        background-position: -120px 0;
      }
      70% {
        background-position: -140px 0;
      }
      80% {
        background-position: -160px 0;
      }
      90% {
        background-position: -180px 0;
      }
      100% {}
    }
    .animation {
      background-image: url('a.jpeg');
      background-repeat: no-repeat;
      height: 200px;
      width: 200px;
      position: absolute;
      top: 200px;
      left: 300px;
      border-radius: 50%;
      -webkit-animation: demo 1s steps(1, end) infinite;
    }
  </style>
</head>
<body>
  <div class="animation"></div>
</body>
</html>


效果就是这样的


网络异常,图片无法展示
|


之后我充满了自信,可以完全接下这个序列帧动画。之后发现我拿到的素材是:


网络异常,图片无法展示
|


网络异常,图片无法展示
|


30 M 大小的 180 张图片,我人傻了!


我拒绝写 180 个状态的 keyframes!


于是我想到了下面这个 js 手段。


js 方案一


不能使用公司素材,于是在此处不进行效果展示。


想着总不能我写 180 个状态吧,于是我就想干脆用 js 吧,在图片全都 load 完成后设置一个定时器,去替换背景图片的 url。


const dom = document.getElementsByClassName('animation')[0];
    let promiseAll = []
    let img = []
    let imgTotal = 180;
    for (let i = 0; i < imgTotal; i++) {
      promiseAll[i] = new Promise((resolve, reject) => {
        img[i] = new Image()
        img[i].src = `./asset/编组 59@2x_00${String(i).padStart(3, '0')}.png`
        img[i].onload = function () {
          resolve(img[i])
        }
      })
    }
    let current = 0
    Promise.all(promiseAll).then((img) => {
      setInterval(() => {
        current = (++current) % 180;
        dom.style.backgroundImage = `url('asset/编组 59@2x_00${String(current).padStart(3, '0')}.png')`
      }, 40)
    })


此处注意两点细节吧:


  • padStart 用法(我很少用这个 api)
  • 用 Promise 处理图片的加载
  • 时间我设置的是 40 ms,因为我想的是一秒至少 24 帧,保证流畅


但是这里还是有一个问题:


莫名其妙在配置低的电脑上,打开控制台时会闪屏...我很不解


js 方案二


现在我依然不解,如果有伙伴知道原因可以评论或者加我好友告诉我,我想到的可能原因就是:


  • 图片过大,背景图的切换的渲染消耗


毕竟不打开控制台,不频繁操作时不会闪屏,但是猜测也只是猜测,毕竟我是菜狗子


我想了很多办法,比如:


  • 把 180 张图片和在一起,只需要改 background-position 就好了
  • 180 个 dom,之后去修改 dom 的透明度


最后我采取了方法二,是不是集齐蹩脚,又土又蹩脚,因为我想的是 dom 都已经渲染完了,每次也只需要去改两个 dom 的透明度,性能压力不大。


  • 之前显示的 dom 隐藏掉
  • 将下一个 dom 显示出来


let promiseAll = [];
    let imgList = [];
    let imgTotal = 180;
    for (let i = 0; i < imgTotal; i++) {
      promiseAll[i] = new Promise((resolve) => {
        imgList[i] = new Image();
        imgList[
          i
        ].src = `./asset/编组 59@2x_00${String(
          i
        ).padStart(3, "0")}.png`;
        imgList[i].onload = function () {
          resolve(imgList[i]);
        };
      });
    }
    let current = 0;
    let domList = [];
    const domWrapper = document.body;
    Promise.all(promiseAll).then((imgList) => {
      for (const img of imgList) {
        const domItem = document.createElement('div');
        domItem.classList = 'animation';
        domItem.style.backgroundImage = `url(${img.src})`;
        domItem.style.backgroundSize = "308px 669px";
        domItem.style.opacity = 0;
        domWrapper.appendChild(domItem);
        domList.push(domItem);
      }
      setInterval(() => {
        domList[current].style.opacity = 0;
        current = ++current % 180;
        domList[current].style.opacity = 1;
      }, 40);
    });


自动生成 keyframes


最后还是想去用 animation 来做,所以就迎来了我的第四种方案,自动生成 好长好长的 keyframes 的关键帧:


const { writeFileSync } = require('fs');
const { join } = require('path');
const generateFunction = (number) => {
  let currentNum = 0;
  let str = '';
  const step = 100 / number;
  while( currentNum < 180) {
    str += `${Number(currentNum * step).toFixed(2)}% {
      background-image: url('./asset/编组 59@2x_00${String(
        currentNum
      ).padStart(3, "0")}.png')
    }
    `
    currentNum ++;
  }
  writeFileSync(join(__dirname, 'funca.js'), str, {
    encoding: 'utf-8'
  })
}
generateFunction(180);


结束语


网络异常,图片无法展示
|


写在最后


春天落英缤纷
夏天栀子花开
秋天芙蓉三变
冬天暗香疏影
春夏秋冬
樱花
栀子
芙蓉
腊梅
花开花落
唯有你,一直在我心中盛放

相关文章
|
JavaScript 应用服务中间件 图形学
基于Threejs实现glb三维模型的预览
文章将重点介绍如何基于Threejs进行三维模型glb进行预览,可以旋转控制。
2083 0
基于Threejs实现glb三维模型的预览
|
12月前
|
人工智能 监控 数据可视化
在Zabbix中通过ECharts模块增强可视化功能
Zabbix凭借模块化架构支持灵活扩展,ECharts-Zabbix模块集成丰富图表库,提升数据可视化能力。支持多种图表、深度自定义与动态交互,无缝对接Zabbix数据,助力构建直观、响应式的监控大屏,显著增强运维效率。
508 9
|
人工智能 监控 物联网
深度探索人工智能与物联网的融合:构建未来智能生态系统###
在当今这个数据驱动的时代,人工智能(AI)与物联网(IoT)的深度融合正引领着一场前所未有的技术革命。本文旨在深入剖析这一融合背后的技术原理、探讨其在不同领域的应用实例及面临的挑战与机遇,为读者描绘一幅关于未来智能生态系统的宏伟蓝图。通过技术创新的视角,我们不仅揭示了AI与IoT结合的强大潜力,也展望了它们如何共同塑造一个更加高效、可持续且互联的世界。 ###
|
前端开发 JavaScript 数据可视化
58K star!这个让网页动起来的JS库,前端工程师直呼真香!
Anime.js 是一款轻量级但功能强大的JavaScript动画引擎,它能够以最简单的方式为网页元素添加令人惊艳的动效。这个项目在GitHub上已经获得58,000+星标,被广泛应用于电商页面、数据可视化、游戏开发等场景。
885 8
|
Android开发 iOS开发 异构计算
电竞模式,启动!用无影云电脑畅玩3A游戏大作
电竞模式,启动!用无影云电脑畅玩3A游戏大作
关于ECharts仪表盘的全部相关配置
关于ECharts仪表盘的全部相关配置
481 0
|
存储 JavaScript
ThreeJS创建关键帧动画
这篇文章讲解了如何在Three.js中利用关键帧轨道 (`KeyframeTrack`) 创建动画效果,并提供了详细的步骤和代码示例。
587 0
ThreeJs的场景实现鼠标拖动旋转控制
这篇文章介绍了如何在Three.js中实现通过鼠标拖动来旋转场景中的模型,并提供了实现这一功能的代码示例。
926 0
|
JavaScript 前端开发
JavaScript随手笔记---轮播图(点击切换)
JavaScript随手笔记---轮播图(点击切换)
JavaScript随手笔记---轮播图(点击切换)
|
JavaScript 前端开发
JS获取DOM元素的八种方法(含代码,简单易懂)
JS获取DOM元素的八种方法(含代码,简单易懂)

热门文章

最新文章