videojs创建control-bar组件,实现点击播放下一视频

引言

上一篇文章:为videojs添加自定义组件 已经介绍了在开源网页视频播放器videojs中添加简单的titleBar组件.
在实际使用中,我们可以发现,在大部分视频网站,都有点击播放下一集和自动连续播放两个选项.这篇文章将通过这两个功能的开发,介绍如何开发control-bar中的组件.

实现Control-Bar中的组件

编写play-next类

这次我们要实现的两个功能都在control-bar上,所以我们在control-bar目录下创建play-next文件.
playNext类中,主要handleClick函数,实现对按钮点击的监听,每当用户点击时,切换到下一个视频资源.
这里的实现方法是通过将player中的资源数组进行循环切换,然后使用资源重新加载方法更换当前播放的资源.

  handleClick(event) {
    console.log('play-next click');
    console.log(this.player_.options_.sources);
    let theSrc = this.player_.options_.sources[0];
    
    // 资源数组长度
    const len = this.player_.options_.sources.length;
    // 更新资源数组
    for (let i = 1; i < len; i++) {
      this.player_.options_.sources[i - 1] = this.player_.options_.sources[i];
    }
    this.player_.options_.sources[len - 1] = theSrc;
    // 获取下一个资源
    theSrc = this.player_.options_.sources[0];
    this.player_.pause();
    // 重载资源
    this.player_.src(theSrc);
    this.player_.load();
    this.player_.play();
  }

其次实现buildCSSClass函数,这里使用video自带的图标

  /**
   * Builds the default DOM `className`.
   *
   * @return {string}
   *         The DOM `className` for this object.
   */
  buildCSSClass() {
    return 'vjs-icon-next-item';
  }

完整类代码如下

import Button from '../button.js';
import Component from '../component.js';
import console from 'global/console';

/**
 * Button to play the next video
 *
 * @extends Button
 */
class PlayNext extends Button {

  /**
   * Creates an instance of this class.
   *
   * @param {Player} player
   *        The `Player` that this class should be attached to.
   *
   * @param {Object} [options={}]
   *        The key/value store of player options.
   */
  constructor(player, options = {}) {
    super(player, options);

    // show or hide replay icon
    options.replay = options.replay === undefined || options.replay;

  }

  /**
   * Builds the default DOM `className`.
   *
   * @return {string}
   *         The DOM `className` for this object.
   */
  buildCSSClass() {
    return 'vjs-icon-next-item';
  }

  /**
   * This gets called when an `PlayNext` is "clicked". See
   * {@link ClickableComponent} for more detailed information on what a click can be.
   *
   * @param {EventTarget~Event} [event]
   *        The `keydown`, `tap`, or `click` event that caused this function to be
   *        called.
   *
   * @listens tap
   * @listens click
   */
  handleClick(event) {
    console.log('play-next click');
    console.log(this.player_.options_.sources);
    let theSrc = this.player_.options_.sources[0];
    
    // 资源数组长度
    const len = this.player_.options_.sources.length;
    // 更新资源数组
    for (let i = 1; i < len; i++) {
      this.player_.options_.sources[i - 1] = this.player_.options_.sources[i];
    }
    this.player_.options_.sources[len - 1] = theSrc;
    // 获取下一个资源
    theSrc = this.player_.options_.sources[0];
    this.player_.pause();
    // 重载资源
    this.player_.src(theSrc);
    this.player_.load();
    this.player_.play();
  }

  /**
   * This gets called once after the video has ended and the user seeks so that
   * we can change the replay button back to a play button.
   *
   * @param {EventTarget~Event} [event]
   *        The event that caused this function to run.
   *
   * @listens Player#seeked
   */
  handleSeeked(event) {
    console.log('play-next seeked');
  }

}

/**
 * The text that should display over the `PlayNext`s controls. Added for localization.
 *
 * @type {string}
 * @private
 */
PlayNext.prototype.controlText_ = 'PlayNext';
//在component中注册组件
Component.registerComponent('PlayNext', PlayNext);
export default PlayNext;

编写auto-play-next类

