H5 瀏覽器自定義用戶控件——嘿

參考文章:
https://css-tricks.com/custom...
https://blog.hellojs.org/crea...css

原生用戶控件

對於 <video>標籤,有一個名爲 'controls' 的屬性,按以下寫法就能給播放器增長原生的暫停/開始、進度條、音量、視頻最大化這些基礎功能。html

<video id="myVideo" controls ></video>

可是原生控件每每沒法知足咱們的一些需求,因此自定義用戶控件仍是很必要的。
首先聲明一個變量,咱們把 <video id="video"></video>作以下定義html5

let videoElement = document.getElementById('video');
let $videoElement = $('#video');

自定義用戶控件

如何實現自定義控件,提及來也很簡單,只須要藉助幾個 H5 播放器的事件和屬性就能夠了:web

暫停和開始

暫停和開始是最基本的功能了,實現起來很簡單
開始:chrome

videoElement.play()

暫停:bootstrap

videoElement.pause()

因此只須要在當前視頻暫停的時候調用play()方法就能夠繼續播放,同理在視頻正在播放的時候調用pause()就能夠了。
提的一提的是『判斷當前視頻是否暫停』
若是僅用videoElement.paused來判斷視頻暫停可能會有報錯api

The play() request was interrupted by a call to pause().

,通過查詢,最後使用了isPlaying 變量來判斷視頻是否暫停瀏覽器

let isPlaying = videoElement.currentTime > 0 && !videoElement.paused && !videoElement.ended && videoElement.readyState > 2;

最後暫停/開始事件的方法以下:dom

let playpauseToggle = function(e){
            let isPlaying = videoElement.currentTime > 0 && !videoElement.paused && !videoElement.ended && videoElement.readyState > 2;
            if(!isPlaying) {
                videoElement.play();
            }
            else {
                videoElement.pause();
            }
            return false;
        }

視頻當前時長/總時長

這個就很容易了,藉助兩個參數便可;
duration 能夠獲取視頻總時長
currentTime 能夠獲取視頻當前時長ide

視頻總時長在視頻載入後獲取一次便可,
視頻當前時間則不一樣,每當視頻進度更新一次後,視頻當前時間就須要隨之更新
loadedmetadata事件:獲取視頻元數據。
timeupdate事件:視頻播放後,更新播放進度的事件。 會有明確的進度變化,能夠獲取到currentTime
值得一提的是,用durationcurrentTime 獲取到的數據格式是保留了若干位小數,以秒爲單位的一個值,一般須要根據須要格式化一下,我爲了將『十分鐘二十四秒』格式化爲10:24這樣的格式,建立了以下方法

let numberToTime = function(number){
            number = parseInt(number,10);
            let minues = 0;
            let second = 0;
        
            minues = parseInt(number / 60, 10);
            second = number % 60

            if(minues<10){
                minues = '0'+ minues
            }

            if(second<10){
                second = '0'+ second
            }

            return minues + ':' + second;
        }

以及監聽對應事件並更新當前時間的代碼以下

$videoElement.on('loadedmetadata', function() {
       $('.duration').text(numberToTime(videoElement.duration));
    });

    $videoElement.on('timeupdate', function() {
       $('.current').text(numberToTime(videoElement.currentTime));
    });
<div class="progressTime">
   <span class="current">00:00</span> / <span class="duration">00:00</span>
</div>

進度條

沒有進度條的視頻不是好視頻,實現一個進度條很重要
聲明一點:進度條這裏的樣式我使用了 bootstrap 的 dom 結構以下

<div class="progress">
  <div class="progress-bar progress-bar-primary" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">  </div>
  <div class="bufferBar progress-bar progress-bar-buffered"></div>
</div>

有兩個條,一個是當前進度,一個是緩衝進度。
基本原理也很簡單,獲取 當前時間/總時長 * 100% 的值,而後把這個值賦給進度條對應 dom 的樣式中的 'width',經過timeupdate事件不斷更新便可。

$videoElement.on('timeupdate', function() {
        let currentPos = videoElement.currentTime;
        let maxduration = videoElement.duration;
        let percentage = 100 * currentPos / maxduration;
        $('.progress-bar-primary').css('width', percentage + '%');
     })

緩衝進度條和上面的實現基本一致,對應上面currentPos值的是

let currentBuffer = videoElement.buffered.end(0)

進度條不但要能看進度,還要能拖拽進度
拖拽進度的思路是:根據鼠標在進度條上的mousedown事件和mouseup事件鼠標的 X 座標量(含正負)變化來肯定當前進度的變化程度。

具體代碼以下:

let timeDrag = false;   /* Drag status */
$('.progress').mousedown(function(e) {
    timeDrag = true;
    updatebar(e.pageX);
});
$(document).mouseup(function(e) {
    if(timeDrag) {
        timeDrag = false;
        updatebar(e.pageX);
    }
});
$(document).mousemove(function(e) {
    if(timeDrag) {
        updatebar(e.pageX);
    }
});
 
