plugins(插件)

Video.js插件

Video.js的强大功能之一是其插件生态系统,该插件生态系统使来自世界各地的作者可以共享其视频播放器自定义设置。这包括从最简单的UI调整到新的播放技术和源处理程序的所有内容

由于我们将插件视为Video.js的重要组成部分,因此该组织致力于维护一套强大的插件创作工具:

generator-videojs-plugin

一个Yeoman生成器,用于搭建Video.js插件项目。此外,它为插件的作者提供了一套约定,如果遵循,可使作者,贡献和使用保持一致且可预测。

简而言之,生成器让插件作者专注于编写插件——而不是把工具弄得一团糟。


编写基本插件

如果您以前编写过Video.js插件,则应该熟悉基本的插件概念。它类似于jQuery插件,其核心思想是向播放器添加方法。


编写JavaScript函数

一个基本的插件是一个普通的JavaScript函数:

function examplePlugin(options) {

  if (options.customClass) {
    this.addClass(options.customClass);
  }

  this.on('playing', function() {
    videojs.log('playback began!');
  });
}

按照惯例,插件被传递一个options对象;但是,您可以实际地接受您想要的任何参数。这个示例插件将添加一个自定义类(作为options.customClass传入的任何类),并且每当播放开始时,它将一条消息记录到浏览器控制台。

注意:this在插件的功能是播放器实例; 因此,您可以访问其完整的API


注册基本插件

现在我们有了一个函数,可以对播放器做一些事情,剩下的就是用Video.js注册插件:

videojs.registerPlugin('examplePlugin', examplePlugin);
之后,任何播放器都会在其原型上自动具有一个examplePlugin方法!

注意:插件名称的规定是唯一的,它不能与任何现有的插件或播放器方法冲突。


编写高级插件

Video.js 6引入了高级插件:这些插件与基本插件共享相似的API,但是基于类,并提供了一系列额外的功能。

阅读以下各节时,您可能需要参考Plugin API文档以获取更多详细信息。

编写一个JavaScript类/构造函数

如果您熟悉创建组件,则此过程类似。高级插件以JavaScript类(也称为构造函数)开头。

如果您已经在使用ES6,则可以将该语法与所选的翻译器/语言(Babel,TypeScript等)一起使用:

const Plugin = videojs.getPlugin('plugin');

class ExamplePlugin extends Plugin {

  constructor(player, options) {
    super(player, options);

    if (options.customClass) {
      player.addClass(options.customClass);
    }

    player.on('playing', function() {
      videojs.log('playback began!');
    });
  }
}
或使用ES5:
var Plugin = videojs.getPlugin('plugin');

var ExamplePlugin = videojs.extend(Plugin, {

  constructor: function(player, options) {
    Plugin.call(this, player, options);

    if (options.customClass) {
      player.addClass(options.customClass);
    }

    player.on('playing', function() {
      videojs.log('playback began!');
    });
  }
});
现在,这个示例高级插件的功能与上述基本插件完全相同-不用担心,随着我们的继续,我们将使其变得更加有趣!


注册高级插件

高级插件的注册过程与基本插件的注册过程相同。

videojs.registerPlugin('examplePlugin', ExamplePlugin);

注意:因为ES6类是JavaScript中现有构造函数和原型架构之上的语法,所以在所有情况下registerPlugin的第二个参数都是一个函数。


与基本插件的主要区别

高级插件与基本插件有两个主要区别,在描述其高级功能之前必须了解这些区别。

this

使用基本插件时,this插件函数中的值将为player。

对于高级插件,this是plugin类的实例。播放器作为第一个参数传递给插件构造函数(并作为player属性自动应用于插件实例),之后再传递任何其他参数。

播放器插件名称属性

基本插件和高级插件都可以通过在播放器上调用名称与插件匹配的方法(例如player.examplePlugin())来设置。

但是,对于高级插件,此方法的作用类似于工厂函数,并由返回插件实例的新函数替换为当前播放器:

// `examplePlugin` has not been called, so it is a factory function.
player.examplePlugin();

// `examplePlugin` is now a function that returns the same instance of
// `ExamplePlugin` that was generated by the previous call.
player.examplePlugin().someMethodName();
使用基本插件,方法不会改变-它始终是相同的功能。基本插件的作者可以处理对其插件函数的多次调用。


高级插件的功能

至此,我们的示例高级插件在功能上与示例基本插件相同。但是,高级插件带来了很多好处,而基本插件没有内置这些好处。

事件

像组件一样,高级插件提供事件的实现。这包括:

1、在插件实例上监听事件的能力使用onone:

player.examplePlugin().on('example-event', function() {
  videojs.log('example plugin received an example-event');
});
2、在插件实例上trigger自定义事件的能力:
player.examplePlugin().trigger('example-event');
3、可以使用以下命令停止监听插件实例上的自定义事件off
player.examplePlugin().off('example-event');
通过提供内置的事件系统,高级插件以大多数Web开发人员熟悉的模式为代码结构提供了更多选择。


额外事件数据

插件触发的所有事件都包含一个附加数据对象作为第二个参数。该对象具有三个属性:

  • name:插件名称(例如"examplePlugin")作为字符串。
  • plugin:插件的构造函数(例如ExamplePlugin)。
  • instance:插件构造函数实例。

