自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Javascript如何實(shí)現(xiàn)類似西瓜視頻的視頻隊(duì)列自動(dòng)播放?

開發(fā) 架構(gòu)
我的第一思路就是監(jiān)聽滾動(dòng)位置來判斷某個(gè)視頻元素是否到達(dá)指定區(qū)域內(nèi),但是這種方式需要處理的條件很多,比如邊界條件判斷,滾動(dòng)方向判斷等,而且頻繁觸發(fā)還會(huì)出現(xiàn)性能問題。

[[420253]]

前言

去年利用空余時(shí)間研究了一下javascript的Intersection Observer API,發(fā)現(xiàn)其有很大的應(yīng)用場(chǎng)景,比如圖片或者內(nèi)容的懶加載,視差動(dòng)畫等。我也在之前的文章中詳細(xì)介紹了3種Observer(觀察者)的用法,包括位置監(jiān)聽,dom變化監(jiān)聽以及窗口變化監(jiān)聽,它們有非常多的應(yīng)用場(chǎng)景,所以很有必要研究明白, 感興趣的可以讀完本片文章之后學(xué)習(xí)一下(幾個(gè)非常有意思的javascript知識(shí)點(diǎn)總結(jié)).

這里有一個(gè)很常見的例子,平時(shí)喜歡看短視頻的朋友可能會(huì)注意到,我們?cè)跒g覽某視頻頭條時(shí),滾動(dòng)視頻列表,當(dāng)某一個(gè)視頻滾動(dòng)到手機(jī)的一定位置時(shí)(一般可以看成是屏幕中心),該視頻會(huì)自動(dòng)播放,當(dāng)移出指定區(qū)域后視頻會(huì)自動(dòng)關(guān)閉并播放移入指定區(qū)域的下一個(gè)視頻,如下:

作為一名好奇心極強(qiáng)的前端工程師,有必要好好研究一下其內(nèi)部實(shí)現(xiàn)。

我的第一思路就是監(jiān)聽滾動(dòng)位置來判斷某個(gè)視頻元素是否到達(dá)指定區(qū)域內(nèi),但是這種方式需要處理的條件很多,比如邊界條件判斷,滾動(dòng)方向判斷等,而且頻繁觸發(fā)還會(huì)出現(xiàn)性能問題。

好在之前深入研究過Intersection Observer API,發(fā)現(xiàn)可以使用它提供的API,很方便的監(jiān)聽到元素在指定根元素下的位置變化,并做一些自定義操作:

接下來我將利用Intersection Observer提供的api來實(shí)現(xiàn)視頻在滾動(dòng)的過程中自動(dòng)播放的功能,如果對(duì)該api不太熟悉的朋友可以移步

幾個(gè)非常有意思的javascript知識(shí)點(diǎn)總結(jié)

視頻播放插件筆者將使用比較流行的Dplayer,它可以很方便的操作視頻的展現(xiàn)并實(shí)現(xiàn)很好的排他性播放控制,并且支持彈幕。

正文

根據(jù)以上的介紹我們大致了解了具體的需求,接下來我們就來基于Intersection Observer API實(shí)現(xiàn)一下它。思路大致如下圖所示:

具體思路就是我們可以把Intersection Observer的根元素的rootMargin(即根元素的外邊距)設(shè)置為如上圖藍(lán)色所示區(qū)域,然后當(dāng)視頻完全進(jìn)入該區(qū)域內(nèi)后(也就是thresholds閾值為1時(shí)),觸發(fā)當(dāng)前視頻的播放即可。因?yàn)槲覀兪褂玫氖荄player,所以我們只要將其配置屬性中的mutex屬性設(shè)置為true(為true時(shí)會(huì)阻止多個(gè)播放器同時(shí)播放,當(dāng)前播放器播放時(shí)暫停其他播放器)。有關(guān)設(shè)置rootMargin的知識(shí),可以參考下圖介紹:

rootMargin接收格式如下:"10px 0px 10px 0px",從左到右數(shù)字依次代表top(上) right(右) bottom(下) left(左)邊距,當(dāng)然我們單位也可以使用百分比(%),為正值時(shí)代表擴(kuò)大更元素的邊距范圍,負(fù)值代表縮小根元素的邊距范圍,這里我們應(yīng)該縮小范圍,所以rootMargin我們可以這么設(shè)置"-180px 0px -180px 0px",這樣上下的邊距就會(huì)縮小,當(dāng)然大家也可以根據(jù)需求設(shè)置不同的值。