在control-bar目录下创建auto-play-next文件,编写自动连续播放代码.
自动连续播放按钮主要实现点击事件,当用户点击时切换连续播放状态

  handleClick(event) {
    console.log('auto-play-next click: ' + flag);
    if (flag) {
      this.addClass('autoplay-off');
      this.removeClass('autoplay-on');
      console.log('show ' + 'autoplay-off');
      this.off(this.player_, 'ended', this.handleEnded);  //解除监听事件
    } else {
      this.addClass('autoplay-on');
      this.removeClass('autoplay-off');
      console.log('show ' + 'autoplay-on'); 
      this.on(this.player_, 'ended', this.handleEnded);   //添加监听事件
    }
    flag = !flag;
  }

其次绑定监听事件,在视频播放结束时播放播放下一个视频

handleEnded(event) {
    console.log('play-next ended');
    console.log(this.player_.options_.sources);
    let theSrc = this.player_.options_.sources[0];
    const len = this.player_.options_.sources.length;

    for (let i = 1; i < len; i++) {
      this.player_.options_.sources[i - 1] = this.player_.options_.sources[i];
    }
    this.player_.options_.sources[len - 1] = theSrc;
    theSrc = this.player_.options_.sources[0];
    this.player_.pause();
    this.player_.src(theSrc);
    this.player_.load();
    this.player_.play();
  }

auto-play-next完整代码如下

import Button from '../button.js';
import Component from '../component.js';
import console from 'global/console';

let flag = true;

/**
 * Button to auto play next
 *
 * @extends Button
 */
class AutoPlayNext extends Button {

  /**
   * Creates an instance of this class.
   *
   * @param {Player} player
   *        The `Player` that this class should be attached to.
   *
   * @param {Object} [options={}]
   *        The key/value store of player options.
   */
  constructor(player, options = {}) {
    super(player, options);

    // show or hide replay icon
    options.replay = options.replay === undefined || options.replay;

    // 绑定监听器
    this.on(player, 'ended', this.handleEnded);

    flag = true;
  }

  /**
   * Builds the default DOM `className`.
   *
   * @return {string}
   *         The DOM `className` for this object.
   */
  buildCSSClass() {
    return 'autoplay-on';
  }

  /**
   * This gets called when an `autoPlaynext` is "clicked". See
   * {@link ClickableComponent} for more detailed information on what a click can be.
   *
   * @param {EventTarget~Event} [event]
   *        The `keydown`, `tap`, or `click` event that caused this function to be
   *        called.
   *
   * @listens tap
   * @listens click
   */
  handleClick(event) {
    console.log('auto-play-next click: ' + flag);
    if (flag) {
      this.addClass('autoplay-off');
      this.removeClass('autoplay-on');
      console.log('show ' + 'autoplay-off');
      this.off(this.player_, 'ended', this.handleEnded);  //解除监听事件
    } else {
      this.addClass('autoplay-on');
      this.removeClass('autoplay-off');
      console.log('show ' + 'autoplay-on'); 
      this.on(this.player_, 'ended', this.handleEnded);   //添加监听事件
    }
    flag = !flag;
  }

  /**
   * when the video is ended,play next one
   *
   * @param {EventTarget~Event} [event]
   *        The event that caused this function to run.
   *
   * @listens Player#ended
   */
  handleEnded(event) {
    console.log('play-next ended');
    console.log(this.player_.options_.sources);
    let theSrc = this.player_.options_.sources[0];
    const len = this.player_.options_.sources.length;

    for (let i = 1; i < len; i++) {
      this.player_.options_.sources[i - 1] = this.player_.options_.sources[i];
    }
    this.player_.options_.sources[len - 1] = theSrc;
    theSrc = this.player_.options_.sources[0];
    this.player_.pause();
    this.player_.src(theSrc);
    this.player_.load();
    this.player_.play();
  }
}

/**
 * The text that should display over the `PlayNext`s controls. Added for localization.
 *
 * @type {string}
 * @private
 */
AutoPlayNext.prototype.controlText_ = 'autoPlayNext';

Component.registerComponent('autoPlayNext', AutoPlayNext);
export default AutoPlayNext;

修改css样式

为css样式文件中添加auto-play-next按钮的两种状态(一种为启用时,一种为未启用时)


