Plugin
The design of xgplayer is based on plugin system, all of built-in components are developed as plugins, so it is really important for you to learn about the mechanism of plugin for better customizing the player.
Player privides a complete plugin mechanism based on lifecycle callbacks with a series of useful APIs, Therefore you can really focus on your own code.
It's also easy to configurate you plugin, by passing config to player.config. See examples below to learn more:
BasePlugin
BasePlugin is a class of plugin without UI rendering, so it provides full lifecycle except for render
// my-base-plugin.js
import { BasePlugin, Events } from 'xgplayer'
export default class MyBasePlugin extends BasePlugin {
/**
* (required) name and identifier of this plugin
* you can find、configure、deregister plugin by pluginName, for example:
*
* const p = new player({
* [myBasePlugin]: {
* text: 'text for plugin'
* }
* })
**/
static get pluginName() {
return 'myBasePlugin'
}
static get defaultConfig () {
return {
text: 'default text for plugin'
}
}
/**
* Before plugin initialized, cannot access to this here
* @param { { index?: number, player: object, pluginName: string, config: { [propName: string]: any }} args
*/
beforeCreate(args) {}
/**
* After plugin created, we recommand you to add event listeners here
*/
afterCreate () {
this.on(Events.PLAY, () => {
console.log(this.config.text) // 'default text for plugin'
})
}
/**
* before player starting to load
*/
beforePlayerInit () {
}
/**
* DOM of media element was created, player.video as accessable
*/
afterPlayerInit () {
}
/**
* Plugin instance destroyed
*/
destroy () {
}
}
Plugin
Plugin extends BasePlugin by adding render hook and DOM APIs
import { Plugin } from 'xgplayer'
import IconSVG from './my-icon'
const { POSITIONS } = Plugin
// myPlugin.js
export default class MyPlugin extends Plugin {
/**
* (required) name and identifier of this plugin
* you can find、configure、deregister plugin by pluginName, for example:
*
* const p = new player({
* [myPlugin]: {
* position: POSITIONS.CONTROLS_LEFT
* }
* })
**/
static get pluginName() {
return 'myPlugin'
}
static get defaultConfig () {
return {
// Which area for current plugin to mount on
position: POSITIONS.CONTROLS_RIGTH,
// Index of plugin,
index: 0,
}
}
/**
* Before plugin initialized, cannot access to this here
* @param { { index: number, player: object, pluginName: string, config: { [propName: string]: any }, root: HTMLElement, position: string}} args
*/
registerIcons () {
return {
myIcon: { icon: IconSVG, class: 'custom-icon' },
}
}
/**
* Before plugin initialized, cannot access to "this" here cause DOM and APIs not ready
* @param { { index: number, player: object, pluginName: string, config: { [propName: string]: any }, root: HTMLElement, position: string}} args
*/
beforeCreate(args) {
}
afterCreate () {
// Bind click event to icon DOM node
this.bind('.icon', 'click', this.onIconClick)
// Bind click event to root DOM node
this.bind('click', this.onClick)
}
onClick () {
console.log('root of plugin was clicked')
}
onIconClick () {
console.log('div.icon was clicked')
}
initIcons () {
const { icons } = this
this.appendChild('.icon', icons.myIcon)
}
destroy () {
this.unbind('.icon', 'click', this.onIconClick)
this.unbind('click', this.onClick)
this.icon = null
}
render () {
return `<div class="my-plugin">这是一个dmeo插件<div class="icon"></div></div>`
}
}
Use plugin
You can use plugin by pass it to player.config or invoke player.registerPlugin
import Player from 'xgplayer'
import MyBasePlugin from './my-base-plugin.js'
import MyPlugin from '../my-plugin.js'
const player = new Player({
url: '../video/mp4/xgplayer-demo-720p.mp4',
plugins: [MyBasePlugin],
})
// register plugin dynamically
player.registerPlugin(MyPlugin)
Reserved config position
Use position config to specify where the plugin should mount on
default layout
flex layout
- If position is not specified, plugin will mount on the root node;
- Position ROOT_TOP、ROOT_RIGHT、ROOT_LEFT would auto hide when player unfocused
Reserved config index
Plugins are sorted by it's index, small index indicates high priority. If there are two plugins with the same index, player would render them by register order
Lifecycle hooks
beforeCreate
Plugin is being inited, cannot access to properties in beforeCreate hook
render
Only in Plugin (not BasePlugin), DOM string or DOM node is needed as return value
afterCreate
Invoked after plugin instance created, you can access to properties in afterCreate hook, for example: this.player or this.el
onPluginsReady
All of the plugins are created, you can access to this.player.plugins[pluginName] for other plugin instances.
destory
Plugin is destroyed by player
beforePlayerInit
Before player start to load media resource
afterPlayerInit
Media resource was loaded by player
Reserved properties
player[readonly]
Player instance, for example you can pause player using this.player.pause()
playerConfig[readonly]
The same with this.player.config
pluginName[readonly]
Name and identifier of current plugin
root[readonly]
Root node of plugin, counld be accessed by this.root in plugin
Built-in API
on (event, callback)
Listen to player events
Tip: plugin would automatically remove eventlistener during plugin destroy
this.on(Events.PLAY, () => {
console.log('play')
})
// Listen to multiple events
this.on([Events.ENDED, Events.PAUSE], () => {
console.log('ended or pause')
})
once (event, callback)
Listen to player events and the callback would be triggered only once
Tip: plugin would automatically remove eventlistener during plugin destroy
this.once(Events.PLAY, () => {
console.log('play')
})
off (event, callback)
- Remove player event listener
this.off(Events.PLAY, () => {
console.log('play')
})
// Remove multi event listenning
this.off([Events.ENDED, Events.PAUSE], () => {
console.log('ended or pause')
})
offAll ()
Remove all event listeners
this.offAll()
emit (event)
emit event to player
this.emit('customEvent')
plugins
get plugin instances
const plugin = this.plugins[pluginName]
getPlugin(pluginName)
Another way to access to plugin instance
const pc = this.getPlugin('pc')
[Invalid in BasePlugin]registerPlugin (Plugin, options, name)
- Register a plugin that mount on current plugin
- If options.root is specified, new plugin would mount on options.root, or it would be mounted on root node of current plugin
- You can override identifier of new plugin by pasing name
// Assuming that CustomPlugin has the pluginName of 'customPlugin'
import CustomPlugin from './customplugin'
/**
* You can get new plugin instance by player.plugins.customPlugin
* Custom Plugin would be mounted on root node of current plugin
*/
const child1 = this.registerPlugin(CustomPlugin)
/**
* You can get new plugin instance by player.plugins.csplugin
*/
const child = this.registerPlugin(CustomPlugin, {
// specified the mount point of CustomPlugin
root: this.find('.childdiv'),
// config for CustomPlugin
config: {
text: 'custom plugin'
}, 'csplugin'});
show
Show current plugin
plugin.show()
// show with a specified css display value, default to block
plugin.show('flex')
hide
Hide plugin
find (selector)
find node within the root node, using querySelector
// find the first dom with className "icon"
this.icon = this.find('.icon')
bind (selector, event, handler)
- add event listeners to DOM node within root node of plugin, note that you need to remove listeners manually by unbind API
this.bind('li a', 'click', this.clickHandler)
this.unbind('li a', 'click', this.clickHandler)
// bind event listener to root node
this.bind('click', this.clickHandler)
this.unbind('click', this.clickHandler)
// for multi events
this.bind('li a', ['click', 'touched'], this.clickHandler)
this.unbind('li a', ['click', 'touched'], this.clickHandler)
unbind (selector, event, handler)
Remove event listeners from bind API
setStyle;
@param { string | {[propName: string]: any} } name
@param { any? } value
Set style for root node of the plugin
// Set style property
this.setStyle('height', '40px')
// Set multiple style properties
this.setStyle({
'height': '40px',
'width': '40px'
})
setAttr (name, value)
Set DOM attributes for root node of the plugin
this.setAttr('data-url', 'https://ixigua.com')
// Set multiple DOM attributes
this.setAttr({
'data-id': 1,
'data-name': 'name'
})
setHtml (htmlStr, callback)
Set innerHTML for root node of the plugin
this.setHtml(`<div class="icon">newIcon</div>`)
Enum
Plugin.POSITIONS
Plugin.POSITIONS = {
ROOT: 'root', // mount on root node of the player
ROOT_LEFT: 'rootLeft', // mount on left side bar of the player
ROOT_RIGHT: 'rootRight', // mount on right side bar of the player
ROOT_TOP: 'rootTop', // mount on top bar of the player
CONTROLS_LEFT: 'controlsLeft', // mount on control bar's left of the player
CONTROLS_RIGHT: 'controlsRight', // mount on control bar's right of the player
CONTROLS_CENTER: 'controlsCenter' // mount on middle of control bar of the player
}