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

Canvas滚动序列动画实现分段延迟加载优化方案问询

滚动触发序列帧动画的分段加载优化

现有基于Canvas的滚动触发序列帧动画,共884张WebP图片,全量加载导致初始化耗时过长。需要实现分段加载逻辑:初始加载前100张,之后每5秒加载下一批100张,直至所有图片加载完成。


修改后的JavaScript代码

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

const frameCount = 884;
const batchSize = 100; // 每批加载数量
const loadInterval = 5000; // 分批加载间隔(毫秒)
const imageCache = {}; // 存储已加载的图片对象

// 生成图片路径
const currentFrame = index => `compressed/${index.toString().padStart(9, 'web_0000')}.webp`;

// 加载指定范围的图片
const loadBatch = (start, end) => {
  for (let i = start; i <= end && i <= frameCount; i++) {
    if (!imageCache[i]) {
      const img = new Image();
      img.src = currentFrame(i);
      imageCache[i] = img;
      // 第一张图片加载完成后渲染初始帧
      if (i === 1) {
        img.onload = () => scaleToFill(img);
      }
    }
  }
};

// 初始加载第一批
loadBatch(1, batchSize);

// 分批加载剩余图片
let currentBatchStart = batchSize + 1;
const loadNextBatch = () => {
  const end = Math.min(currentBatchStart + batchSize - 1, frameCount);
  loadBatch(currentBatchStart, end);
  currentBatchStart = end + 1;
  if (currentBatchStart <= frameCount) {
    setTimeout(loadNextBatch, loadInterval);
  }
};

// 启动后续分批加载
setTimeout(loadNextBatch, loadInterval);

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// 图片缩放填充画布
function scaleToFill(img) {
  const scale = Math.max(canvas.width / img.width, canvas.height / img.height);
  const x = (canvas.width / 2) - (img.width / 2) * scale;
  const y = (canvas.height / 2) - (img.height / 2) * scale;
  context.drawImage(img, x, y, img.width * scale, img.height * scale);
}

// 更新画布显示的帧
const updateImage = index => {
  const targetImg = imageCache[index];
  if (targetImg) {
    // 如果图片已加载完成,直接渲染
    if (targetImg.complete) {
      scaleToFill(targetImg);
    } else {
      // 图片未加载完成,加载完成后再渲染
      targetImg.onload = () => scaleToFill(targetImg);
    }
  }
};

// 滚动事件监听
window.addEventListener('scroll', () => {  
  const scrollTop = html.scrollTop;
  const maxScrollTop = html.scrollHeight - window.innerHeight;
  const scrollFraction = scrollTop / maxScrollTop;
  const frameIndex = Math.min(
    frameCount - 1,
    Math.ceil(scrollFraction * frameCount)
  );
  
  requestAnimationFrame(() => updateImage(frameIndex + 1));
});

HTML代码

<canvas id="hero-lightpass"></canvas>

关键改动说明

  • 图片缓存机制:用imageCache对象存储已加载的图片,避免重复请求和重复创建Image实例
  • 分段加载逻辑:loadBatch函数负责加载指定范围的图片,初始加载前100张,后续通过定时器每5秒加载下一批
  • 滚动渲染优化:updateImage函数优先使用缓存中的图片,若图片未加载完成则监听onload事件,确保滚动到对应帧时能正常渲染
  • 边界处理:通过Math.min确保最后一批加载不会超出总帧数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 08:10:31