点击下载教程相关资源
注意:本指南主要针对 Video.js 8+。它不再提及 videojs.extend() 方法的使用,该方法已在 8.0 中移除。有关详细信息,请参阅我们的迁移指南!
Video.js 的一大优势是其插件生态系统,它允许世界各地的作者分享他们对视频播放器的定制。这包括从最简单的用户界面调整到新的播放技术和源处理程序的所有内容!
由于我们将插件视为 Video.js 的重要组成部分,因此本组织致力于维护一套强大的插件作者工具:
用于构建 Video.js 插件项目脚手架的 Yeoman 生成器。此外,它还提供了一套关于插件作者身份的约定,只要遵循这些约定,就能使作者身份、贡献和使用变得一致且可预测。
简而言之,该生成器可让插件作者专注于编写插件,而不是摆弄工具。
如果你以前编写过 Video.js 插件,那么插件的基本概念应该不会陌生。它与 jQuery 插件类似,核心思想是为播放器添加一个方法。
基本插件就是一个普通的 JavaScript 函数:
function examplePlugin(options) { if (options.customClass) { this.addClass(options.customClass); } this.on('playing', function() { videojs.log('playback began!'); }); }
按照惯例,插件会传递一个选项对象;但实际上,你可以接受任何你想要的参数。本示例插件将添加一个自定义类(无论传入的是 options.customClass),每当播放开始,它都会向浏览器控制台记录一条信息。
注意:插件函数中的值是播放器实例;因此,您可以访问其完整的 API。
现在我们已经有了一个可以执行播放器操作的函数,剩下的就是向 Video.js 注册插件了:
videojs.registerPlugin('examplePlugin', examplePlugin);
之后,任何播放器都会自动在其原型中加入 examplePlugin 方法!
注意:插件名称的唯一规定是不能与任何现有插件或播放器方法冲突。
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Video.js</title> <!-- 引入 Video.js 样式 --> <link href="https://vjs.zencdn.net/8.10.0/video-js.css" rel="stylesheet" /> <!-- 如果您想支持 IE8(适用于 v7 之前的 Video.js 版本) --> <!-- <script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script> --> <style> .my_player_class { border: solid 3px red; } </style> </head> <body> <div id="container"> <video id="vid1" class="video-js" data-setup='{"preload":"auto","controls":true,"width":"640","height":"264px", "poster":"../resources/oceans.jpg"}'> <source src="../resources/oceans.mp4" type="video/mp4" /> <source src="../resources/oceans.webm" type="video/webm" /> </video> </div> <!-- 引入 Video.js 库 --> <script src="https://vjs.zencdn.net/8.10.0/video.min.js"></script> <script> // 1.编写插件,基本插件就是一个函数 function examplePlugin(options) { // 此处的 this 表示播放器 if (options.customClass) { this.addClass(options.customClass); } this.on('playing', function() { videojs.log('playback began!'); }); } // 2.注册插件 videojs.registerPlugin('examplePlugin', examplePlugin); // 3.创建播放器 let player = videojs('vid1'); player.examplePlugin({ customClass: "my_player_class" }); </script> </body> </html>
运行示例,如下图:
Video.js 6 引入了高级插件:这些插件与基本插件共享类似的 API,但它们基于类,并提供一系列开箱即用的额外功能。
在阅读以下章节时,您可能需要参考插件 API 文档以了解更多细节。
如果您熟悉创建组件,那么这个过程也是类似的。高级插件以 JavaScript 类开始:
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!'); }); } }
目前,这个高级插件示例的功能与上述基本插件完全相同--不用担心,我们会继续让它变得更有趣!
高级插件的注册过程与基本插件的注册过程相同。
videojs.registerPlugin('examplePlugin', ExamplePlugin);
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Video.js</title> <!-- 引入 Video.js 样式 --> <link href="https://vjs.zencdn.net/8.10.0/video-js.css" rel="stylesheet" /> <!-- 如果您想支持 IE8(适用于 v7 之前的 Video.js 版本) --> <!-- <script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script> --> <style> .my_player_class { border: solid 3px red; } </style> </head> <body> <div id="container"> <video id="vid1" class="video-js" data-setup='{"preload":"auto","controls":true,"width":"640","height":"264px", "poster":"../resources/oceans.jpg"}'> <source src="../resources/oceans.mp4" type="video/mp4" /> <source src="../resources/oceans.webm" type="video/webm" /> </video> </div> <!-- 引入 Video.js 库 --> <script src="https://vjs.zencdn.net/8.10.0/video.min.js"></script> <script> // 1.编写插件,基本插件就是一个函数 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!'); }); } } // 2.注册插件 videojs.registerPlugin('examplePlugin', ExamplePlugin); // 3.创建播放器 let player = videojs('vid1'); player.examplePlugin({ customClass: "my_player_class" }); </script> </body> </html>
运行示例,如下图:
高级插件与基本插件有两个主要区别,在介绍其高级功能之前,必须了解这两个区别。
对于基本插件,插件函数中 this 的值将是播放器。
对于高级插件,this 的值是插件类的实例。播放器作为第一个参数传递给插件构造函数(并作为播放器属性自动应用到插件实例中),之后再传递其他参数。
基本插件和高级插件都是通过调用播放器上的一个方法(例如 player.examplePlugin())来设置的,该方法的名称与插件的名称相匹配。
不过,对于高级插件来说,该方法就像一个工厂函数,对于当前播放器来说,它会被一个返回插件实例的新函数取代:
// `examplePlugin` 尚未被调用,因此它是一个工厂函数。 player.examplePlugin(); // `examplePlugin` 现在是一个函数,它返回的是上一次调用生成的实例。 player.examplePlugin().someMethodName();
对于基本插件,方法不会改变,始终是同一个函数。基本插件的作者可以自行处理对其插件函数的多次调用。
到此为止,我们的高级插件示例在功能上与基本插件示例完全相同。但是,高级插件具有大量基本插件所没有的优点。
与组件一样,高级插件也提供事件实现。这包括
使用 on 或 one 监听插件实例上的事件:
player.examplePlugin().on('example-event', function() { videojs.log('example plugin received an example-event'); });
在插件实例上触发自定义事件的功能:
player.examplePlugin().trigger('example-event');
使用 off 功能停止监听插件实例上的自定义事件:
player.examplePlugin().off('example-event');
通过提供内置事件系统,高级插件为代码结构提供了更广泛的选择,其模式为大多数网络开发人员所熟悉。
插件触发的所有事件都包含一个附加数据对象作为第二个参数。该对象有三个属性:
name:字符串形式的插件名称(例如 "examplePlugin")。
plugin: 插件构造函数(如 ExamplePlugin)。
instance(实例): 插件构造函数实例。
高级插件引入的一个新概念是状态性。这类似于 React 组件的状态属性和 setState 方法。
高级插件实例都有一个 state 属性,它是一个纯 JavaScript 对象,可以包含插件作者想要的任何键和值。
可以通过在插件构造函数中添加静态属性来提供默认状态:
ExamplePlugin.defaultState = { customClass: 'default-custom-class' };
当通过 setState 方法更新状态时,插件实例会触发一个 "statechanged "事件,但仅限于有变化的情况!该事件可用作更新 DOM 或执行其他操作的信号。传递给该事件侦听器的事件对象包括一个描述状态属性发生变化的对象:
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 方法销毁:
// 设置一个示例插件实例 player.examplePlugin(); // 之后随时销毁它 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() 等。
注意:此方法在构造函数中添加,不会覆盖插件原型中任何预定义的日志属性。
下面是一个完整的 ES6 高级插件,当播放器的状态在播放和暂停之间变化时,它会记录一条自定义信息。它使用了所述的所有高级功能:
import videojs from 'video.js'; const Plugin = videojs.getPlugin('plugin'); class Advanced extends Plugin { constructor(player, options) { super(player, options); // 每当播放器发出播放或暂停事件时,我们会在必要时更新播放器的状态。 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(); // 这将开始播放,触发 "play" 事件,更新插件状态,并记录一条信息。 player.play(); // 这将暂停播放,触发 "paused "事件,更新插件状态,并记录一条信息。 player.pause(); player.advanced().dispose(); // 这将开始播放,但插件已被废弃,因此不会记录任何信息。 player.play();
这个例子在现实中可能有点毫无意义,但它展示了高级插件比基本插件所提供的灵活性。
在播放器上设置(或初始化)插件有两种方法。这两种方法对基本插件和高级插件的作用都是一样的。
第一种方法是在创建播放器时。使用插件选项,可以在播放器上自动设置插件:
videojs('example-player', { plugins: { examplePlugin: { customClass: 'example-class' } } });
否则,可以手动设置插件:
var player = videojs('example-player'); player.examplePlugin({customClass: 'example-class'});
这两种方法在功能上完全相同,请根据自己的喜好选择!
偶尔会出现这样的用例,即某些代码需要等待插件初始化。从 Video.js 6 开始,这可以通过监听播放器上的插件设置事件来实现。
对于任何给定的插件初始化,都有四个事件需要注意:
beforepluginsetup: 在任何插件初始化之前触发。
beforepluginsetup:examplePlugin 在 examplePlugin 初始化前触发。
pluginsetup:在任何插件初始化后触发。
pluginsetup:examplePlugin: 在 examplePlugin 插件初始化后触发。
这些事件对基本插件和高级插件都有效。它们在播放器上触发,每个事件都包含一个额外事件数据对象,作为其监听器的第二个参数。
Player API 播放器 API
Plugin API 插件 API
Plugin Generator 插件生成器
Plugin Conventions 插件约定