Video.js 指南

这些指南涵盖了 Video.js 用户的各种主题

组件

注意:本指南侧重于 Video.js 8+ 版本。它不再提及已在 8.0 版本中移除的 videojs.extend() 方法。请参阅我们的迁移指南获取更多信息!

Video.js 播放器的架构以组件为中心。

Player 类以及所有表示播放器控件和其他 UI 元素的类都继承自 Component 类。这种架构使得以镜像 DOM 的树状结构构建 Video.js 播放器的用户界面变得容易。

什么是组件?

组件是一个 JavaScript 对象,具有以下特点:

  • 在几乎所有情况下都关联一个 DOM 元素。
  • 与一个 Player 对象关联。
  • 能够管理任意数量的子组件。
  • 能够监听和触发事件。
  • 具有初始化和销毁的生命周期。

有关组件编程接口的更多详细信息,请参阅组件 API 文档

添加组件

可以使用 new Component() 创建组件实例。

// Creating an instance of a button
var player = videojs('some-video-id');
var Button = videojs.getComponent('Button');
var button = new Button(player, {
  clickHandler: function(event) {
    videojs.log('Clicked');
  }
});

console.log(button.el());

上述代码将输出:

<button class="vjs-control vjs-button" type="button" aria-disabled="false">
  <span class="vjs-icon-placeholder" aria-hidden="true"></span>
  <span class="vjs-control-text" aria-live="polite"></span>
</button>

请注意,这创建了按钮,但并未将其添加到 DOM 中。将其作为组件的子项添加将使其显示在 DOM 中。

player.getChild('ControlBar').addChild(button);

或者,通过将组件名称传递给 addChild,可以一步创建并添加组件的新实例。

// Creating an instance of a button and addingit to the player's control bar
var player = videojs('some-video-id');
var button = player.getChild('ControlBar').addChild('button', {
  clickHandler: function(event) {
    videojs.log('Clicked');
  }
});

console.log(button.el());
// will have the same html result as the previous example

按钮应包含文本。默认按钮不显示其文本,但它存在用于屏幕阅读器,并由浏览器显示为工具提示。按钮的文本可以设置为选项:

const myButton = player.getChild('ControlBar').addChild('button', {controlText: 'My button'});

要显示控件文本,请将 vjs-visibile-text 类添加到按钮。

const myButton = player.getChild('ControlBar').addChild('button', {
  controlText: 'My button',
  className: 'vjs-visible-text'
});

类和控件文本也可以在按钮创建后设置。

myButton.controlText('My button');
myButton.addClass('vjs-visible-text');

当播放器上启用experimentalSvgIcons 选项时,可以使用 setIcon 方法在任何 Component 上添加或替换图标。

您可以将 sandbox/svg-icons.html.example 重命名为 sandbox/svg-icons.html,然后使用 npm run build 构建 Video.js,并在您选择的浏览器中打开 sandbox/svg-icons.html,从而查看所有可用图标。

myButton.setIcon('play');

创建组件

Video.js 组件是 ES6 类,可以使用类语法进行扩展并向 Video.js 注册,以便为播放器添加新功能和 UI。

有几个用于创建和注册组件的函数:

  • videojs.getComponent(String name):从 Video.js 中检索组件类。
  • videojs.registerComponent(String name, Function Comp):向 Video.js 注册组件类。

此示例创建了一个标题栏组件,作为扩展 Component 的类。

// Get the Component base class from Video.js
const Component = videojs.getComponent('Component');

class TitleBar extends Component {

  // The constructor of a component receives two arguments: the
  // player it will be associated with and an object of options.
  constructor(player, options = {}) {

    // It is important to invoke the superclass before anything else, 
    // to get all the features of components out of the box!
    super(player, options);

    // If a `text` option was passed in, update the text content of 
    // the component.
    if (options.text) {
      this.updateTextContent(options.text);
    }
  }

  // The `createEl` function of a component creates its DOM element.
  createEl() {
    return videojs.dom.createEl('div', {

      // Prefixing classes of elements within a player with "vjs-" 
      // is a convention used in Video.js.
      className: 'vjs-title-bar'
    });
  }

  // This function could be called at any time to update the text 
  // contents of the component.
  updateTextContent(text) {

    // If no text was provided, default to "Title Unknown"
    if (typeof text !== 'string') {
      text = 'Title Unknown';
    }

    // Use Video.js utility DOM methods to manipulate the content
    // of the component's element.
    videojs.emptyEl(this.el());
    videojs.appendContent(this.el(), text);
  }
}

