前言
项目遇到一个需求:
- 实现一个包含四层元素的动画按钮,这篇文章只单说明video这层的元素。
- 需要控制其播放/暂停,鼠标移入使其播放(执行动画),鼠标移出则暂停。
问题
Uncaught (in promise): The play() request was interrupted by a call to pause().
<video
onMouseEnter={play}
onMouseLeave={pause}
>
<source src={videoUrl} type="video/mp4" />
</video>
const play = () => {
videoTarget.play();
}
const pause = () => {
videoTarget.pause();
}
错误思路
-
使用
setTimeout延迟执行,这样解决会延迟执行。有两个弊端,一是设置50ms、100ms甚至200ms也会触发相同的error,并且设置大了会明显感觉到延迟执行,体验不好。<video onMouseEnter={play} onMouseLeave={pause} > <source src={videoUrl} type="video/mp4" /> </video>const play = () => { setTimeout(() => { videoTarget.play(); }, 100) } const pause = () => { setTimeout(() => { videoTarget.pause(); }, 100) } -
使用play、pause方法返回的
promise + isPlaying处理。这种处理方式,会导致isPlaying的设置并不是准确的,如果鼠标移动过快,或者多次尝试,也是有几率将isPlaying的值设置错的,故弃用。<video onMouseEnter={play} onMouseLeave={pause} > <source src={videoUrl} type="video/mp4" /> </video>let isPlaying = false; // 初始状态 const play = () => { if (isPlaying) { return; } videoTarget.play().then(() => { isPlaying = true; }); } const pause = () => { if (!isPlaying) { return; } videoTarget.pause().then(() => { isPlaying = false; }); }
解决方法
<video
onMouseEnter={play}
onMouseLeave={pause}
onPlaying={playing}
onPause={pausing}
>
<source src={videoUrl} type="video/mp4" />
</video>
let isPlaying = false;
const playing = () => {
isPlaying = true;
}
const pausing = () => {
isPlaying = false;
}
const play = () => {
if (videoTarget.paused && !isPlaying) {
videoTarget.play();
}
}
const pause = () => {
if (!videoTarget.paused && isPlaying) {
videoTarget.pause();
}
}
分析
先了解这两个事件。
playing事件,当播放准备开始时(之前被暂停或者由于数据缺乏被暂缓)被触发onpause可以用来获取或设置当前元素的onpause事件的事件处理函数。当媒体播放被暂停时,将触发pause事件。
video、audio这类媒体播放器在播放时,需要注意的点其实挺多的,这里单就播放/暂停这点,因为牵涉到硬件层,所以行为一定会有延迟,具体耗时其实是不太好确定的,所以这里是通过原生的回调事件去控制isPlaying这个flag,而不是promise去处理,promise处理方式会导致判断有误差。
我理解play或者pause方法返回的promise中再去处理的话,是延后了,这时修改flag,会影响判断,且onMouseEnter、onMouseLeave在鼠标一次移入、移出的过程中分别只会触发一次,所以isPlaying的修改要置前,在video行为准备过程中去处理,然后再切换播放/暂停,这样就不会让chrome报错,误认当前的播放状态相互影响。
结束语
如果觉得写的不错,有用的话,还请帮我点个赞 O(∩_∩)O
转发请注明出处,谢谢!