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

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

前言


前几天隔壁组的同事问我们 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);


结束语


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


写在最后


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

目录
打赏
0
0
0
0
3
分享
相关文章
kde
|
5天前
|
Docker镜像加速指南:手把手教你配置国内镜像源
配置国内镜像源可大幅提升 Docker 拉取速度,解决访问 Docker Hub 缓慢问题。本文详解 Linux、Docker Desktop 配置方法,并提供测速对比与常见问题解答,附最新可用镜像源列表,助力高效开发部署。
kde
2998 8
国内如何安装和使用 Claude Code镜像教程 - Windows 用户篇
国内如何安装和使用 Claude Code镜像教程 - Windows 用户篇
556 0
Dify MCP 保姆级教程来了!
大语言模型,例如 DeepSeek,如果不能联网、不能操作外部工具,只能是聊天机器人。除了聊天没什么可做的。
814 9
2025年最新版最细致Maven安装与配置指南(任何版本都可以依据本文章配置)
本文详细介绍了Maven的项目管理工具特性、安装步骤和配置方法。主要内容包括: Maven概述:解释Maven作为基于POM的构建工具,具备依赖管理、构建生命周期和仓库管理等功能。 安装步骤: 从官网下载最新版本 解压到指定目录 创建本地仓库文件夹 关键配置: 修改settings.xml文件 配置阿里云和清华大学镜像仓库以加速依赖下载 设置本地仓库路径 附加说明:包含详细的配置示例和截图指导,适用于各种操作系统环境。 本文提供了完整的Maven安装和配置
2025年最新版最细致Maven安装与配置指南(任何版本都可以依据本文章配置)
【保姆级图文详解】大模型、Spring AI编程调用大模型
【保姆级图文详解】大模型、Spring AI编程调用大模型
342 7
【保姆级图文详解】大模型、Spring AI编程调用大模型
Excel数据治理新思路:引入智能体实现自动纠错【Python+Agent】
本文介绍如何利用智能体与Python代码批量处理Excel中的脏数据,解决人工录入导致的格式混乱、逻辑错误等问题。通过构建具备数据校验、异常标记及自动修正功能的系统,将数小时的人工核查任务缩短至分钟级,大幅提升数据一致性和办公效率。
DeepSeek R1+Open WebUI实现本地知识库的搭建和局域网访问
本文介绍了使用 DeepSeek R1 和 Open WebUI 搭建本地知识库的详细步骤与注意事项,涵盖核心组件介绍、硬件与软件准备、模型部署、知识库构建及问答功能实现等内容,适用于本地文档存储、向量化与检索增强生成(RAG)场景的应用开发。
366 0
让AI时代的卓越架构触手可及,阿里云技术解决方案开放免费试用
阿里云推出基于场景的解决方案免费试用活动,新老用户均可领取100点试用点,完成部署还可再领最高100点,相当于一年可获得最高200元云资源。覆盖AI、大数据、互联网应用开发等多个领域,支持热门场景如DeepSeek部署、模型微调等,助力企业和开发者快速验证方案并上云。
303 22
让AI时代的卓越架构触手可及,阿里云技术解决方案开放免费试用
FLUX.1 Kontext 的全生态教程来啦!AIGC专区在线试玩!
Flux.1 Kontext [dev] 开源模型大家都用上了吗?小编汇总了3个使用教程,打包送上!
407 1

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问