原生<video>进度条需用JS自定义:监听timeupdate事件更新currentSeconds变量,用requestAnimationFrame节流更新DOM;拖拽通过mousedown/mousemove计算位置并设置currentTime;buffered可能不连续,需遍历TimeRanges;时间显示应格式化而非直接Math.floor。

原生 <video> 的进度条没法直接样式定制,想改颜色、加拖拽反馈、同步显示时间,必须自己造一个——不是靠 CSS 覆盖,而是用 JS 监听事件 + 手动控制播放位置。
怎么监听视频播放进度并更新自定义进度条
核心是监听 timeupdate 事件,它在播放过程中高频触发(约每 250ms 一次),但别直接在里面做 DOM 更新,容易卡顿。实际做法是用 requestAnimationFrame 节流:
video.addEventListener('timeupdate', () => { updateProgress(); });-
updateProgress()内部只更新一个currentSeconds变量,不操作 DOM - 另起一个
requestAnimationFrame循环,读取该变量并更新<input type="range">的value或div的width
这样既保证视觉流畅,又避免频繁重排。
怎么让自定义进度条支持拖拽跳转
不能只靠 <input type="range"> 的 change 事件,它只在鼠标松开时触发,拖动过程无响应。必须监听 input 事件 + 计算鼠标位置:
立即学习“前端免费学习笔记(深入)”;
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 给进度条容器绑定
mousedown,记录初始offsetX和当前video.duration - 拖动中监听
mousemove,用event.clientX - container.getBoundingClientRect().left算出相对位置 - 把位置比例换算成秒数:
video.currentTime = (x / container.offsetWidth) * video.duration - 记得加
video.pause()防止拖动时自动播放干扰定位
漏掉 mouseup 和 mouseleave 清理监听,会导致后续点击失效。
为什么 video.buffered 返回的不是连续区间
浏览器按分片(segment)缓存视频,video.buffered 是个 TimeRanges 对象,可能返回多个不连续区间,比如 [0, 12.5) 和 [23.1, 48.7)。直接取 buffered.end(0) 会漏掉中间已缓存的部分。
- 要用循环遍历:
for (let i = 0; i - 常见需求是画“已缓冲”灰色区域,得合并所有区间再映射到进度条宽度
- 注意
buffered在加载初期可能为空,需加if (video.buffered.length > 0)判断 - 部分移动端浏览器(如 iOS Safari)对
buffered支持不稳定,建议 fallback 到固定“加载中”状态
怎么同步显示当前时间和总时长(如 02:15 / 05:43)
别用 Math.floor(video.currentTime) 直接转整数秒——它会丢掉毫秒,导致时间跳变。正确做法是格式化函数里保留两位小数再截断:
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
}- 调用时机:在
timeupdate触发后更新,但同样建议节流(和进度条更新共用同一个requestAnimationFrame) - 总时长
video.duration初始为NaN,要等loadedmetadata事件后才可用 - 如果视频是流式(HLS/DASH),
duration可能为Inf,此时应显示“直播中”而非数字
最易被忽略的是移动端 touch 事件坐标计算和 buffered 的多段处理——这两处不细调,进度条看起来就“不跟手”或“缓冲条断断续续”。


















