
页面首次加载时 Canvas 动画不显示,仅在滚动后才出现——根本原因是 render() 未在 DOM 就绪或图像加载完成时主动调用;需在 onload 和 resize 时机显式触发初始渲染,并优化性能。
页面首次加载时 canvas 动画不显示,仅在滚动后才出现——根本原因是 render() 未在 dom 就绪或图像加载完成时主动调用;需在 onload 和 resize 时机显式触发初始渲染,并优化性能。
要解决 GSAP + Canvas 逐帧动画“首屏无图、滚动才显、回滚即失”的问题,核心在于确保动画帧在页面加载完成、图像资源就绪、Canvas 尺寸确定后立即绘制一次,而非仅依赖 ScrollTrigger 的 onUpdate 触发。
✅ 正确的初始化流程
原代码中,render() 仅在以下两个时机被调用:
- 所有图片
onload完成后(✅ 正确但不够); - GSAP ScrollTrigger 的
onUpdate(❌ 依赖滚动,导致首屏空白)。
但缺少关键一环:即使图片已加载完毕,若 Canvas 尚未设置宽高或未执行首次绘制,画面仍为空白。因此必须在 window.onload(或更优的 DOMContentLoaded)后,主动调用一次 setup() —— 该函数负责同步设置 Canvas 尺寸并执行首帧渲染。
? 修改建议(推荐写法)
function sequence_animation() {
const canvas = document.querySelector('#home > canvas');
const context = canvas.getContext('2d');
// ? 提取为独立 setup 函数,兼顾初始化与响应式
function setup() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
render(); // ⚠️ 关键:强制首帧绘制!
}
// 初始化尺寸并绘制(替代原 canvas.width/height 直接赋值)
setup();
// 图片预加载逻辑(保持不变,但确保 onload 后也调用 render)
let imagesLoaded = 0;
const frameCount = 19;
const images = [];
const imageSeq = { frame: 0 };
function files(index) {
const paths = [
'../assets/img/animation/1.png',
'../assets/img/animation/1.png',
'../assets/img/animation/1-2.png',
// ... 其余路径(建议改用数组而非 split('\n'),更健壮)
'../assets/img/animation/10.png'
];
return paths[index] || '';
}
for (let i = 0; i < frameCount; i++) {
const img = new Image();
img.src = files(i);
images.push(img);
img.onload = () => {
if (++imagesLoaded === frameCount) {
render(); // 图片就绪后再次绘制,确保内容可用
}
};
}
// ✅ 使用防抖 resize(避免高频重绘)
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(setup, 16); // ~60fps 节奏
});
// ✅ 绑定 GSAP 动画(scrollTrigger 不影响首帧)
gsap.to(imageSeq, {
frame: frameCount - 1,
snap: 'frame',
ease: 'none',
scrollTrigger: {
scrub: 1,
trigger: '.header__list-item.message',
start: 'top top', // 建议修正为语义化值(原 'left %' 无效)
invalidateOnRefresh: true
},
onUpdate: render
});
function render() {
const frameIndex = Math.min(Math.max(0, Math.floor(imageSeq.frame)), frameCount - 1);
scaleImage(images[frameIndex], context);
}
function scaleImage(img, ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
}
}
// ? 启动动画(确保 DOM 已就绪)
document.addEventListener('DOMContentLoaded', sequence_animation);⚠️ 注意事项与优化点
-
不要使用
window.onload = setup():onload等待所有资源(含图片)加载完成,而你的图片是异步加载的,会导致重复或阻塞;应优先用DOMContentLoaded启动主逻辑,再由图片onload控制帧就绪。 -
scrollTrigger.start值需修正:原'left %'是非法语法,应改为如'top top'或'center 80%'等有效锚点。 -
性能防护:
resize事件加防抖(setTimeout)可防止连续重绘导致卡顿;GSAP 内置invalidateOnRefresh可提升响应式稳定性。 -
兜底容错:
render()中对frameIndex做边界校验(Math.min/max),避免imageSeq.frame为负数或超界时读取undefined图片报错。
通过以上调整,动画将在页面加载完成、Canvas 尺寸设定、图片资源就绪后自动呈现首帧,后续滚动则平滑驱动帧序列——真正实现“所见即所得”的专业交互动效。



