.video-js .autoplay-on{
  background-color:rgba(0, 0, 0, 0.4);
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABRFBMVEX///8AqBQApRQAohMAnhIAmhEAlhAAkg8AjQ4AiQ0AhAwAfQoAHQIAqRUAqhUAqhUAqhUAqBQkwTdU4GZT32QjvzYApRRT3mRP2mAAohMAnhIAmhEAlhAAkg8AjQ4AiQ0AhAwAfQoVyiUPyCAAbQYIkhIQzCAPzB8HkhAAAAAADgEASgIAXQIAXQIAAAAAAAAAAABd5W5c5G1O1l9W3mdGzlc5wUpAyFFP12A9xU4zu0T///+e4qdHz1hJ0Vo2vkcttT4wuUEmrzccpC3i4uLj4+Pn5+cVniYosTlEzFUrszz4+PgcqC0SoiMRnyLe3t7m5uYRniIRoSIbqixByVKi16nV1dXr6+sRpSIRoyIRqiIXrygww0ESriPa2toRqCIRtCIUtSUgxjERviIRrSISviMazCsRyCIRsiIR0SIRtiIR2SJwalQ3AAAAMXRSTlMAAAAAAAAAAAAAAAAADHO6zHPd+fnduvn5zMzMzMzMzMy6+flz3fn53RIzg7zMCRYaP+s52AAAAAFiS0dEAIgFHUgAAAAHdElNRQfkDAYDFSM2DmjWAAAA0UlEQVQY02NgQAeMvHz8AlDAz8fLyMAoKCRsCARGQCAiKsjIwCQmbgwHEmJMDMySJqYQYGZuaiHJzMAiZWEJBlbWNpa2UiwMrNJ29g72jk7OLq5u7h7SrAxsMp5e3j6+fv4uAYFBwTJsDOyyIaFh4RFAfmRUVLQsOwOHXExsWByQH5+QkJAox8HAKZ+UnALkpyQDQao8JwOXQlp6ekZARjoYKHAxcCsqZWZmZmWCgbIiNwOPiqpaNhSoa6jwMGhqaevoQoGOtpYmg56+ARLQ1wMAeFUzXuC3XNoAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjAtMDctMTlUMDM6Mzk6MjArMDA6MDCGZw5cAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTAxLTA4VDE2OjA2OjE1KzAwOjAwr9jbcQAAACB0RVh0c29mdHdhcmUAaHR0cHM6Ly9pbWFnZW1hZ2ljay5vcme8zx2dAAAAGHRFWHRUaHVtYjo6RG9jdW1lbnQ6OlBhZ2VzADGn/7svAAAAF3RFWHRUaHVtYjo6SW1hZ2U6OkhlaWdodAAxNh2vXm8AAAAWdEVYdFRodW1iOjpJbWFnZTo6V2lkdGgAMTblAJ7iAAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1lADE1NDY5NjM1NzVfAtNDAAAAEHRFWHRUaHVtYjo6U2l6ZQA2MDVC8ZjPjwAAAFh0RVh0VGh1bWI6OlVSSQBmaWxlOi8vL2RhdGEvd3d3cm9vdC93d3cuZWFzeWljb24ubmV0L2Nkbi1pbWcuZWFzeWljb24uY24vZmlsZXMvNTEvNTE0NzcwLnBuZ31F9QcAAAAASUVORK5CYII=');
  background-repeat: no-repeat;
  width: 20px;
  height: 22px;
  margin-top:7px;
  text-align: center;
}
.video-js .autoplay-off{
  background-color: rgba(0,0,0,0.4);
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfkDAYDFiX0QJ4gAAAAgklEQVQoz32QwQ1CMQxD7WIhIcQAiJnYgPtf4h9YFnUA9A9t2pQD58TXvFhP5vuJO+JU7NtKsm+aWFjBOzEhoyeAUYMOD4CCQRkcM3Q0qDMGiE4ZZwIY04aCTrUEOKHlDf5viB0mGnVwhTssHFRVwTmUrOL1VR7hTvAPccENCu4D3x+g7FRfDswphQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMC0wNy0xOVQwMzozOToyMCswMDowMIZnDlwAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTktMDEtMDhUMTY6MDU6NTArMDA6MDCSnUEvAAAAIHRFWHRzb2Z0d2FyZQBodHRwczovL2ltYWdlbWFnaWNrLm9yZ7zPHZ0AAAAYdEVYdFRodW1iOjpEb2N1bWVudDo6UGFnZXMAMaf/uy8AAAAXdEVYdFRodW1iOjpJbWFnZTo6SGVpZ2h0ADE2Ha9ebwAAABZ0RVh0VGh1bWI6OkltYWdlOjpXaWR0aAAxNuUAnuIAAAAZdEVYdFRodW1iOjpNaW1ldHlwZQBpbWFnZS9wbmc/slZOAAAAF3RFWHRUaHVtYjo6TVRpbWUAMTU0Njk2MzU1MB1eRU4AAAAQdEVYdFRodW1iOjpTaXplADI4MUIUhcxkAAAAWHRFWHRUaHVtYjo6VVJJAGZpbGU6Ly8vZGF0YS93d3dyb290L3d3dy5lYXN5aWNvbi5uZXQvY2RuLWltZy5lYXN5aWNvbi5jbi9maWxlcy81MS81MTM3MzYucG5nY1FLqAAAAABJRU5ErkJggg==');
  background-repeat: no-repeat;
  width: 20px;
  height: 22px;
  margin-top:7px;
  text-align: center;
}

