当前位置: 首页 > 科技观察

使用IntersectionObserverAPI实现视频队列的自动播放_0

时间:2023-03-15 09:57:20 科技观察

前言笔者利用业余时间研究了javascript的IntersectionObserverAPI,发现其应用场景非常多,比如图片或内容的延迟加载,视差动画等。作者详细介绍了3种Observer的用法,包括位置监听、dom变化监听和窗口变化监听。它们的应用场景非常多,所以有必要去研究和了解。有兴趣的可以看这篇文章以后再学(几个很有意思的javascript知识点总结)。这是一个很常见的例子。平时喜欢看短视频的朋友可能会注意到,当我们浏览某个视频的头条时,会滚动视频列表。屏幕中心),视频将自动播放。当它移出指定区域时,视频会自动关闭并播放移入指定区域的下一个视频,如下:作为一个很好奇的前端工程师,有必要研究一下它的内部实现。作者的第一个想法是通过监听滚动位置来判断某个视频元素是否到达指定区域,但是这种方法需要处理很多条件,比如边界条件判断,滚动方向判断等,频繁触发也会导致性能问题。幸运的是,笔者深入研究了IntersectionObserverAPI,发现其提供的API可以方便的监听指定根元素下元素的位置变化,并进行一些自定义操作:笔者将直接使用接下来提供的IntersectionObserver。api实现滚动过程中自动播放视频的功能。如果对api不熟悉,可以移步到几个很有意思的javascript知识点来总结一下视频播放插件。我会用现在流行的Dplayer,可以很方便的操作视频的显示,实现很好的专属播放控制,支持弹幕。根据上面的介绍,我们对具体的需求有了一个大致的了解,接下来我们将基于IntersectionObserverAPI进行实现。思路大致如下图所示:具体思路是我们可以将IntersectionObserver的根元素的rootMargin(即根元素的外边距)设置为上图中蓝色所示的区域,然后当视频完全进入该区域时(即thresholds为1),才触发当前视频的播放。因为我们使用的是Dplayer,所以只需要将其配置属性中的mutex属性设置为true即可(会防止多个玩家同时播放,当前播放时暂停其他播放)。设置rootMargin的知识可以参考下图:rootMargin的接收格式如下:“10px0px10px0px”,从左到右的数字分别代表top(上)right(右)bottom(下)left(左)边距,当然我们的单位也可以用百分比(%)。为正值时表示扩大更多元素的边距范围,为负值时表示缩小根元素的边距范围。这里要缩小范围,所以我们可以这样设置rootMargin:“-180px0px-180px0px”,这样上下边距就会缩小。当然你也可以根据自己的需要设置不同的值。有了以上思路,我们就可以实现上面动图所示的效果了。笔者将使用react来实现。在实现之前,我们会准备好几个视频素材,然后实现列表的基本框架:constdata=[//videolist]functionVideoList(props){useEffect(()=>{letobserverVideo=newIntersectionObserver((entries,observer)=>{entries.forEach(entry=>{//移入后指定区域,播放视频if(entry.intersectionRatio===1){//部分操作返回}//停止监听//observer.unobserve(entry.target);});},{root:document.getElementById('scrollView'),rootMargin:'-180px0px-180px0px',threshold:1});document.querySelectorAll('.video-item').forEach(video=>{observerVideo.observe(video)});},[])返回{data.map(item=>{return})}

}exportdefaultVideoList上面代码中的VideoItem组件后面会介绍。现在有个问题,我们已经监听到需要自动播放的video元素了,但是怎么通知VideoItem组件让它播放呢?作者这里的想法是给VideoItem添加一个自定义属性。该属性的值为当前视频的src。当我们监听一个需要播放的video元素时,我们可以获取之前设置的自定义属性,并将其作为prop传递。对于VideoItem,当VideoItem组件监听到prop变化等于自己的src时,就会播放视频代码如下://VideoItem.jsimportReact,{useRef,useEffect}from'react';importDPlayerfrom'dplayer';exportdefault(props)=>{letvideoRef=useRef(null)letdpRef=useRef(null)let{src,groupName,curPlaySrc}=propsuseEffect(()=>{dpRef.current=newDPlayer({container:videoRef.current,screenshot:true,video:{url:src,thumbnails:'logo.png'},logo:'logo.png'});},[])useEffect(()=>{//当应该播放的视频url等于当前视频组件的src时,播放视频if(curPlaySrc===src){dpRef.current.play()}},[curPlaySrc])返回
}此时视频列表页面代码如下://...functionVideoList(props){const[curPlaySrc,setCurPlaySrc]=useState('')useEffect(()=>{letobserverVideo=newIntersectionObserver((条目,观察er)=>{entries.forEach(entry=>{//移动到指定区域后,播放视频if(entry.intersectionRatio===1){//设置要播放的视频的当前urlsetCurPlaySrc(entry.target.dataset.src)返回}});},{root:document.getElementById('scrollView'),rootMargin:'-180px0px-180px0px',threshold:1});document.querySelectorAll('.video-item').forEach(video=>{observerVideo.observe(video)});},[])return{data.map(item=>{return})}}以上步骤完成了根据指定区域自动播放视频的功能,效果如下如下:体验URL视频自动播放demo仿微信朋友圈动态demo