Wenn Sie Video.js schon eine Weile verwenden, sind Sie wahrscheinlich mit dem Konzept der Plugins vertraut: Funktionen, die zu Methoden eines von Ihnen erstellten Players werden. Wenn Sie mit Video.js-Plugins nicht vertraut sind, finden Sie hier eine umfassende Anleitung zu Plugins.
Diese Plugins, die wir als Basis-Pluginsbezeichnen , sindleichtgewichtig und bieten vollständige Kontrolle über den Player. Das ist wirklich nützlich und wird sich nicht ändern.
Aber was ist, wenn Sie eine größere Anzahl von Funktionen wünschen? Oder mehr Anleitungen für die Strukturierung Ihres Plugins? Oder mehr Tools, die Sie bei der Verwaltung komplexer Plugin-reicher Player unterstützen?
Nun, bis Video.js 6.0 mussten Sie die Dinge selbst in die Hand nehmen.
Einführung in erweiterte Plugins
Eine der Stärken von Video.js ist sein reichhaltiges Ökosystem an Plugins. Daher wollten wir in den letzten Monaten unsere Bemühungen auf die Verbesserung der Erfahrung der Plugin-Autoren konzentrieren.
Während Projekte wie der Plugin-Generator die Erstellung von Plugins einfacher denn je machen, hielt es das Video.js-Team für wichtig, eine grundlegende API und eine Reihe von Konventionen bereitzustellen, auf denen die Zukunft der Video.js-Plugins aufgebaut werden kann.
Unsere Lösung sind fortschrittliche Plugins.
Erweiterte Plugins sind komponentenähnlich
Eines der Designziele für erweiterte Plugins war die Bereitstellung einer API, die an das bestehende Komponentensystem erinnert. Dies haben wir auf verschiedene Weise erreicht.
Auf der untersten Ebene beinhaltete dies eine Namensänderung für die Plugin-Registrierungsfunktion von videojs.plugin
zu videojs.registerPlugin
(in Anlehnung an die Namensgebung von videojs.registerComponent
und videojs.registerTech
).
Abgesehen von einer einfachen Änderung des Namens der Registrierungsmethode, sind erweiterte Plugins klassenbasiert. Ein triviales Beispiel für ein erweitertes Plugin könnte etwa so aussehen:
var Plugin = videojs.getPlugin('plugin');
var HelloWorld = videojs.extend(Plugin, {
constructor(player) {
Plugin.call(this, player);
this.player.addClass('hello-world');
}
});
videojs.registerPlugin('helloWorld', HelloWorld);
Wenn Sie einen ES6-Transpiler verwenden, können Sie ES6-Klassen auf ähnliche Weise nutzen.
Dieses Plugin kann auf die gleiche Weise wie ein Basis-Plugin initialisiert werden - über eine Player-Methode, deren Name dem registrierten Namen des Plugins entspricht.
Im Falle von fortgeschrittenen Plugins ist diese Methode eine Fabrikfunktion, die die Plugin-Klasse instanziiert und eine Instanz zurückgibt.
Es ist nützlich zu wissen, dass die erstellte Playermethode immer eine Funktion ist. Wenn ein Player bereits über eine Instanz eines erweiterten Plugins verfügt, gibt die zugehörige Methode einfach die bereits vorhandene Instanz zurück, anstatt sie neu zu initialisieren:
var player = videojs('my-player');
var instance = player.helloWorld();
// Logs: 'true'
videojs.log(instance === player.helloWorld());
Die helloWorld
Methode wird dieses Plugin-Objekt zurückgeben, bis es entsorgt wird - danach wird wieder eine neue Plugin-Instanz erstellt.
Veranstaltungen
Ähnlich wie bei Komponenten können fortgeschrittene Plugins auf Ereignisse hören und diese über die on
, one
, off
und trigger
Methoden.
Dies bietet einen lose gekoppelten Kommunikationskanal für Plugins und andere Objekte (Komponenten, Player usw.), um ihren eigenen Zustand zu verwalten und auf Änderungen des Zustands der anderen zu reagieren.
Zusätzliche Ereignisdaten
Das Video.js-Ereignissystem ermöglicht die Übergabe zusätzlicher Daten an Zuhörer als zweites Argument beim Auslösen von Ereignissen (das erste Argument ist das Ereignisobjekt selbst).
Plugin-Ereignisse übergeben einen konsistenten Satz von Eigenschaften in diesem Objekt (einschließlich aller benutzerdefinierten Eigenschaften, die an trigger
):
instance
: Die Plugin-Instanz, die das Ereignis ausgelöst hat.name
: Der Name des Plugins als String (z.B.'helloWorld'
).plugin
: Die Plugin-Klasse/Konstruktorfunktion (z. B.HelloWorld
).
Zum Beispiel kann ein Listener für ein Ereignis auf einem Plugin etwas wie dieses erwarten:
var player = videojs('my-player');
var instance = player.helloWorld();
instance.on('some-custom-event', function(e, data) {
videojs.log(data.instance === instance); // true
videojs.log(data.name === 'helloWorld'); // true
videojs.log(data.plugin === videojs.getPlugin('helloWorld')); // true
videojs.log(data.foo); // "bar"
});
instance.trigger('some-custom-event', {foo: 'bar'});
Lebenszyklus
Eine weitere Ähnlichkeit zwischen Plugins und Komponenten ist das Konzept des Lebenszyklus - genauer gesagt, die Prozesse des Auf- und Abbaus.
Wir erhalten die Einrichtungsfunktion als Nebeneffekt der normalen Objekterzeugung in JavaScript, aber wir sind auf uns selbst gestellt, wenn es um die Objektzerstörung geht und darum, sicherzustellen, dass Verweise zwischen Objekten bereinigt werden, um Speicherlecks zu vermeiden.
Video.js-Komponenten haben seit langem eine dispose
Methode und Ereignis, die sich mit dem Entfernen einer Komponente aus dem DOM und dem Speicher befassen. Erweiterte Plugins haben die gleiche Funktion:
var player = videojs('my-player');
var firstInstance = player.helloWorld();
// Logs: 'true'
videojs.log(firstInstance === player.helloWorld());
firstInstance.on('dispose', function() {
videojs.log('disposing a helloWorld instance');
});
// Logs: 'disposing a helloWorld instance'
firstInstance.dispose();
var secondInstance = player.helloWorld();
// Logs: 'false'
videojs.log(firstInstance === secondInstance);
Die pluginsetup
Veranstaltung
Plugins haben eine Lebenszyklusfunktion, die Komponenten nicht haben: die pluginsetup
Veranstaltung.
Dieses Ereignis wird bei einem Player ausgelöst, wenn ein Plugin für ihn initialisiert wird:
var player = videojs('my-player');
player.on('pluginsetup', function(e, hash) {
if (hash.name === 'helloWorld') {
videojs.log('A helloWorld instance was created!');
}
});
// Logs: 'A helloWorld instance was created!'
player.helloWorld();
React-inspirierte Statefulness
Eine der aufregenden Neuerungen in Video.js, sowohl für fortgeschrittene Plugins als auch für Komponenten, ist die von React inspirierte Statefulness. Im Wesentlichen bedeutet dies, dass alle Plugin-Objekte und Komponenten-Objekte eine state
Eigenschaft, die ein einfaches Objekt ist, das zum Speichern des variablen Zustands für dieses Objekt verwendet werden kann. Dann gibt es eine setState
Methode, die dieses Objekt aktualisiert und eine statechanged
Veranstaltung.
Dieses System ermöglicht es Plugins und Komponenten, ihre ereignisgesteuerte Natur zu nutzen, um In-Memory-Zustandsänderungen über eine einheitliche API zu kommunizieren:
// A static property of the constructor can be used to pre-populate state
// for all instances.
HelloWorld.defaultState = {color: 'red'};
var player = videojs('my-player');
var instance = player.helloWorld();
instance.on('statechanged', function(e) {
var color = e.changes.color;
if (color) {
videojs.log('The helloWorld color changed from "' + color.from + '" to "' + color.from + '"!');
}
});
// Logs: 'The helloWorld color changed from "red" to "blue"!'
instance.setState({color: 'blue'});
Player-Plugin-Bewusstsein
Schließlich konnten wir keine neue Plugin-Infrastruktur hinzufügen, ohne eines der schwerwiegendsten Probleme bei der Verwaltung komplexer Plugin-Kombinationen zu lösen: Der Player kann nicht melden, welche Plugins er initialisiert hat - oder nicht. Zu diesem Zweck verfügt der Player über zwei neue Methoden: hasPlugin
und usingPlugin
. Diese Methoden funktionieren für beide Arten von Plugins.
Die hasPlugin
Methode
Diese Methode meldet, ob ein Plugin, das einem bestimmten Namen entspricht, auf dem Player verfügbar ist:
var player = videojs('my-player');
// Logs: 'true'
videojs.log(player.hasPlugin('helloWorld'));
// Logs: 'false'
videojs.log(player.hasPlugin('fooBar'));
Diese Methode ignoriert, ob das Plugin initialisiert wurde oder nicht, und meldet lediglich, ob es registriert wurde oder nicht.
Die usingPlugin
Methode
Diese Methode meldet nicht nur, ob ein Plugin auf einem Player verfügbar ist, sondern auch, ob es derzeit auf dem Player aktiv ist:
var player = videojs('my-player');
// Logs: 'false'
videojs.log(player.usingPlugin('helloWorld'));
player.helloWorld();
// Logs: 'true'
videojs.log(player.usingPlugin('helloWorld'));
Eine Einschränkung: Während dies für beide Arten von Plugins funktioniert, können nur fortgeschrittene Plugins diesen Wert mehr als einmal ändern. Ein einfaches Plugin hat keinen eingebauten Lebenszyklus oder Ereignisse, so dass es nicht möglich ist, festzustellen, ob es "entsorgt" wurde.
Weitermachen und codieren
Wir hoffen, dass diese Ergänzungen und Verbesserungen der Plugin-Architektur das Schreiben von Video.js-Plugins angenehmer machen und einen Teil der Low-Level-Arbeit abnehmen, die nötig ist, um sicherzustellen, dass Plugins keine Speicherlecks oder andere Probleme verursachen.
Das Design der fortgeschrittenen Plugins ist so angelegt, dass wir mit der Reife von 6.0 und dem Feedback der Community weitere Funktionen hinzufügen können. Wie immer ermutigen wir unsere Nutzer, dem Video.js-Projekt auf jede erdenkliche Weise zu helfen.
Dieser Artikel wurde ursprünglich im Video.js-Blog veröffentlicht.