在control-bar中配置自定义组件

想要使用自定义组件,需要在control-bar中进行配置.首先在control-bar中import对应文件
在这里插入图片描述
之后在control-bar的children数组中添加自己的组件
在这里插入图片描述

应用自定义control-bar组件

首先对项目进行重新编译,生成新的dist文件夹.
测试方法与之前的一致,编写一个简单网页,这里在player初始化中声明启用playNext和autoPlayNext组件,同时在资源数组中传入多个值
测试网页代码如下:

<!DOCTYPE html>
<html lang="en">
<head>

    <title>Video.js | HTML5 Video Player</title>
    <link href="C:\Users\KKFORKK\Desktop\example\docs\copycss.css" rel="stylesheet">
    <script src="C:\Users\KKFORKK\Desktop\example\dist\video.min.js"></script>
</head>
<body>

  <video id="example_video_1" class="video-js"  controls preload="none" width="1024" height="768" 
    poster="http://vjs.zencdn.net/v/oceans.png">
    <p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web 
      browser that <a href="https://videojs.com/html5-video-support/" target="_blank">
        supports HTML5 video</a></p>
  </video>
<script>
    var player = videojs('example_video_1', {
      inactivityTimeout: 2000,
      sourcesOrder:true,
      controls: true, // 是否显示控制条
      preload: 'auto',
      autoplay: false,
      language: 'zh-CN', // 设置语言
      muted: false, // 是否静音
      controlBar: { // 设置控制条组件
        
        /* 使用children的形式可以控制每一个控件的位置,以及显示与否 */
        children: [
          {name: 'playToggle'}, // 播放按钮
          {name: 'PlayNext'},   //点击播放下一个按钮
          {name: 'currentTimeDisplay'}, // 当前已播放时间
          {name: 'progressControl'}, // 播放进度条
          {name: 'durationDisplay'}, // 总时间
          {name: 'audioTrackButton'},
          { // 倍数播放
            name: 'playbackRateMenuButton',
            'playbackRates': [0.5, 1, 1.5, 2, 2.5]
          },
          {
            name: 'volumePanel', // 音量控制
            inline: false, // 不使用水平方式
          },
          {name: 'AutoPlayNext'},     //控制是否自动播放下一个
          {name: 'FullscreenToggle'} // 全屏

        ]
      },
        sources:[ // 视频源,这里使用了音频文件
            {
                src: 'D:/Music/Aimer - DAWN.mp3',
                type: 'audio/mp3',
                poster: '//vjs.zencdn.net/v/oceans.png',
                title: '000'
            },{
              src: 'D:/Music/Aimer - Re:far.mp3',
                type: 'audio/mp3',
                poster: '//vjs.zencdn.net/v/oceans.png',
                title: '001'
            },{
              src: 'D:/Music/Aimer - Re:pray.mp3',
                type: 'audio/mp3',
                poster: '//vjs.zencdn.net/v/oceans.png',
                title: '002'
            }
        ]
      }, function (){
        console.log('视频可以播放了',this);
      });
  </script> 
</body>

</html>

最后实现效果如下
在这里插入图片描述
可以看到我们的组件都正常启用,并且功能运行正常(样式比较丑,大家见谅)

结语

在对videojs中control-bar组件开发,主要运用js监听器以及点击事件的实现.开发的功能比较简单,更为复杂的功能可查看videojs官方提供的文档,以及对源码详细阅读实现.

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值