如何获取HTMLMediaElement执行seek操作前的currentTime值
可行方案
最稳定的实现方式是拦截视频元素currentTime的赋值操作,从属性修改的源头捕获跳转前的时间值,完全不受浏览器事件触发顺序影响,在Safari默认播放器场景下可以稳定拿到你要的结果。
实现代码
const video = document.querySelector('#myvideo'); let preSeekTime = 0; // 拿到原生currentTime的属性方法 const nativeCurrentTime = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'currentTime'); // 重写当前video实例的currentTime属性 Object.defineProperty(video, 'currentTime', { get() { return nativeCurrentTime.get.call(this); }, set(targetTime) { // 非seeking状态下的赋值,就是seek操作触发的修改,此时先存下旧值 if (!this.seeking) { preSeekTime = nativeCurrentTime.get.call(this); } return nativeCurrentTime.set.call(this, targetTime); }, configurable: true }); // 后续任意事件回调里都能拿到正确的跳转前时间 video.addEventListener('seeking', () => { console.log('seek前的播放时间:', preSeekTime); // 对应你举的例子,这里会输出7 });
普通缓存方案失效的原因
你之前靠timeupdate缓存时间的方案不生效,是因为Safari处理seek操作的内部执行顺序是:
- 内部直接把
currentTime修改为跳转目标值 - 触发
timeupdate事件,你缓存的变量会被更新为新的时间值 - 触发
pause事件 - 依次触发
seeking、seeked事件
等你在pause或者seeking回调里读缓存值的时候,旧值已经被提前触发的timeupdate覆盖了,自然拿不到想要的结果。
方案优势
- 不依赖浏览器事件触发顺序,就算后续Safari调整事件触发的先后逻辑,功能也不会失效
- 没有定时器、轮询这类额外性能开销,完全不影响视频原有播放功能
- 兼容所有支持ES5属性拦截的浏览器版本,覆盖所有上线的Safari正式版本
内容的提问来源于stack exchange,提问作者MGR
相关产品推荐
相关产品推荐