请注意,由于 extend() 函数已被移除,在转译为 ES5 时扩展组件需要使用以下语法。

// My ES5 constructor function extending Component
function MyComponent(arguments) {
  Component.call(this, arguments);
}

MyComponent.prototype = Object.create(Component.prototype);

组件创建后,可以注册并在播放器中使用。

// Register the component with Video.js, so it can be used in players.
videojs.registerComponent('TitleBar', TitleBar);

// Create a player.
var player = videojs('my-player');

// Add the TitleBar as a child of the player and provide it some text 
// in its options.
player.addChild('TitleBar', {text: 'The Title of The Video!'});

实时示例位于此 JSBin 中。

组件子项

再次,请参阅组件 API 文档以获取有关管理组件结构的完整详细信息。

基本示例

当子组件添加到父组件时,Video.js 会将子组件的元素插入到父组件的元素中。例如,添加一个组件像这样:

// Add a "BigPlayButton" component to the player. Its element will be appended to the player's element.
player.addChild('BigPlayButton');

结果是 DOM 看起来像这样:

<!-- Player Element -->
<div class="video-js">
  <!-- BigPlayButton Element -->
  <div class="vjs-big-play-button"></div>
</div>

相反,移除子组件将从 DOM 中移除子组件的元素。

player.removeChild('BigPlayButton');

结果是 DOM 看起来像这样:

<!-- Player Element -->
<div class="video-js">
</div>

使用选项

为子构造函数及其子项传递选项。

var player = videojs('some-vid-id');
var Component = videojs.getComponent('Component');
var myComponent = new Component(player);
var myButton = myComponent.addChild('MyButton', {
  text: 'Press Me',
  buttonChildExample: {
    buttonChildOption: true
  }
});

在组件初始化时,也可以通过选项添加子项。

注意:如果两个相同类型但需要不同选项的子组件,请包含一个 'name' 键。

// MyComponent is from the above example
var myComp = new MyComponent(player, {
  children: ['button', {
    name: 'button',
    someOtherOption: true
  }, {
    name: 'button',
    someOtherOption: false
  }]
});

事件监听

使用 on

var player = videojs('some-player-id');
var Component = videojs.getComponent('Component');
var myComponent = new Component(player);
var myFunc = function() {
  var myComponent = this;
  console.log('myFunc called');
};

myComponent.on('eventType', myFunc);
myComponent.trigger('eventType');
// logs 'myFunc called'

除非绑定,否则 myFunc 的上下文将是 myComponent。您可以向另一个元素或组件添加监听器。

var otherComponent = new Component(player);

// myComponent/myFunc is from the above example
myComponent.on(otherComponent.el(), 'eventName', myFunc);
myComponent.on(otherComponent, 'eventName', myFunc);

otherComponent.trigger('eventName');
// logs 'myFunc called' twice

使用 off

var player = videojs('some-player-id');
var Component = videojs.getComponent('Component');
var myComponent = new Component(player);
var myFunc = function() {
  var myComponent = this;
  console.log('myFunc called');
};
myComponent.on('eventType', myFunc);
myComponent.trigger('eventType');
// logs 'myFunc called'

myComponent.off('eventType', myFunc);
myComponent.trigger('eventType');
// does nothing

如果排除了 myFunc,则该事件类型的所有监听器都将被移除。如果排除了 eventType,则组件的所有监听器都将被移除。您可以使用 off 来移除使用以下方法添加到其他元素或组件的监听器:

myComponent.on(otherComponent...

在这种情况下,事件类型和监听器函数都是必需的

var otherComponent = new Component(player);

// myComponent/myFunc is from the above example
myComponent.on(otherComponent.el(), 'eventName', myFunc);
myComponent.on(otherComponent, 'eventName', myFunc);

otherComponent.trigger('eventName');
// logs 'myFunc called' twice
myComponent.off(otherComponent.el(), 'eventName', myFunc);
myComponent.off(otherComponent, 'eventName', myFunc);
otherComponent.trigger('eventName');
// does nothing

使用 one

var player = videojs('some-player-id');
var Component = videojs.getComponent('Component');
var myComponent = new Component(player);
var myFunc = function() {
  var myComponent = this;
  console.log('myFunc called');
};
myComponent.one('eventName', myFunc);
myComponent.trigger('eventName');
// logs 'myFunc called'

myComponent.trigger('eventName');
// does nothing

您还可以向另一个元素或组件添加一个只触发一次的监听器。

var otherComponent = new Component(player);

// myComponent/myFunc is from the above example
myComponent.one(otherComponent.el(), 'eventName', myFunc);
myComponent.one(otherComponent, 'eventName', myFunc);

otherComponent.trigger('eventName');
// logs 'myFunc called' twice

otherComponent.trigger('eventName');
// does nothing

使用 trigger

var player = videojs('some-player-id');
var Component = videojs.getComponent('Component');
var myComponent = new Component(player);
var myFunc = function(data) {
  var myComponent = this;
  console.log('myFunc called');
  console.log(data);
};
myComponent.one('eventName', myFunc);
myComponent.trigger('eventName');
// logs 'myFunc called' and 'undefined'

myComponent.trigger({'type':'eventName'});
// logs 'myFunc called' and 'undefined'

myComponent.trigger('eventName', {data: 'some data'});
// logs 'myFunc called' and "{data: 'some data'}"

myComponent.trigger({'type':'eventName'}, {data: 'some data'});
// logs 'myFunc called' and "{data: 'some data'}"

默认组件树

Video.js 播放器的默认组件结构如下所示:

Player
├── MediaLoader (has no DOM element)
├── PosterImage
├── TextTrackDisplay
├── LoadingSpinner
├── BigPlayButton
├── LiveTracker (has no DOM element)
├─┬ ControlBar
│ ├── PlayToggle
│ ├── VolumePanel
│ ├── CurrentTimeDisplay (hidden by default)
│ ├── TimeDivider (hidden by default)
│ ├── DurationDisplay (hidden by default)
│ ├─┬ ProgressControl (hidden during live playback, except when liveui: true)
│ │ └─┬ SeekBar
│ │   ├── LoadProgressBar
│ │   ├── MouseTimeDisplay
│ │   └── PlayProgressBar
│ ├── LiveDisplay (hidden during VOD playback)
│ ├── SeekToLive (hidden during VOD playback)
│ ├── RemainingTimeDisplay
│ ├── CustomControlSpacer (has no UI)
│ ├── PlaybackRateMenuButton (hidden, unless playback tech supports rate changes)
│ ├── ChaptersButton (hidden, unless there are relevant tracks)
│ ├── DescriptionsButton (hidden, unless there are relevant tracks)
│ ├── SubsCapsButton (hidden, unless there are relevant tracks)
│ ├── AudioTrackButton (hidden, unless there are relevant tracks)
│ ├── PictureInPictureToggle
│ └── FullscreenToggle
├── ErrorDisplay (hidden, until there is an error)
├── TextTrackSettings
└── ResizeManager (hidden)

特定组件详情

播放切换按钮

PlayToggle 有一个选项 replay,可以显示或隐藏重播图标。默认行为是在视频播放结束后显示重播图标,通过传递 {replay: false} 可以进行设置。

隐藏重播图标的示例:

let player = videojs('myplayer', {
  controlBar: {
    playToggle: {
      replay: false
    }
  }
});

音量面板

VolumePanel 包含 MuteToggleVolumeControl 组件,如果不支持音量更改,它们将被隐藏。VolumePanel 有一个重要的选项,可以让您的 VolumeControl 垂直显示在 MuteToggle 上方。默认行为是水平的 VolumeControl{inline: true}),通过将 VolumePanel 传递 {inline: false} 可以进行设置。

垂直 VolumeControl 的示例:

let player = videojs('myplayer', {
  controlBar: {
    volumePanel: {
      inline: false
    }
  }
});

文本轨道设置

文本轨道设置组件仅在使用模拟文本轨道时可用。

尺寸管理器

这个新组件负责在播放器尺寸改变时触发一个 playerresize 事件。如果 ResizeObserver 可用或提供了 polyfill,它将使用 ResizeObserver。当使用 ResizeObserver 时,它没有元素。如果 ResizeObserver 不可用,它将回退到 iframe 元素并通过去抖动处理程序监听其尺寸改变事件。

可以像这样传入 ResizeObserver polyfill:

var player = videojs('myplayer', {
  resizeManager: {
    ResizeObserver: ResizeObserverPoylfill
  }
});

要强制使用 iframe 回退,请将 null 作为 ResizeObserver 传入。

var player = videojs('myplayer', {
  resizeManager: {
    ResizeObserver: null
  }
});

ResizeManager 也可以像这样禁用:

var player = videojs('myplayer', {
  resizeManager: false
});