watcheffect实现清晰度无缝切换的关键是自动响应变化并协调加载、状态校准与播放恢复,而非直接操作src;它通过监听currentresolution,调用switchresolution封装逻辑,在readystate≥2时恢复currenttime和播放状态,确保不黑屏、不跳帧、不断播。

用 watchEffect 实现清晰度切换的“无缝衔接”,关键不是靠它直接控制视频源,而是让它**自动响应清晰度变化,并协调加载、状态校准与播放恢复逻辑**,避免黑屏、卡顿或跳帧。它不替代 src 切换本身,而是让切换过程更可控、更响应式。
核心思路:用 watchEffect 驱动“准备 → 切换 → 恢复”三阶段
清晰度切换本质是更换 <source></source> 或 src,但浏览器需重新加载、解码、同步时间点。watchEffect 的作用是监听清晰度变量变化,自动触发这一整套流程,并确保当前播放进度、暂停/播放状态被正确继承。
- 定义一个响应式清晰度标识,如
const currentResolution = ref('720p') - 所有清晰度选项(URL 映射、是否已加载、就绪状态)统一由一个逻辑管理(例如 Pinia store 或组合式函数)
- watchEffect 不直接操作
video.src,而是调用封装好的switchResolution(newRes)方法,该方法内部处理异步加载与状态同步
防卡顿:只在 readyState 允许时才执行切换
直接赋值 video.src 后立即 play() 很容易报错(如 “The element has no supported sources” 或 “play() failed because the user didn’t interact with the document first”)。watchEffect 可结合 onInvalidate 和事件监听做兜底:
- 在 watchEffect 内监听
currentResolution,触发loadNewSource() - 使用
onInvalidate移除旧的canplay或loadeddata监听器,防止多次绑定 - 等待
video.readyState >= 2(即至少能开始播放)后再恢复播放状态;若未就绪,缓存当前currentTime和paused状态,等就绪后自动 seek + play/pause
保进度:切换前后同步 currentTime 和播放状态
用户在 1:23 秒切换清晰度,新视频应从 1:23 秒继续播放(而非从头)。watchEffect 可确保这个时间点被“记住并应用”:
- 切换前记录:
const savedTime = videoRef.value?.currentTime || 0 - 新视频加载完成(
loadeddata)后,立即设置videoRef.value.currentTime = savedTime - 若原视频处于播放中,新视频就绪后调用
videoRef.value.play();若原视频已暂停,则保持pause() - 注意:部分浏览器在
currentTime设置后会触发seeking,需忽略此期间的 timeupdate 干扰,避免误同步
提升体验:配合 computed 缓存清晰度元数据
清晰度列表常含 label、res、url、是否支持等字段。不要每次 watchEffect 执行都重复查找或解析,而应:
- 将清晰度配置定义为响应式数组,如
const resolutions = ref([{ res: '480p', url: '...' }, ...]) - 用
computed获取当前选中的清晰度对象:const activeRes = computed(() => resolutions.value.find(r => r.res === currentResolution.value)) - watchEffect 中只依赖
activeRes和videoRef,避免追踪整个数组,减少不必要的重执行
不复杂但容易忽略:watchEffect 让你摆脱手动监听 + 条件判断的嵌套,把“清晰度变了该干嘛”变成一句声明式逻辑——它自动帮你盯住变量、清理旧任务、并在合适时机执行下一步。真正无缝,靠的是对视频生命周期的尊重,而不是强行快进。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