有了以上思路之后我們就可以實(shí)現(xiàn)上文動(dòng)圖所展示的效果了。筆者將采用react來實(shí)現(xiàn),在實(shí)現(xiàn)之前我們先準(zhǔn)備幾個(gè)視頻素材,然后實(shí)現(xiàn)列表基本框架:

  1. import React, { useEffect, useState } from 'react' 
  2. import VideoItem from 'components/VideoItem' 
  3. import styles from './videoList.less' 
  4.  
  5. const data = [ 
  6.     // 視頻列表 
  7.  
  8. function VideoList(props) { 
  9.   useEffect(() => { 
  10.     let observerVideo = new IntersectionObserver( 
  11.         (entries, observer) => { 
  12.             entries.forEach(entry => { 
  13.                 // 當(dāng)移入指定區(qū)域內(nèi)后,播放視頻 
  14.                 if(entry.intersectionRatio === 1) { 
  15.                     // 一些操作 
  16.                     return 
  17.                 } 
  18.                 // 停止監(jiān)聽 
  19.                 // observer.unobserve(entry.target); 
  20.               }); 
  21.             }, 
  22.             { 
  23.               root: document.getElementById('scrollView'), 
  24.               rootMargin: '-180px 0px -180px 0px'
  25.               threshold: 1 
  26.             } 
  27.         ); 
  28.         document.querySelectorAll('.video-item').forEach(video => { observerVideo.observe(video) }); 
  29.   }, []) 
  30.   return <div className={styles.videoWrap}> 
  31.     <div className={styles.list} id="scrollView"
  32.         { 
  33.             data.map(item => { 
  34.                 return <VideoItem src={item} groupName="video-item" key={item} /> 
  35.             }) 
  36.         } 
  37.     </div> 
  38.   </div> 
  39.  
  40. export default VideoList 

以上代碼中VideoItem組件我們后面會(huì)介紹,現(xiàn)在有個(gè)問題是我們已經(jīng)監(jiān)聽到了需要自動(dòng)播放的視頻元素,但是我們?nèi)绾瓮ㄖ猇ideoItem組件讓其播放呢?這里筆者實(shí)現(xiàn)思路是給VideoItem添加一個(gè)自定義屬性,該屬性的值就是當(dāng)前video的src,我們?cè)诒O(jiān)聽到某個(gè)視頻元素需要播放時(shí),我們可以獲取到之前設(shè)置的自定義屬性,然后作為prop傳給VideoItem,當(dāng)VideoItem組件監(jiān)聽到該prop變化時(shí),并且等于自身的src,此時(shí)則觸發(fā)視頻播放。代碼如下:

  1. // VideoItem.js 
  2. import React, { useRef, useEffect } from 'react'
  3. import DPlayer from 'dplayer'
  4.  
  5. export default (props) => { 
  6.     let videoRef = useRef(null
  7.     let dpRef = useRef(null
  8.     let { src, groupName, curPlaySrc } = props 
  9.     useEffect(() => { 
  10.         dpRef.current = new DPlayer({ 
  11.             container: videoRef.current
  12.             screenshot: true
  13.             video: { 
  14.                 url: src, 
  15.                 thumbnails: 'logo.png' 
  16.             }, 
  17.             logo: 'logo.png' 
  18.         }); 
  19.     }, []) 
  20.  
  21.     useEffect(() => { 
  22.         // 當(dāng)當(dāng)當(dāng)前應(yīng)該播放的視頻url等于當(dāng)前視頻組件的src時(shí),播放視頻 
  23.         if(curPlaySrc === src) { 
  24.             dpRef.current.play() 
  25.         } 
  26.     }, [curPlaySrc]) 
  27.     return <div data-src={src}> 
  28.         <div ref={videoRef}></div> 
  29.     </div> 

此時(shí)視頻列表頁(yè)代碼如下:

  1. // ... 
  2. function VideoList(props) { 
  3.   const [curPlaySrc, setCurPlaySrc] = useState(''
  4.   useEffect(() => { 
  5.     let observerVideo = new IntersectionObserver( 
  6.         (entries, observer) => { 
  7.             entries.forEach(entry => { 
  8.                 // 當(dāng)移入指定區(qū)域內(nèi)后,播放視頻 
  9.                 if(entry.intersectionRatio === 1) { 
  10.                     // 設(shè)置當(dāng)前因該播放的視頻url 
  11.                     setCurPlaySrc(entry.target.dataset.src) 
  12.                     return 
  13.                 } 
  14.               }); 
  15.             }, 
  16.             { 
  17.               root: document.getElementById('scrollView'), 
  18.               rootMargin: '-180px 0px -180px 0px'
  19.               threshold: 1 
  20.             } 
  21.         ); 
  22.         document.querySelectorAll('.video-item').forEach(video => { observerVideo.observe(video) }); 
  23.   }, []) 
  24.   return <div className={styles.videoWrap}> 
  25.     <div className={styles.list} id="scrollView"
  26.         { 
  27.             data.map(item => { 
  28.                 return <VideoItem src={item} groupName="video-item" key={item} curPlaySrc={curPlaySrc} /> 
  29.             }) 
  30.         } 
  31.     </div> 
  32.   </div> 

以上步驟即完成了基于指定區(qū)域自動(dòng)播放視頻的功能,效果如下:

體驗(yàn)地址

視頻自動(dòng)播放demo

仿微信朋友圈動(dòng)態(tài)demo

最后

 

如果想學(xué)習(xí)更多H5游戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數(shù)據(jù)可視化等前端知識(shí)和實(shí)戰(zhàn),歡迎在公號(hào)《趣談前端》加入我們的技術(shù)群一起學(xué)習(xí)討論,共同探索前端的邊界。

 

責(zé)任編輯:武曉燕 來源: 趣談前端
相關(guān)推薦

2022-08-26 12:13:08

APIjavascript視頻

2022-03-06 20:02:21

監(jiān)聽視頻播放

2022-06-21 14:41:38

播放器適配西瓜視頻

2009-06-02 08:55:43

2021-04-01 08:22:04

微軟Edge瀏覽器

2024-03-14 08:24:25

MediaCodec解碼播放Android

2013-07-01 10:53:05

2018-05-18 14:12:41

Chrome 66自動(dòng)播放

2017-03-27 09:00:09

Windows 7Windows自動(dòng)播放

2011-07-20 16:21:20

iPhone 視頻 播放器

2024-08-20 09:59:22

2011-03-21 10:13:22

Ubuntu自動(dòng)播放

2024-01-03 16:39:07

2009-10-20 10:05:22

Windows 7策略組關(guān)閉自動(dòng)播放

2011-08-03 13:30:08

組策略自動(dòng)播放

2023-06-02 14:18:55

2011-08-23 09:47:20

UbuntuU盤

2020-06-28 14:35:54

OBSWebSockets開源

2022-05-29 16:59:21

微軟Edge瀏覽器

2024-02-05 08:41:08

因果推斷快手短視頻應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)