天天看點

深入了解Video标簽

深入了解Video标簽

作者 | 華仔專業打雜連結

Video相關屬性

1、自動播放

目前主流浏覽器加強了對自動播放政策(Autoplay)的限制:浏覽器在沒有互動操作之前不允許有聲音的媒體檔案自動播放。 而且各個浏覽器關于自動播放政策有不同的實作。

{/* 自動播放 */}
<video ref={ videoRef } controls autoPlay />      

為了解決自動播放失敗,在這裡介紹兩種方法解決 Autoplay 限制的方案

播放失敗時繞過 Autoplay 限制

直接繞過 Autoplay 限制

1.1 播放失敗時繞過 Autoplay 限制​

在實際使用中,頁面并不是完全被 Autoplay 限制,随着使用者使用這個頁面的次數增加,浏覽器會将這個頁面加入自己的 Autoplay 白名單清單中。

根據這個原理,可在檢測到播放失敗時,引導使用者點選頁面上的某個位置來恢複播放。(Google浏覽器下測試均播放失敗)​

// 可播放監聽。當浏覽器能夠開始播放指定的音頻/視訊時觸發
this.videoRef.addEventListener('canplay', () => {
    console.log('視訊可以播放了')
    setTimeout(() => {
        // this.videoRef.paused 判斷是否暫停,用來判斷是視訊是否在播放中,如果沒有播放就
        console.log(this.videoRef.paused) 
        console.log('視訊是否在暫停中', this.videoRef.paused) 
        this.isPlay = !this.videoRef.paused
    }, 500)
})


// 通過promise來判斷是否在播放
const videoPromise = this.videoRef.play()
if(!!videoPromise) {
    videoPromise.then(() => {
        this.isPlay = true
        console.log('播放成功')
    }).catch(() => {
        this.isPlay = false
        console.log('播放失敗')
    })
} else {
    // 此時可以通過canplay 監聽是否在播放
}      
1.2 直接繞過 Autoplay 限制​

可以通過如下兩種方案實作直接繞過 Autoplay 限制

在video标簽中關閉靜音muted屬性設定為true。媒體不包含聲音時不會被 Autoplay 限制。(引導使用者開啟聲音)

UI上引導使用者觸發播放

注意:無論使用哪種方案,在自動播放政策的限制下,沒有使用者操作之前都不可能自動播放有聲媒體。

雖然浏覽器會在本地維護一個白名單來決定對哪些網站解除自動播放限制,但該白名單無法通過 JavaScript 探測到。​

// 移動端
document.body.addEventListener('touchstart', () => {
    console.log('觸發播放')
    this.videoRef.play();
})
// PC端
document.body.addEventListener('mousedown', () => {
    console.log('觸發播放')
    this.videoRef.play();
})
// 微信端IOS手機下觸發自動播放,大部分IOS能正常自動播放(安卓機隻能通過touchstart觸發播放)
document.body.addEventListener('WeixinjsBridgeReady', () => {
    console.log('觸發播放')
    this.videoRef.play();
})      

注意: Safari 隻允許通過使用者互動來觸發有聲媒體的播放,而不是在使用者互動後就打開 Autoplay 限制。

2、播放時間屬性控制

首先我們來看一段代碼,在Google端能夠正常播放,但是在移動端和Safari中還是重頭開始播放。使用了canplay 和loadedmetadata,oncanplay事件來判斷視訊狀态再設定currentTime,但移動端還是無效。​

const videoPromise = this.videoRef.play()
this.videoRef.currentTime =  10      

解決方案:​

設定視訊的Timeupdate事件監聽設定播放時間

使用定時器設定播放時間​

this.videoRef.play();   
// 通過時間更新播放時間
let timer = setTimeout(function(){
    // 這裡還是有一定的缺陷,如果使用者觸發了視訊播放,但是加載比較長就會有問題
    this.videoRef.currentTime = 需要設定的時間;
    clearTimeout(timer);
},200);


// timeupdate:目前的播放位置已更改時,播放時間更新
this.videoRef.addEventListener('timeupdate', (e) => {
    console.log('timeupdate')
    let timeDisplay = Math.floor(this.videoRef.currentTime);
    if(timeDisplay > 0){
        if(this.firstOpen){
            this.videoRef.currentTime = 10;
            this.firstOpen = false;
        }  
    }
})


// seeking:查找開始。當使用者開始移動/跳躍到音頻/視訊中新的位置時觸發
this.videoRef.addEventListener('seeking', (e) => {
    // 在這裡處理視訊播放是否播到放指定的時間
    console.log('開始移動進度條', this.videoRef.currentTime)
})


// seeked:查找結束。當使用者已經移動/跳躍到視訊中新的位置時觸發
this.videoRef.addEventListener('seeked', (e) =>  {
    console.log('進度條已經移動到了新的位置', this.videoRef.currentTime)
})      

其他屬性介紹:

this.videoRef.error; //null:正常

this.videoRef.error.code; //1.使用者終止 2.網絡錯誤 3.解碼錯誤 4.URL無效

this.videoRef.networkState; //0.此元素未初始化 1.正常但沒有使用網絡 2.正在下載下傳資料 3.沒有找到資源

this.videoRef.buffered; //傳回已緩沖區域,TimeRanges

this.videoRef.paused; //是否暫停

