apng 替代 gif 图片动画,且可控制播放停止

2,267 阅读1分钟

第一,apng 格式支持的浏览器包括 Firefox、Chrome、Safari、Edge、Opera,使用方式与 png 一样(注意apng的文件扩展名也还是 png )。

第二,apng 不支持放到 css 的 background 中使用。

第三,apng 的动画可以借助 apng-js 或者 apng-js-plus 包,利用 canvas 实现对 apng 的播放控制。

-------------------------------华丽分割线------------------------------

apng-js/apng-js-plus 控制apng播放示例代码(vue3版)

utils/apng.js

import parseAPNG from 'apng-js-plus';

/**
 * 获取图片ArrayBuffer
 * @param url 图片地址
 * @returns {Promise<ArrayBuffer>}
 */
export function getImgBuffer(url) {
  return new Promise(async (resolve) => {
   const blob = await fetch(url).then((res) => res.blob());
   const reader = new FileReader();
   reader.readAsArrayBuffer(blob);
   reader.onload = () => {
    resolve(reader.result);
   };
  });
}

/**
 * 获取apng图片的控制实例
 * @param url 图片地址
 * @param options apng配置参数
 * @returns {Promise<APNG>}
 */
export async function getApng(url, options = {}) {
  const imgBuffer = await getImgBuffer(url);
  const apng = parseAPNG(imgBuffer);
  Object.keys(options).forEach((key) => {
   apng[key] = options[key];
  });
  return apng;
}

/**
 * 获取apng图片的控制实例Player属性
 * @param url
 * @param ctx CanvasRenderingContext2D canvas的2D渲染上下文
 * @param options apng配置参数
 * @returns {Promise<Player>}
 */
export async function getApngPlayer(url, ctx, options = {}) {
  const apng = await getApng(url, options);
  const player = await apng.getPlayer(ctx);
  return player;
}

export default {
  getImgBuffer,
  getApng,
  getApngPlayer,
};

demo.vue-template

<template>
  <canvas id="idCanvas" ref="refCanvas"></canvas>
</template>

demo.vue-javascript

<script setup>
import { ref, onMounted } from 'vue';
import apng from '../../utils/apng';

// refCanvas的dom对象
const refCanvas = ref();
// apng文件
let apngFile = require('@/assets/layout/apng/level-music.png');
// apngjs实例
let apngObj = ref();
apng.getApng(apngFile).then((res) => {
  apngObj.value = res;
});
// apng播放控制
let apngPlayer = ref();
// canvas控制apng播放
onMounted(() => {
  let si = setInterval(() => {
   if (!apngObj.value) {
    return;
   }
   // canvasDom 与 refCanvas.value 作用相同,两者都能取到标签的dom对象,看自己喜好
   let canvasDom = document.getElementById(`idCanvas`);
   if (!canvasDom) {
    return;
   }
   // 设置canvas宽高,只支持px
   canvasDom.width = canvasDom.height = 100;
   apngObj.value.getPlayer(canvasDom.getContext('2d')).then((res) => {
    apngPlayer.value = res;
    // 从头开始播放apng动画
    apngPlayer.value.play();
    // 添加动画播放结束监听事件
    apngPlayer.value.on('end', () => { 
      console.log(`apng动画播放结束`)
    });
   });
   clearInterval(si);
  }, 300);
});
</script>

参考文章:
www.npmjs.com/package/apn…
juejin.cn/post/698358…
developer.mozilla.org/zh-CN/docs/…
developer.mozilla.org/zh-CN/docs/…