状态

为高级插件引入的新概念是状态性。这类似于React组件的state属性和setState方法。

每个高级插件实例都有一个state属性,该属性是一个纯JavaScript对象-它可以包含插件作者想要的任何键和值。

state可以通过向插件构造函数添加静态属性来提供默认值:

ExamplePlugin.defaultState = {
  customClass: 'default-custom-class'
};
当state通过更新setState方法,插件实例触发一个"statechanged"事件,但只有当事情发生了转变!此事件可以用作更新DOM或执行某些其他操作的信号。传递给此事件的侦听器的事件对象包括一个描述该state属性发生的更改的对象:
player.examplePlugin().on('statechanged', function(e) {
  if (e.changes && e.changes.customClass) {
    this.player
      .removeClass(e.changes.customClass.from)
      .addClass(e.changes.customClass.to);
  }
});

player.examplePlugin().setState({customClass: 'another-custom-class'});

生命周期

像组件一样,高级插件也具有生命周期。可以使用工厂功能创建它们,也可以使用其dispose方法销毁它们:

// set up a example plugin instance
player.examplePlugin();

// dispose of it anytime thereafter
player.examplePlugin().dispose();

dispose方法有几个效果:

  • 在插件实例上触发"dispose"事件。
  • 清理插件实例上的所有事件侦听器,这有助于避免清理对象后触发事件引起的错误。
  • 删除插件状态和对播放器的引用,以避免内存泄漏。
  • 将播放器的命名属性(例如player.examplePlugin)恢复为原始的工厂功能,因此可以再次设置插件。
此外,如果处置了播放器,则还将触发其所有高级插件实例的处置。

版本

向插件添加版本号是通过VERSION在注册插件之前在插件上定义属性来完成的:

ExamplePlugin.VERSION = '1.0.1';

videojs.registerPlugin('examplePlugin', ExamplePlugin);

检索它使用videojs.getPluginVersion:

var version = videojs.getPluginVersion('examplePlugin');
console.log(version);  // 1.0.1
请注意,插件生成器已经负责为您添加版本号。

日志

默认情况下,每个高级插件实例都有自己的日志属性,就像videojs和Player实例一样。日志消息将以播放器ID和插件名称作为前缀:

player.examplePlugin().log('hello world!');
上面将记录以下内容:
VIDEOJS: $PLAYER_ID: examplePlugin: hello world!

log函数也将拥有默认videojs.log的所有方法/属性;例如,error()、warn()、level()等。

注意:此方法已添加到构造函数中,并且不会覆盖log插件原型的任何预定义属性。

高级示例高级插件

接下来是一个完整的ES6高级插件,当播放器的状态在播放和暂停之间变化时,该插件会记录一条自定义消息。它使用了所有已描述的高级功能:

import videojs from 'video.js';

const Plugin = videojs.getPlugin('plugin');

class Advanced extends Plugin {

  constructor(player, options) {
    super(player, options);

    // Whenever the player emits a playing or pause event, we update the
    // state if necessary.
    this.on(player, ['playing', 'pause'], this.updateState);
    this.on('statechanged', this.logState);
  }

  dispose() {
    super.dispose();
    videojs.log('the advanced plugin is being disposed');
  }

  updateState() {
    this.setState({playing: !this.player.paused()});
  }

  logState(changed) {
    videojs.log(`the player is now ${this.state.playing ? 'playing' : 'paused'}`);
  }
}

videojs.registerPlugin('advanced', Advanced);

const player = videojs('example-player');

player.advanced();

// This will begin playback, which will trigger a "playing" event, which will
// update the state of the plugin, which will cause a message to be logged.
player.play();

// This will pause playback, which will trigger a "paused" event, which will
// update the state of the plugin, which will cause a message to be logged.
player.pause();

player.advanced().dispose();

// This will begin playback, but the plugin has been disposed, so it will not
// log any messages.
player.play();
这个示例在现实中可能没有意义,但是它演示了高级插件相对于基本插件所提供的灵活性。


设置插件

有两种方法可以在播放器上设置(或初始化)插件。两种方式对于基本插件和高级插件都相同。

第一种方法是在创建播放器期间。使用该plugins选项,可以在播放器上自动设置插件:

videojs('example-player', {
  plugins: {
    examplePlugin: {
      customClass: 'example-class'
    }
  }
});
否则,可以手动设置插件:
var player = videojs('example-player');
player.examplePlugin({customClass: 'example-class'});
这两种方法在功能上是相同的-使用您喜欢的任何一种!


设置插件事件

偶尔会出现一些代码需要等待插件初始化的情况。在Video.js 6中,这可以通过监听播放器上的pluginsetup事件来实现。

对于任何给定的插件初始化,有四个事件需要注意:
  • beforepluginsetup:在任何插件初始化之前立即触发。
  • beforepluginsetup:examplePlugin在examplePlugin初始化之前立即被触发。
  • pluginsetup:在任何插件初始化后触发。
  • examplePlugin:在examplePlugin初始化后触发。

这些事件适用于基本和高级插件。它们在播放器上触发,每个包含额外事件数据的对象作为其侦听器的第二个参数。


参考资料

上一篇:player-workflows(播放器工作流程) 下一篇:react