用 watcheffect 自动同步视频进度的核心是共享响应式 videotime,播放器组件读写并防抖校验,其他组件只读不写、纯响应更新;统一管理、避免直接操作 dom 或 video.currenttime。

用 watchEffect 自动同步视频进度,核心是让多个组件“读同一份时间”,但只由播放器组件“写”这份时间,其他组件纯响应、不干预。它不是靠监听事件来推时间,而是靠响应式数据流天然驱动视图更新。
统一管理 currentTime 响应式源
在父组件或状态管理层(如 Pinia)中定义一个共享的响应式时间变量:
- Vue 中推荐用
const videoTime = ref(0),避免用普通 number 或 reactive 包裹整个 video 对象 - 通过
provide('videoTime', videoTime)注入子组件,或用 store 统一暴露 - 确保所有进度条、字幕、章节列表等组件都从这个
videoTime读值,而不是各自访问video.currentTime
播放器组件:读取 + 写入 + 防抖校验
播放器组件负责把原生 <video></video> 的实际时间同步到 videoTime,同时响应外部时间变更:
- 监听
timeupdate事件,用throttle(30ms)更新videoTime.value = video.currentTime - 监听
videoTime变化,用watchEffect主动设置video.currentTime,并等待seeked后再恢复播放状态 - 忽略
seeking/seeked过程中触发的重复赋值,防止死循环 - 加载完成前(
loadedmetadata)不启用同步,避免NaN导致异常
非控制类组件:只读不写,用 computed 缓存计算
进度条、字幕、时间轴等组件不操作 DOM,也不调用 video.currentTime = x:
- 进度条显示:直接绑定
:value="videoTime",拖动时只emit('seek', newTime) - 字幕高亮:用
computed查找当前videoTime所在的字幕段,避免每次渲染都遍历数组 - 章节跳转:点击章节项后,也是发事件,由播放器组件统一处理 seek 和状态同步
应对暂停、跨端与初始化差异
真实场景中,用户会暂停、切后台、多设备进入房间——这些都要兜底:
- 暂停时记录
lastPausedTime = videoTime.value;恢复前比对video.currentTime,不一致就手动修正 - 若需 Web + 小程序多端同步,
videoTime需上报服务端,客户端用 WebSocket 接收校准指令 - 组件挂载时,
watchEffect会自动执行一次,可结合onBeforeMount或 loadedmetadata 判断是否就绪










