官术网_书友最值得收藏!

3.3 范例——制作視頻播放器APP

上面的示例已經向讀者展示HTML 5帶來的video元素在瀏覽器視頻上的突破,擺脫了傳統瀏覽器播放視頻過度依賴于第三方插件的局面。雖然video非常美好,但是各種瀏覽器對視頻控件的實現不同,在原有的面板增加自定義功能更是難上加難。本例將初步實現一個自定義的播放器,給各位讀者提供一個思路。

本例播放器將實現3個基本功能:播放、暫停、全屏。使用Chrome瀏覽器打開網頁文件,運行結果如圖3.5所示。點擊視頻中央的播放按鈕,運行結果如圖3.6所示。

圖3.5 使用Chrome打開網頁文件

圖3.6 點擊視頻中央的播放按鈕

此時,中央的播放按鈕被隱藏,緊隨著出現視頻底部工具條。該工具條并非瀏覽器原生視頻工具條,而是通過HTML進行模擬定制。如圖3.6所示,工具條上出現了左下角暫停按鈕和右下角全屏按鈕。

提示

除了例子實現的3個功能外,后續例子將會在本例實現的基礎上進行加強,讀者可以繼續閱讀后續示例,感受自定義的魅力。

3.3.1 普通視頻播放器

利用編輯器打開“3-4.普通視頻播放器.html”文件,代碼如下:

【代碼3-4】

        01    <! DOCTYPE HTML>
        02    <html>
        03    <head>
        04       <style>/* ......此處樣式忽略,讀者可以查看對應源代碼 */</style>
        05        <script src="../js/jquery-1.8.3.js"></script>
        06    </head>
        07    <body>
        08       <header><h2>做一個自己的視頻播放器</h2></header>
        09        <div class="video_box">
        10             <video src="../res/BigBuck.webm" width="480" height="320"
                    controls></video>
        11        </div>
        12    </body>
        13    <script>
        14        (function () {
        15            var CONTROLS_HTML = '......省略’;            // 播放工具條HTML,此處省略
        16            function VideoControl(ele) {                      // 播放工具條類
        17                  this.video = $(ele);
        18                  this.init();
        19             };
        20            VideoControl.prototype = {                        // 原型方法
        21                  init: function () {
        22                    // 移除video原本的controls屬性,去除瀏覽器默認工具條
        23                      this.video.removeAttr('controls');
        24                      this._render();
        25                      this._bind();
        26                  },
        27                _render: function () {                      // 用于生成工具條html結構
        28                      var wraper = this.wraper = $(document.createElement('div'));
        29                      wraper.html(CONTROLS_HTML);
        30                    this.video.parent().append(wraper);     // 將工具類插入文檔
        31                  },
        32                _bind: function () {                        // 給工具條的元素綁定事件
        33                      var self = this,
        34                        video = self.video.get(0),                // 獲取對應的原生元素
        35                           wraper = self.wraper,
        36                           control_btn = wraper.find('div.control_btn');
        37                    // 用jQuery的delegate方法委托特制元素監聽click事件
        38                      wraper.delegate('div[data-type]', 'click', function (e) {
        39                           var data_type = $(this).attr('data-type');
                              // 獲取按鈕自定義操作類型屬性
        40                           switch (data_type) {
        41                            case 'go':                                 // 初始屏中間大按鈕
        42                                    wraper.find('div.play_button').hide();
        43                                    wraper.find('div.play_controls').show();
        44                                video.play();               // 播放視頻
        45                                    break;
        46                            case 'play':                    // 自定義工具條播放鍵
        47                                    control_btn.toggle();
        48                                    video.play();
        49                                    break;
        50                            case 'pause':                   // 自定義工具條暫停鍵
        51                                control_btn.toggle();       // 暫停視頻
        52                                    video.pause();
        53                                    break;
        54                            case 'fullscreen':              // 自定義工具條全屏鍵
        55                                self._fullScreen(video);    // 調用實例的全屏方法
        56                                    break;
        57                           };
        58                      });
        59                  },
        60                _fullScreen: function (video) {             // 全屏方法
        61                      var prefixs = 'Webkit Moz O ms Khtml'.split(' '),
                          // 各種瀏覽器全屏方法前綴
        62                           parent = video,  prefix;
        63                    // 循環各瀏覽器前綴名,找尋符合的方法并執行
        64                      for (var i = 0, l = prefixs.length; i < l; i++) {
        65                           prefix = prefixs[i].toLowerCase();
        66
        67                           if (parent[prefix + 'EnterFullScreen']) {
                            // 兼容不同瀏覽器全屏方法
        68                                parent[prefix + 'EnterFullScreen']();
        69                                break;
        70                           } else if (parent[prefix + 'RequestFullScreen']) {
        71                                parent[prefix + 'RequestFullScreen']();
                                // 如果存在該方法即執行
        72                                break;
        73                           };
        74                      };
        75                  }
        76             };
        77             new VideoControl(document.querySelector('video'));
                  // 實例化自定義工具條類
        78        })();
        79    </script>
        80    </html>

