前言
我利用业余时间研究了javascript.的Intersection Observer原料药
发现它有很大的应用场景,比如图片或内容的偷懒加载,视差动画等等。在以前的文章中,作者还详细介绍了三种Observer,的用法,包括:
位置监听,dom变化监听和窗口变化监听的应用场景很多,有必要研究清楚。
感兴趣的可以看完这篇文章再学习。
这里有一个非常常见的例子。平时喜欢看短视频的朋友可能会注意到,当我们浏览一个视频的标题时,会滚动视频列表。当一个视频滚动到手机上的某个位置(一般可以认为是屏幕的中心)时,视频会自动播放。移出指定区域后,视频会自动关闭并播放下一个移入指定区域的视频,如下所示:
作为一个好奇的前端工程师,有必要研究一下它的内部实现。
笔者首先想到的是通过监控滚动位置来判断一个视频元素是否到达指定区域,但这种方法需要处理很多条件,比如边界条件判断、滚动方向判断等。频繁触发也会导致性能问题。
好的,我之前深入研究过Intersection Observer原料药。
发现它提供的API可以很方便地监控指定根元素下元素位置的变化,并做一些自定义操作:
接下来,我将直接使用Observer十字路口提供的api来实现视频在滚动的过程中自动播放.
功能,如果你不熟悉api,可以踩几个非常有趣的javascript知识点总结。
作者将使用流行的Dplayer视频插件,可以轻松操作视频演示,实现良好的独家播放控制,并支持弹幕。
主体
根据上面的介绍,我们对具体的需求有了一个大概的了解,接下来我们将基于Intersection ObserverAPI来实现。思路大致如下图所示:
具体的想法是我们可以把Observer十字路口的根元素当成rootMargin.
(即根元素的外边缘距离)设置为上面蓝色显示的区域,然后当视频完全进入该区域时(即thresholds)。
当阈值为1)时,触发当前视频的播放。因为我们正在使用Dplayer,所以我们只需要在属性中将它配置为mutex。
属性设置为true(如果为true,将阻止多个玩家同时玩,当前玩家玩时其他玩家将被暂停)。关于建立rootMargin.
知识,可以参考下图:
://p6.toutiaoimg.com/large/pgc-image/417335525f1a44daaad282624006713c' alt='前端如何实现类似西瓜视频的视频队列自动播放?' />rootMargin 接收格式如下:"10px 0px 10px 0px",从左到右数字依次代表 top (上) right
(右) bottom (下) left
(左)边距,当然我们单位也可以使用百分比(%),为正值时代表扩大更元素的边距范围,负值代表缩小根元素的边距范围,这里我们应该缩小范围,所以
rootMargin 我们可以这么设置"-180px 0px -180px 0px",这样上下的边距就会缩小,当然大家也可以根据需求设置不同的值。
有了以上思路之后我们就可以实现上文动图所展示的效果了。笔者将采用react来实现,在实现之前我们先准备几个视频素材,然后实现列表基本框架:
import React, { useEffect, useState } from 'react'import VideoItem from 'components/VideoItem'import styles from './videoList.less'const data = [ // 视频列表]function VideoList(props) { useEffect(() => { let observerVideo = new IntersectionObserver( (entries, observer) => { entries.forEach(entry => { // 当移入指定区域内后,播放视频 if(entry.intersectionRatio === 1) { // 一些操作 return } // 停止监听 // observer.unobserve(entry.target); }); }, { root: document.getElementById('scrollView'), rootMargin: '-180px 0px -180px 0px', threshold: 1 } ); document.querySelectorAll('.video-item').forEach(video => { observerVideo.observe(video) }); }, []) return
以上代码中 VideoItem 组件我们后面会介绍,现在有个问题是我们已经监听到了需要自动播放的视频元素,但是我们如何通知
VideoItem 组件让其播放呢?这里笔者实现思路是给 VideoItem
添加一个自定义属性,该属性的值就是当前video的src,我们在监听到某个视频元素需要播放时,我们可以获取到之前设置的自定义属性,然后作为 prop
传给 VideoItem ,当 VideoItem 组件监听到该 prop
变化时,并且等于自身的src,此时则触发视频播放。代码如下:
import React, { useEffect, useState } from 'react'import VideoItem from 'components/VideoItem'import styles from './videoList.less'const data = [ // 视频列表]function VideoList(props) { useEffect(() => { let observerVideo = new IntersectionObserver( (entries, observer) => { entries.forEach(entry => { // 当移入指定区域内后,播放视频 if(entry.intersectionRatio === 1) { // 一些操作 return } // 停止监听 // observer.unobserve(entry.target); }); }, { root: document.getElementById('scrollView'), rootMargin: '-180px 0px -180px 0px', threshold: 1 } ); document.querySelectorAll('.video-item').forEach(video => { observerVideo.observe(video) }); }, []) return
以上步骤即完成了基于指定区域自动播放视频的功能,效果如下:
最后
如果想学习更多 H5游戏 , webpack , node , gulp , css3 ,
javascript , nodeJS , canvas数据可视化
等前端知识和实战,欢迎在《趣谈前端》专栏学习讨论,共同探索前端的边界。