let updatebar = function(x) {
    let progress = $('.progress');
    let maxduration = videoElement.duration; //視頻總時長
    let position = x - progress.offset().left; //變化量
    let percentage = 100 * position / progress.width();
 
    //超出範圍的修正
    if(percentage > 100) {
        percentage = 100;
    }
    if(percentage < 0) {
        percentage = 0;
    }
 
    //更新進度條和當前時間
    $('progress-bar').css('width', percentage+'%');
    videoElement.currentTime = maxduration * percentage / 100;
};

音量

音量的控制很容易,主要藉助如下方法和屬性,具體的交互能夠爲所欲爲的實現。以前還有看過一篇文章是介紹喪心病狂的音量鍵的,能夠學習學習[滑稽]:http://adquan.com/post-10-410...

videoElement.muted = true //靜音
videoElement.muted = false //解除靜音

videoElement.volume = 1 //設置音量爲最大值
videoElement.volume = 0.5 //設置音量爲50%
videoElement.volume = 0 //設置音量爲最小值

全屏

全屏是一個兼容起來有點麻煩的功能。
若是你要爲 firefox 寫用戶控件的話,調用全屏 api 的就得是 <video><div class="controls"><div>的共同父元素,否則會發現全屏後,你的用戶控件看不到了。(但然,firefox 原生的用戶控件比 chrome 的好看一百倍,因此你要是用原生的用戶控件,那直接 element.requestFullscreen()就行)
同時咱們也記下這個 tips :能調用全屏 api 的不僅是<video>

<div class="live__player">
    <video></video>
    <div class="controls"></div>
</div>
//全屏
function fullScreenOn(element) {
    if(element.requestFullscreen) {
        element.requestFullscreen();
    } else if(element.mozRequestFullScreen) {
        $('.live__player')[0].mozRequestFullScreen();
    } else if(element.msRequestFullscreen){ 
        element.msRequestFullscreen(); 
    } else if(element.oRequestFullscreen){
        element.oRequestFullscreen();
    } else if(element.webkitRequestFullscreen)
    {
        element.webkitRequestFullScreen();
    } else{

        var docHtml = document.documentElement;
        var docBody = document.body;
        var videobox = document.getElementById('sfLive');
        var cssText = 'width:100%;height:100%;overflow:hidden;';
        docHtml.style.cssText = cssText;
        docBody.style.cssText = cssText;
        videobox.style.cssText = cssText+';'+'margin:0px;padding:0px;';
        document.IsFullScreen = true;

    }
    $controls.css('z-index','2147483647');
    
}

此處傳入的值就是videoElement

<small>`(videoElement = document.getElementById('video');)`</small>

另一點,最後一行代碼作的是:把咱們自定義控件的 z-index 屬性設置爲瀏覽器最大值。緣由是,webkit 內核的瀏覽器在全屏的時候,視頻的 z-index 變爲了瀏覽器容許的最大值,咱們把自定義控件的 z-index 也設置爲最大值,就能避免用戶控件被視頻遮住。

一樣的,退出全屏模式的代碼以下:

function fullScreenOff() {
    if (document.exitFullscreen) {
        document.exitFullscreen();
    } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
    } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
    } else if(document.oRequestFullscreen){
        document.oCancelFullScreen();
    } else if (document.webkitExitFullscreen){
        document.webkitExitFullscreen();
    } else {
        var docHtml = document.documentElement;
        var docBody = document.body;
        var videobox = document.getElementById('sfLive');
        docHtml.style.cssText = "";
        docBody.style.cssText = "";
        videobox.style.cssText = "";
        document.IsFullScreen = false;
    }

    $('.live__playcontrol').css('z-index','1');
}

檢查視頻是否全屏的代碼以下:

let isFullScreen =  document.fullscreenElement ||
                    document.webkitFullscreenElement ||
                    document.mozFullScreenElement ||
                    document.msFullscreenElement

踩坑

  1. 視頻開始/暫停的判斷依據

    文中已寫,代碼以下
    let isPlaying = videoElement.currentTime > 0 && !videoElement.paused && !videoElement.ended && videoElement.readyState > 2;
  2. firefox 全屏後,自定義的用戶控件不見了

    文中已寫,和其餘瀏覽器不一樣,firefox 不是用 `<video>`元素的 dom 對象去調用`requestFullscreen()`,而是用 `<video>`元素的父元素去調。
  3. shadowDom 隱藏的問題
    若是你發現,你明明把 <video>元素的屬性controls去掉了,可是原生控件依然顯示,那麼只有用 CSS 去幹掉它

video::-webkit-media-controls-enclosure {
  display:none !important;
}
相關文章
相關標籤/搜索