代碼第16~19行定義了工具類構造函數。函數接收1個參數,該參數需要加入自定義工具條的video元素。

代碼第20~76行在VideoControl的prototype原型上增加如下4個方法:

● init:初始化函數。

● _render:生成工具條HTML結構。

● _bind:在工具條元素上綁定事件。

● _requestFullscreen:video元素全屏方法。

提示

prototype屬性是JavaScript面向對象編程的基礎,如果對其還不是很了解,可以參考http://msdn.microsoft.com/zh-cn/magazine/cc163419.aspx

_render方法將字符模板CONTROLS_HTML插入對應的video父節點中,用于構建工具條DOM結構。

_bind方法在工具條的外圍容器增加事件委托,監聽元素類型為符合選擇器“div[datatype]”的click事件。data-type是自定義的元素屬性,表示播放按鈕的類型。本例中共有4種類型,具體如下:

● go:初始狀態中央的大三角按鈕事件類型。

● play:工具條播放按鈕事件類型。

● pause:工具條暫停按鈕事件類型。

● fullscreen:工具條全屏按鈕事件類型。

在各種瀏覽器上,video元素的播放和暫停方法的名稱都相同,分別為play和pause。全屏方法由于還處于草案階段,因此需要加上對應瀏覽器的前綴名,代碼第60~75行就是為了解決這個問題而設置的。兼容方案可以參考代碼,這里不做過多說明。

細心的讀者會發現,Chrome瀏覽器下調用video全屏方法后,不論video是否帶有controls屬性,都會出現播放器的默認工具條,這顯然不是當初想看到的,讀者不妨先想想,稍后會給出解決方案。

提示

本次代碼分析主要針對示例的腳本邏輯,樣式說明可以參考源碼中的注釋。

3.3.2 添加視頻進度條

本例將完成給自定義播放器添加進度條的工作。一共會添加兩種進度條,分別為下載進度條和播放進度條。使用Chrome瀏覽器打開網頁文件,點擊屏幕中央的三角播放按鈕,播放器底部出現自定義工具條,同時進度條慢慢地向右伸長,運行效果如圖3.7所示。

圖3.7 點擊播放按鈕

圖3.7中的藍色進度條表示播放時間,灰色條表示視頻下載進度。將鼠標懸浮于進度條之上,此時進度條上方會出現對應的時間提示框,效果如圖3.8所示。

圖3.8 鼠標懸浮于進度條出現時間提示

本例的代碼構建在“3-5.添加視頻進度條.html”的功能基礎之上。下面對增添的代碼部分做一個分析。

字符串模板CONTROLS_HTML增加進度條HTML結構,代碼如下:

        '<div class="control progress_control">' +                          // 進度條外圍層
            '<div class="progress_bar_bg"></div>' +                   // 進度條背景層
            '<div class="progress_bar_buffered"></div>' +             // 下載進度條層
            '<div class="progress_bar_played"></div>' +               // 播放進度條層
            '<div class="progress_bar_time">' +                             // 懸浮提示外圍層
              '<div class="progress_bar_time_line"></div>' +
              '<div class="progress_bar_time_txt">00:00</div>' +      // 懸浮時間提示
            '</div>' +
        '</div>' +

提示

HTML模板對應的CSS可以參考源碼。

視頻工具類VideoControl的prototype原型上增加_progress和_bartime方法。其中_progress方法用于控制下載進度條的移動,代碼如下:

        _progress: function () {                                 // 控制下載進度條
            var self = this,
              video = self.video,                                // 實例上的video屬性
              video_ele = video.get(0),                          // 視頻的原生元素
              progress_bar = self.wraper.find('div.progress_control'), // 進度條外圍元素
              progress_bar_buffered =
    self.wraper.find('div.progress_bar_buffered'); // 下載進度條元素
            video.on({
              'progress': function (e) {                         // 監聽video的下載進度事件
                  if (this.buffered && this.buffered.length) {    // 判斷是否開始接收數據
                      var percent = video_ele.buffered.end(0) / video_ele.duration;
        // 下載數據相對總時間百分比
                      progress_bar_buffered.width(percent * progress_bar.width());
        // 設置下載進度條長度
                  };
              }
            });
        },

