JavaScript 前端实现 GIF 图片循环播放

作者:交互手记时间:2026-10-31 19:33:41浏览:486

传统 GIF 图片仅播放一次后自动暂停,而使用定时器重新加载会导致内存泄漏与画面闪烁。本文介绍利用 WebCodecs API 中的 ImageDecoder 接口,通过 fetch 获取资源并逐帧解码渲染至 Canvas,从而实现 GIF 图片在前端的无限循环播放。

前言

在网页开发中,直接使用 img 标签加载 GIF 图片时,动画通常只播放一轮便自动停止;

若尝试通过定时器在指定时间后重新加载图片以模拟循环,这种做法不仅会引发浏览器内存持续攀升,还容易造成画面闪烁与卡顿现象;

ImageDecoder

WebCodecs API 提供的 ImageDecoder 接口,为编码图像数据的解包与解码提供了标准化方法。

前言

需要注意的是,ImageDecoder 仅在 localhost 环境或 https 协议的标签页中可用。

代码

首先设置 canvas 元素的 width 和 height 属性,使其与 GIF 图片的实际尺寸保持一致;

<canvas width="1310" height="954"></canvas>

此外,也可通过以下代码动态获取并设置尺寸;

const img = new Image();
img.src = '图片路径';
img.onload = function() {
    var width = this.width;   // 图片宽度
    var height = this.height; // 图片高度
    console.log(`图片尺寸为:${width} x ${height}`);
    
    // some code... 
    // 为canvas 设置 width、height
};

其次,利用 fetch 方法获取 GIF 图片资源,并传入对应的 url;

fetch(url).then((response) => decodeImage(response.body));

接着,调用 decodeImage 方法对图片数据进行解码处理;

imageDecoder = new ImageDecoder({ data: imageByteStream, type: "image/gif" });
imageDecoder.decode({ frameIndex: imageIndex }).then(renderImage);

最后,通过 renderImage 函数逐帧渲染图片内容;

 function renderImage (result) {
   const canvas = document.querySelector("canvas");
   const canvasContext = canvas.getContext("2d");
 
   // 绘制图片 
   canvasContext.drawImage(result.image, 0, 0);
 
   const track = imageDecoder.tracks.selectedTrack;
 
   if (imageDecoder.complete) {
     if (track.frameCount === 1) return;
 
 	 // 如果序号超出了帧数,重置为 0
     if (imageIndex + 1 >= track.frameCount) imageIndex = 0;
   }
 
   // 解码下一帧图片并渲染
   imageDecoder
     .decode({ frameIndex: ++imageIndex })
     .then((nextResult) =>
       setTimeout(() => {
         renderImage(nextResult);
       }, result.image.duration / 1000) // 可以调整播放速度
     )
     .catch((e) => {
       if (e instanceof RangeError) {
         imageIndex = 0;
         imageDecoder.decode({ frameIndex: imageIndex }).then(renderImage);
       } else {
         throw e;
       }
     });
 }

完整代码

<template>
	<div>
		<canvas width="1310" height="954"></canvas>
	</div>
</template>

<script>
export default {
	mounted() {
		this.play(require("@/assets/images/animate.gif"));
	},
	play(url) {
		let imageDecoder = null;
      	let imageIndex = 0;

	      function renderImage (result) {
	        const canvas = document.querySelector("canvas");
	        const canvasContext = canvas.getContext("2d");
	
	        canvasContext.drawImage(result.image, 0, 0);
	
	        const track = imageDecoder.tracks.selectedTrack;
	
	        if (imageDecoder.complete) {
	          if (track.frameCount === 1) return;
	
	          if (imageIndex + 1 >= track.frameCount) imageIndex = 0;
	        }
	
	        imageDecoder
	          .decode({ frameIndex: ++imageIndex })
	          .then((nextResult) =>
	            setTimeout(() => {
	              renderImage(nextResult);
	            }, result.image.duration / 1000)
	          )
	          .catch((e) => {
	            if (e instanceof RangeError) {
	              imageIndex = 0;
	              imageDecoder.decode({ frameIndex: imageIndex }).then(renderImage);
	            } else {
	              throw e;
	            }
	          });
	      }
	
	      function decodeImage (imageByteStream) {
	        imageDecoder = new ImageDecoder({ data: imageByteStream, type: "image/gif" });
	        imageDecoder.decode({ frameIndex: imageIndex }).then(renderImage);
	      }
	
	      fetch(url).then((response) => decodeImage(response.body));
	}
}
</script>

到此这篇关于JavaScript前端实现GIF图片循环播放的文章就介绍到这了,更多相关JavaScript GIF图片循环播放内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章