You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Canvas透明图片逐帧动画卡顿问题及优化咨询

Canvas滚动驱动透明逐帧动画卡顿与闪烁问题解决

问题分析

原代码的核心问题在于:每次更新帧时先清空Canvas,然后修改img.src后立即调用drawImage,但此时新图片可能尚未完成加载(哪怕预加载过,复用单个Image对象时也可能存在加载状态延迟),导致Canvas短暂透明,出现闪烁卡顿。同时预加载逻辑仅创建Image对象但未保留引用,无法确保图片真正缓存到位。


1. 如何消除动画的卡顿效果?

通过以下核心优化点解决:

  • 预加载并缓存所有帧图片:创建数组保存所有预加载完成的Image对象,确保绘制时直接使用已就绪的图片,避免加载延迟。
  • 避免复用单个Image对象:每个帧使用独立的预加载图片,防止src切换时的加载状态冲突。
  • 优化滚动事件处理:在scroll事件中计算帧索引后,直接在requestAnimationFrame中使用缓存好的图片绘制,无需等待加载。

修改后的完整代码:

const html = document.documentElement;
const canvas = document.getElementById("prodPicAnimation");
const context = canvas.getContext("2d");

const frameCount = 120;
const currentFrame = index => (
  `https://www.dr-adler.com/content/produkte/Sheabutter/renderAnimation/${index.toString().padStart(3, '0')}.png`
);

// 预加载并缓存所有图片到数组
const frames = [];
const preloadImages = async () => {
  const promises = [];
  for (let i = 1; i <= frameCount; i++) {
    const img = new Image();
    const promise = new Promise(resolve => {
      img.onload = () => resolve(img);
    });
    img.src = currentFrame(i);
    promises.push(promise);
    frames.push(img);
  }
  await Promise.all(promises); // 确保所有图片加载完成
};

canvas.width = 750;
canvas.height = 750;

// 绘制指定帧,仅在图片就绪时操作
const drawFrame = (index) => {
  const img = frames[index - 1]; // 数组索引从0开始,帧序号从1开始
  if (img.complete) {
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.drawImage(img, 0, 0);
  }
};

window.addEventListener('scroll', () => {  
  const scrollTop = html.scrollTop;
  const maxScrollTop = 750;
  const scrollFraction = scrollTop / maxScrollTop;
  const frameIndex = Math.min(
    frameCount,
    Math.ceil(scrollFraction * frameCount)
  );
  
  requestAnimationFrame(() => drawFrame(frameIndex));
});

// 预加载完成后初始化第一帧
preloadImages().then(() => drawFrame(1));
<canvas id="prodPicAnimation"></canvas>

2. 是否可以仅在下一帧“就绪”时才清除Canvas?

完全可以,这正是解决闪烁问题的核心方案。上述修改后的drawFrame函数会先检查图片是否已加载完成(img.complete),只有当图片就绪后,才执行清空Canvas并绘制新帧的操作,彻底避免了清空后无图可画的透明状态。

如果需要更极致的流畅度,还可以采用离屏Canvas预渲染:先在离屏Canvas绘制好新帧,再一次性将离屏Canvas的内容绘制到显示Canvas,进一步减少绘制操作的视觉断层。


内容的提问来源于stack exchange,提问作者Adler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 03:35:42