video的buffered屬性返回1個TimeRanges對象。TimeRanges對象表示音視頻的已緩沖部分,對象具有1個length屬性,表示音視頻中已緩沖范圍的數量,同時還具有兩個方法,即start和end,語法如下:

        video. buffered.start(index);                         // 獲得某個已緩沖范圍的開始位置
        video. buffered. end (index);                         // 獲得某個已緩沖范圍的結束位置

_bartime方法用于實現鼠標懸浮進度條的時間提示,代碼如下:

        _bartime: function () {                               // 鼠標懸浮進度條的時間提示
            var wraper = this.wraper,
              progress_control = wraper.find('div.progress_control'), // 進度條外圍元素
              progress_bar_bg = wraper.find('div.progress_bar_bg'),       // 進度條背景層
              progress_bar_time = wraper.find('div.progress_bar_time'),
              // 時間懸浮提示層外框
              progress_bar_time_txt = wraper.find('div.progress_bar_time_txt'),
              video_ele = this.video.get(0);                  // 懸浮提示時間元素
            progress_bar_bg.on({                              // 綁定進度條背景層
              'mousemove': function (e) {
                  var offsetX = e.clientX - progress_bar_bg.offset().left,
                  // 相對于進度條橫軸距離
                      percent = offsetX / progress_bar_bg.width();
                  progress_bar_time.css('left', offsetX + 6);     // 設置時間浮動框位置
                  progress_bar_time_txt.html(timeFormat((percent * video_ele.duration)|| 0));
              },
              'mouseenter': function (){ progress_bar_time.show(); }, // 移入顯示時間提醒
              'mouseleave': function (){ progress_bar_time.hide(); }// 移出隱藏時間提醒
            });
        }

最后,完成播放進度條的動態更新功能,修改原型方法_timeupdate,代碼如下:

        this.video.on({
            'timeupdate': function () {                            // 視頻播放位置變動時觸發
              currentTime.html(timeFormat(video.currentTime));     // 當前播放時間動態更新
              var percent = video.currentTime / video.duration;    // 播放時間占總時間百分比
              progress_bar_played.width(percent * progress_bar.width());
             // 設置播放進度條寬度
          },
          'loadedmetadata': function () {                  // 視頻元數據加載完畢后觸發
              duration.html(timeFormat(video.duration));
          }
        });

在上面的代碼中,將之前監聽video的play事件換為loadedmetadata事件,是為了保證視頻的元數據下載完畢后再設置視頻總耗時,避免在play事件觸發時獲取video的duration屬性為空。

提示

視頻的元素據包含時長、尺寸(僅視頻)以及文本軌道等信息。

3.3.3 添加視頻快進慢進按鈕

HTML 5的video元素幾乎帶來了所有傳統播放器都具備的功能,本例將在自定義播放器上加入慢進和快進按鈕。使用Chrome瀏覽器打開網頁文件,點擊屏幕中央的三角播放按鈕,播放器底部出現自定義工具條,同時下方工具條左端出現快慢進按鈕,運行效果如圖3.9所示。

圖3.9 點擊播放按鈕

本例的代碼構建在“3-6.添加視頻快進慢進按鈕.html”的功能基礎之上。下面對增添的代碼部分做一個分析。

字符模板增加快進和慢進HTML結構,代碼如下:

        <div class="control backward_control" data-type="backward" title="慢退
    "><div></div><div></div></div>
        <div class="control forward_control" data-type="forward" title="快進
    "><div></div><div></div></div>

提示

backward_control和forward_control樣式類,讀者可以參考下載資源源碼。

在HTML結構中,自定義data-type屬性表示對應按鈕元素執行的方法名。快進和慢進在委托方法中對應的方法名為“backward”和“forward”,方法執行腳本如下:

        case 'backward':                     // 自定義工具條慢退
            self._playbackRate(-0.1);        // 給實例方法_ playbackRate傳入負數播放速度
            break;
        case 'forward':                      // 自定義工具條快進
            self._playbackRate(0.1);
            break;

