视频ui同步关键在于精准判断缓冲状态与进度:waiting且非暂停才代表真实缓冲,buffered需遍历匹配currenttime区间计算进度,loading与进度条逻辑必须解耦。

视频加载进度和缓冲状态的 UI 同步,关键不在“等它加载完再显示”,而在于用对事件、算准区间、及时响应。用户看到卡顿前,UI 就该给出反馈。
waiting + !paused 才是真正的“正在缓冲”
浏览器触发 waiting 事件,且此时 video.paused === false,才代表播放被数据不足中断——这是唯一能区分“用户暂停”和“被迫卡住”的信号。仅监听 waiting 不够,必须加 !paused 判断,否则暂停状态下拖动进度条也会误触。
- 显隐 loading 的逻辑要独立于 window.onload,一调用 video.load() 就立刻 showLoading
- 在 playing 或 error 事件中隐藏 loading,避免残留
- 加 8 秒超时兜底:setTimeout(() => hideLoading(), 8000),防止异常情况下 loading 永不消失
缓冲进度不是“已下多少”,而是“当前能播到哪”
buffered 是 TimeRanges 对象,可能含多个不连续区间(比如跳播后缓存了开头和结尾两段)。直接取 buffered.end(0) 会出错,必须定位覆盖 currentTime 的那个区间。
- 先确保 duration 已知:只在 loadedmetadata 后开始计算,避免 NaN
- 遍历 buffered.length 个区间,找满足 buffered.start(i) ≤ currentTime ≤ buffered.end(i) 的那个 i
- 命中则用 buffered.end(i) / duration 算百分比;没命中就返回 0%
- Safari 常不更新 buffered 或返回空,建议 fallback 为静态文字 + 旋转图标,不强求进度条动
进度条同步靠 timeupdate,但拖拽要接管 input/change
timeupdate 负责实时反映播放位置,而拖拽跳转必须用 input(拖动中)+ change(松手后)双事件,单靠 change 会有明显延迟。
- timeupdate 中更新进度条 value 或 width,同时刷新 mm:ss 时间文本
- 拖拽时先暂停 video.pause(),松手后再按原状态恢复(需记录 isPlaying)
- 移动端必须补充 touchstart/touchmove/touchend,不能只绑 mouse 事件
- loadedmetadata 前禁用所有交互操作,防止 duration 未就绪导致计算错误
loading 和进度 UI 的生命周期要解耦
缓冲 loading 和播放进度条看似相关,实则驱动逻辑不同:前者响应网络与解码状态,后者响应时间轴变化。混在一起容易互相干扰。
- loading 显隐由 waiting/playing/error + 超时控制,和 timeupdate 无关
- 进度条渲染只依赖 currentTime/duration,不参与缓冲判断
- 两者 DOM 可共存,但 JS 状态管理要隔离,比如用 separate loadingEl 和 progressBarEl 引用
- 初始阶段可统一用 canplay 事件做 UI 启用开关,但后续各自走自己的事件流
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











