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
相关产品推荐
相关产品推荐