如上代碼所示,快慢進執行相同的實例方法_playbackRate,該方法接收1個數字參數,表示增減播放速度,_playbackRate代碼如下:

        _playbackRate: function (rate) {
            this.video.get(0).playbackRate += rate;
        }

playbackRate屬性表示視頻的播放速度,默認值為1,數值越小播放速度越慢,反之亦然。

3.3.4 處理帶字幕的視頻

本例將給讀者介紹的是在HTML 5視頻中添加字幕。聽起來這像是一項非常復雜的工作,不過HTML 5已經將字幕文件進行抽象獨立,同時非常簡單的就能在任意視頻中添加字幕。本節示例不能直接用瀏覽器打開文件,否則Chrome下會報出“Cross-origin text track load denied by Cross-Origin Resource Sharing policy.”的錯誤信息,表示字幕文件加載違反了跨域資源共享策略。所以,需要將文件部署在Web服務器上,如Apache、Nginx、IIS等。

部署完畢后,用Chrome打開對應網址,點擊屏幕中央的三角播放按鈕,視頻的下方出現字幕,效果如圖3.10所示。

圖3.10 點擊播放按鈕,視頻下方出現字幕

本例的代碼構建在“3-7.處理帶字幕的視頻.html”的基礎上,沒有額外的腳本改動。在HTML中增加字幕結構,代碼如下:

        <video width="480" height="320" controls poster="../images/BigBuck.png"
    preload="none">
            <source src="../res/BigBuck.webm" type="video/mp4">
            <track label="English subtitles" kind="captions" srclang="en"
    src="../res/BigBuck.vtt" default>
        </vidde>

track標簽為視頻規定外部文本軌道,標簽帶有多種新屬性,具體如下:

● default:表示該軌道是默認的。

● kind:表示軌道文本類型,如:captions、chapters、descriptions、metadata、subtitles。

● label:軌道的標簽或標題。

● src:軌道的URL。

● srclang:軌道的語言,若kind屬性值是“subtitle”,則該屬性是必需的。

本例track標簽的軌道文件為1個WebVTT文件。WebVTT文件是一個簡單的純文本,打開“../res/BigBuck.vtt”,代碼如下:

        WEBVTT                                                      // 文本軌道文件開頭,必填
        00:00.000--> 00:01.000
        <c>字幕出現---1</c>                             // 表示可以帶CSS的文本
        00:01.000--> 00:02.000
        <i>字幕出現---2</i>                             // 斜體文本
        00:02.000--> 00:03.000
        <b>字幕出現---3</b>                             // 粗體文本
        00:03.000--> 00:04.000
        <u>字幕出現---4</u>                             // 帶下劃線文本
        00:04.000--> 00:05.000
        <v.loud>字幕出現---5                                  // 聲音文本加樣式
        00:05.000--> 00:06.000
        <v Man>字幕出現---6                                   // 聲音文本加人物名

在WebVTT文本中,所有c標簽都可以帶CSS樣式,比如<c.demoClass>。還有一種v標簽,也可以帶樣式,同時還可以加入人名。本例給v標簽加上2種樣式類,如下代碼所示:

        ::cue(.loud) { font-size: 2em; color:Red; }
        ::cue(v[voice="Man"]) { color: green }

該類聲音文本樣式需要以字符串“::cue”開頭,cue表示指定文本和視頻文件中字幕的時間定位。小括號中間的內容如同CSS,表示選擇器的名稱。其中的“.load”如同一般CSS,表示文本中的樣式類。其中,“v[voice="Man"]”表示對應人物音軌文字的樣式類。

提示

WebVTT還有更多更奇怪的設置,詳情可以參考網址http://dev.w3.org/html5/webvtt/

主站蜘蛛池模板: 寿宁县| 鲁山县| 泽库县| 景德镇市| 报价| 馆陶县| 马龙县| 呼伦贝尔市| 柳江县| 安阳县| 黔东| 恩平市| 乌拉特中旗| 长岭县| 赤壁市| 科技| 扬中市| 育儿| 黄浦区| 江门市| 攀枝花市| 夹江县| 桐乡市| 惠东县| 灵石县| 香港 | 嵊州市| 石家庄市| 大庆市| 江孜县| 河源市| 杂多县| 紫金县| 方城县| 将乐县| 盐城市| 平谷区| 鄂尔多斯市| 北京市| 兴宁市| 岫岩|