this.videoRef.defaultPlaybackRate = value;//預設的回放速度,可以設定

this.videoRef.playbackRate = value;//目前播放速度,設定後馬上改變

this.videoRef.played; //傳回已經播放的區域,TimeRanges,

this.videoRef.seekable; //傳回可以seek的區域 TimeRanges

this.videoRef.ended; //是否結束

Video相關事件​

了解Video 标簽相關事件觸發時機,才能處理好業務相關邏輯。​

// loadstart 視訊查找。當浏覽器開始尋找指定的音頻/視訊時觸發,也就是當加載過程開始時
this.videoRef.addEventListener('loadstart', (e) => {
    console.log('提示視訊的中繼資料已加載')
    // console.log(e)
    console.log(this.videoRef.duration)            // NaN
})


// durationchange 時長變化。當指定的音頻/視訊的時長資料發生變化時觸發,加載後,時長由 NaN 變為音頻/視訊的實際時長
this.videoRef.addEventListener('durationchange', (e) => {
    console.log('提示視訊的時長已改變')
    console.log(this.videoRef.duration)           // 視訊的實際時長(機關:秒)
})


// loadedmetadata :中繼資料加載。當指定的音頻/視訊的中繼資料已加載時觸發,中繼資料包括:時長、尺寸(僅視訊)以及文本軌道
this.videoRef.addEventListener('loadedmetadata', (e) => {
    console.log('提示視訊的中繼資料已加載')
    // console.log(e)
})


// loadeddata:視訊下載下傳監聽。當目前幀的資料已加載,但沒有足夠的資料來播放指定音頻/視訊的下一幀時觸發
this.videoRef.addEventListener('loadeddata', (e) => {
    console.log('提示目前幀的資料是可用的')
})


// progress:浏覽器下載下傳監聽。當浏覽器正在下載下傳指定的音頻/視訊時觸發
this.videoRef.addEventListener('progress', (e) => {
    console.log('提示視訊正在下載下傳中')
})


// canplay:可播放監聽。當浏覽器能夠開始播放指定的音頻/視訊時觸發
this.videoRef.addEventListener('canplay', (e) => {
    console.log('視訊可以播放了')
    setTimeout(() => {
        // this.videoRef.paused 判斷是否暫停
        console.log('視訊是否在暫停中', this.videoRef.paused) 
        this.isPlay = !this.videoRef.paused
    }, 1000)
})


// canplaythrough:可流暢播放。當浏覽器預計能夠在不停下來進行緩沖的情況下持續播放指定的音頻/視訊時觸發
this.videoRef.addEventListener('canplaythrough', (e) => {
    console.log('提示視訊能夠不停頓地一直播放')
    console.log(e)
})


// play: 播放監聽
this.videoRef.addEventListener('play', (e) => {
    console.log('提示該視訊正在播放中')
})


// pause:暫停監聽
this.videoRef.addEventListener('pause', (e) => {
    console.log('暫停播放')
})


// seeking:查找開始。當使用者開始移動/跳躍到音頻/視訊中新的位置時觸發
this.videoRef.addEventListener('seeking', (e) => {
    // 在這裡處理到底有沒有更新到最新的位置
    console.log('開始移動進度條', this.videoRef.currentTime)
})


// seeked:查找結束。當使用者已經移動/跳躍到視訊中新的位置時觸發
this.videoRef.addEventListener('seeked', (e) =>  {
    console.log('進度條已經移動到了新的位置', this.videoRef.currentTime)
})


// waiting:視訊加載等待。當視訊由于需要緩沖下一幀而停止,等待時觸發
this.videoRef.addEventListener('waiting', (e) => {
    console.log('視訊加載等待')
    console.log(e)
})


// playing:當視訊在已因緩沖而暫停或停止後已就緒時觸發
this.videoRef.addEventListener('playing', (e) => {
    console.log('playing')
    console.log(e)
})


// timeupdate:目前的播放位置已更改時,播放時間更新
this.videoRef.addEventListener('timeupdate', (e) => {
    // console.log('timeupdate')
    // let timeDisplay = Math.floor(this.videoRef.currentTime);
    // if(timeDisplay > 0){
    //     if(this.firstOpen){
    //         this.videoRef.currentTime = 10;
    //         this.firstOpen = false;
    //     }  
    // }
})


// ended:播放結束
this.videoRef.addEventListener('ended', (e) => {
    console.log('視訊播放完了')
    console.log(e)
})


// error:播放錯誤
this.videoRef.addEventListener('error', (e) => {
    console.log('視訊出錯了')
    console.log(e)
})


// volumechange:當音量更改時
this.videoRef.addEventListener('volumechange', (e) => {
    console.log('volumechange')
    console.log(e)
})


// stalled:當浏覽器嘗試擷取媒體資料,但資料不可用時
this.videoRef.addEventListener('stalled', (e) => {
    console.log('stalled')
    console.log(e)
})


// ratechange:當視訊的播放速度已更改時
this.videoRef.addEventListener('ratechange', (e) => {
    console.log('ratechange')
    console.log(e)
})      

關于微信H5視訊相容介紹: 移動端相容

最後

移動端Web對于Video自動播放的相容性是在太差,尤其安卓。各種問題,各種相容,各種心累。

本文到此結束。希望對你有幫助。