
本文介绍如何通过 javascript 监听 html5 视频播放结束事件,并触发页面平滑滚动至指定位置,解决因事件未绑定或逻辑错误导致的“视频结束不滚动”问题。
在你的代码中,核心问题在于:ended() 函数从未被调用,也未正确绑定到视频的 ended 事件上。你当前的实现混合了两种不兼容的逻辑——一边用 requestAnimationFrame 实现“滚动驱动视频”(scroll-driven playback),另一边又试图在视频自然结束时手动触发滚动,但缺少事件监听机制。
更关键的是,HTML 中
✅ 正确做法是:直接监听 ended 事件,而非轮询或手动判断 currentTime >= duration(该方式在视频缓冲不全、暂停后恢复等场景下极易误判)。
以下是优化后的完整解决方案:
✅ 推荐写法:使用原生 ended 事件(简洁、可靠、标准)
const vid = document.getElementById('v0');
const scrollToPosition = 1000; // 滚动到距顶部 1000px 处
// ✅ 正确绑定 ended 事件
vid.addEventListener('ended', function () {
// 平滑滚动(现代浏览器支持)
window.scrollTo({
top: scrollToPosition,
behavior: 'smooth'
});
// 兼容旧版浏览器(可选降级)
// window.scrollTo(0, scrollToPosition);
});? 提示:ended 是 HTML5 的标准事件,当视频自然播放至结尾且 paused === false 时自动触发,无需手动轮询或定时器,性能更好、逻辑更清晰。
⚠️ 你原代码中的主要问题解析
| 问题 | 说明 |
|---|---|
| ❌ ended() 函数未调用 | 定义了函数但没绑定到任何事件,也未在 scrollPlay() 中主动调用,形同虚设。 |
| ❌ 错误依赖 currentTime >= duration 判断结束 | 视频可能因网络卡顿、seek 不精确等原因导致 currentTime 略小于 duration(如 12.999 |
| ❌ setInterval 轮询方案冗余且低效 | 不仅增加 CPU 开销,还易引发竞态(如视频提前结束但定时器仍在运行)。 |
| ❌ scrollPlay() 与 ended 逻辑耦合混乱 | scrollPlay() 是为“滚动控制视频进度”设计的,和“视频结束触发滚动”属于两个相反方向的交互模式,不应混用。 |
✅ 进阶建议:滚动到下一个区块(语义化更强)
如果你希望视频结束后滚动到
vid.addEventListener('ended', function () {
const nextSection = document.querySelector('.section3');
if (nextSection) {
nextSection.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});? 补充注意事项
- 确保视频资源可正常加载:检查控制台是否有 404(如 Hologram_Planet_by_nuva.mov 路径是否正确)、CORS 错误或 MIME 类型不匹配(.mov 在部分浏览器中支持不佳,建议转为 .mp4)。
- 移动端兼容性:behavior: 'smooth' 在 iOS Safari 15.4+ 和 Android Chrome 之后全面支持;如需兼容更老版本,可用 smoothscroll-polyfill。
- 避免重复绑定:如果脚本可能多次执行(如 SPA 中组件复用),建议先 removeEventListener 或使用 once: true 选项:
vid.addEventListener('ended', () => { document.querySelector('.section3').scrollIntoView({ behavior: 'smooth' }); }, { once: true }); // 自动解绑,更安全
综上,删除所有轮询、手动时间判断和冗余的 scrollPlay 调用,专注使用标准 ended 事件监听,即可稳定、高效地实现“视频结束即滚动”的交互目标。










