西瓜播放器 HTML5 video video.js 播放器 HTML5播放器 mp4 hls hls.js flv flv.js dash dash.js 无缝切换

自定义插件

西瓜视频播放器主张一切设计都是插件,小到一个播放按钮大到一项直播功能支持。想更好的自定义播放器完成自己业务的契合,理解插件机制是非常重要的;

目前有播放器有一套根据播放器生命周期定义的插件机制,内置了一系列的常用API和相关生命周期的回调,让使用这能够专注在插件本身的逻辑上,而不用太多关心插件如何在播放器中安装、卸载,以及播放器的状态相关管理

插件可配置,在实例化播放器的时候根据插件配置对插件进行实例化,并且有相关接口在播放器实例化完成之后安装相关插件,灵活多变,以下是自定义插件机制的相关说明和相关demo说明

播放器插件基类

BasePlugin

基础插件类,有除了(render)以外完整的插件生命周期,其中静态属性pluginName为必须定义的参数,将作为安装存储插件实例的时候的唯一key, 使用demo如下

// demoBasePlugin.js
import { BasePlugin, Events } from 'xgplayer'
export default class DemoBasePlugin extends BasePlugin {
  /**
   * (必须声明)插件的名称,将作为插件实例的唯一key值
   * 该参数还最为播放器上该插件的配置透传key值,例如:
   * var p = new player({
   *   demoBasePlugin: {
   *     text: '这是插件demoBasePlugin的配置信息'
   *   }
   * })
   * 在插件afterCreate之后可以通过this.config.text获取到改配置参数
   **/
  static get pluginName() {
    return 'demoBasePlugin'
  }

  static get defaultConfig () {
    return {
       text: '这是插件demoBasePlugin的默认Text'
    }
  }

  constructor (args) {
    super(args)
  }

  afterPlayerInit () {
    // TODO 播放器调用start初始化播放源之后的逻辑
  }

  afterCreate () {
    // 在afterCreate中可以加入DOM的事件监听

    this.on(Events.PLAY, () => {
      console.log('播放播放回调')
    })
  }

  destroy () {
    // 播放器销毁的时候一些逻辑
  }
}

Plugin

UI类插件基类,继承自BasePlugin,除了具有完善的生命周期回调,还内置了render以及一些dom相关API,使用demo如下:

import { Plugin } from 'xgplayer'

const { POSITIONS } = Plugin

// demoPlugin.js
export default class demoPlugin extends Plugin {
  // 插件的名称,将作为插件实例的唯一key值
  static get pluginName() {
    return 'demoPlugin'
  }

  static get defaultConfig () {
      return {
        // 挂载在controls的右侧,如果不指定则默认挂载在播放器根节点上
        position: POSITIONS.CONTROLS_RIGHT
      }
  }

  constructor (args) {
    super(args)
  }

  beforePlayerInit () {
   // TODO 播放器调用start初始化播放源之前的逻辑
  }

  afterPlayerInit () {
    // TODO 播放器调用start初始化播放源之后的逻辑
  }

  afterCreate () {
    this.icon = this.find('.icon')
    this.onIconClick = (e) => {
      console.log('class为icon元素点击回调')
    }
    this.onClick = () => {
      console.log('当前插件根节点点击事件')
    }
    // 对当前插件根节点内部类名为.icon的元素绑定click事件
    this.bind('.icon', 'click', this.onIconClick)
    // 对当前插件根节点绑定click事件
    this.bind('click', this.onClick)
    //TODO 插件实例化之后的一些逻辑
  }

  destroy () {
    this.unbind('.icon', 'click', this.onIconClick)
    this.unbind('click', this.onClick)
    this.icon = null
    // 播放器销毁的时候一些逻辑
  }

  render () {
    return `<div class="demo-plugin">这是一个dmeo插件<div class="icon"></div></div>`
  }
}

插件使用

根据配置参数将自定义插件注册到播放器上,有两种方式,一种是播放器初始化参数plugins中配置,另一种方式是播放器实例初始化完成之后,调用插件注册接口进行注册

播放器初始化配置

import Player from 'xgplayer'
import DemoBasePlugin from './demoBasePlugin.js'
import DemoPlugin from '../demoPlugin.js'

const player = new Player({
  url: '../video/mp4/xgplayer-demo-720p.mp4',
  plugins: [DemoBasePlugin],  // 配置参数注册插件
})

// 调用接口注册插件
player.registerPlugin(DemoPlugin)

关于保留配置项position

position用于指定UI插件的dom挂载位置,目前定义的位置如下图所示

默认布局image.png

flex布局image.png

  • 插件在不指定position,也不指定root参数的情况下,默认挂载在根节点root下;
  • ROOT_TOP、ROOT_RIGHT、ROOT_LEFT会在播放器失去焦点的时候自动隐藏
  • 手机小屏flex布局下,中间位置自适应,一般中间位置都是进度条

关于保留配置项index

index是一个数字,用于指定UI插件在父节点上插入的位置,数字越小,越靠前,如果这个相等则按照注册顺序插入; index可以通过配置覆盖来达到调整插件顺序的目的

插件生命周期接口

beforeCreate

插件new的时候,但是还未执行其余一系列操作的时候执行

render

继承自BasePlugin不执行该流程 UI插件渲染,非UI插件不执行,该接口支持返回一个结构的字符串,也支持返回一个dom对象,最终会挂载在root或者指定的其他dom节点上

afterCreate

插件实例创建之后回调,此时可以获取所有内置对象,例如this.player, 如果是UI插件则可以获取到当前插件的根节点,例如this.el

onPluginsReady

播放器初始化带有的的所有插件创建完成之后执行,在该流程可以获取到所有播放器上注册的插件实例,可进行插件实例之间相互依赖交互

destory

播放器destroy的之后回调,插件销毁之前执行,播放器销毁的时候,会先依次执行各个插件的destory

beforePlayerInit

播放器执行start初始化播放源之前

afterPlayerInit

播放器执行start逻辑,播放源被初始化之后

内置对象

player[只读]

播放器实例, 在插件内部可以直接通过this.player调用播放器任何API

playerConfig[只读]

播放器初始配置, 在插件内部可以直接通过this. playerConfig获取

pluginName[只读]

插件名称唯一key, 可通过this.name调用,通过注册插件的时候指定name或者插件静态属性获取

root[只读]

当前插件为UI插件,则是该UI的根节点dom, 通过this.root获取,否则为null

内置API

on (event, callback)

  • 说明: 监听播放器事件, 所有通过该API添加的监听事件在destroy的时候会默认off, 不需要再单独调用off

  • 备注:通过该API监听,播放器销毁的时候会默认接触监听,不需要额外在destroy的时候显示的解除事件监听

  • 举例:

this.on(Events.PLAY, () => {
  console.log('play')
})
// 多个事件同时监听处理
this.on([Events.ENDED, Events.PAUSE], () => {
  console.log('ended or pause')
})

once (event, callback)

  • 说明: 监听播放器事件,只监听一次

  • 备注:通过该API监听,播放器销毁的时候会默认接触监听,不需要额外在destroy的时候显示的解除事件监听

  • 举例:

this.once(Events.PLAY, () => {
  console.log('play')
})

off (event, callback)

  • 说明: 解除播放器事件监听

  • 举例:

this.off(Events.PLAY, () => {
  console.log('play')
})
// 多个事件同时监听处理
this.off([Events.ENDED, Events.PAUSE], () => {
  console.log('ended or pause')
})

offAll ()

  • 说明: 解除当前插件对播放器的所有事件监听

  • 举例:

this.offAll()

emit (event)

  • 说明: 触发自定义事件

  • 举例:

this.emit('customEvent', () => {
  console.log('customEvent')
})

plugins()

  • 说明: 返回当前插件的所有子插件实例,通过调用this.registerPlugin注册的所有子插件

  • 举例:

const childPlugins = this.plugins

getPlugin(key)

  • 说明: 根据插件key值,获取插件实例

  • 举例:

const pc = this.getPlugin('pc')

registerPlugin (Plugin, options, name)

  • 说明: 在当前插件中注册自插件,如果当前插件为UI插件
    • options或者options.root为空,插件dom结构默认挂载在当前插件根节点上;如果指定了
    • options.root为dom结构,插件dom结构默认挂载在root下
    • name不为空,插件注册之后实例以name为key值存储
    • name为空,插件注册之后实例以Plugin.pluginName返回的值为key
  • 举例:
// get pluginName() 返回值为 customplugin
import CustomPlugin from './customplugin'

/**
 * 注册之后可以根据this.getPlugin('customplugin')得到插件实例
 * 子插件dom挂载在当前插件根节点下
 */
const child1 = this.registerPlugin(CustomPlugin)

/**
 * 注册之后可以根据this.getPlugin('csplugin')得到插件实例
 * 子插件dom挂载在当前插件dom中classNamew为childdiv的dom下
 */
const child = this.registerPlugin(CustomPlugin, {
  //以className 为childdiv的div作为父节点
  root: this.find('.childdiv'),
  //插件配置信息
  config: {
    disable: false
  }, 'csplugin'});

show

  • 说明: 显示当前插件

  • 示例:

// 默认使用block
plugin.show()
// 指定show参数
plugin.show('flex')

hide

  • 说明: 隐藏当前插件

find (selector)

  • 说明: 在当前插件根节点下查找,底层使用的querySelector

  • 示例:

// 获取当前UI插件root下类名为.icon的第一个dom
this.icon = this.find('.icon')
// 获取当前UI插件root下tag为li的所有dom
this.lis = this.find('li')

bind (selector, event, handler)

  • 说明: 对符合选择器的dom添加event事件代理,对应的解除事件代理的UI为unbind,可以在destory的时候调用

  • 示例:

// 对当前UI插件根节点下的li a进行事件代理
this.bind('li a', 'click', this.clickHandler)
this.unbind('li a', 'click', this.clickHandler)

// 对当前插件根节点添加事件监听,目标元素为this.el
this.bind('click', this.clickHandler)
this.unbind('click', this.clickHandler)

// 同时对同一选择器的多个事件监听相同的事件代理
this.bind('li a', ['click', 'touched'], this.clickHandler)
this.unbind('li a', ['click', 'touched'], this.clickHandler)

unbind (selector, event, handler)

  • 说明: 对符合选择器的dom解除event事件代理,可以在destory的时候调用

  • 示例: 参考bind说明

setStyle;

  • @param { string | {[propName: string]: any} } name

  • @param { any? } value

  • 说明: 对当前UI插件的根节点设置样式

  • 示例:

// 设置单个样式
this.setStyle('height', '40px')
// 设置多个样式单位
this.setStyle({
  'height': '40px',
  'width': '40px'
})

setAttr (name, value)

  • 说明: 对当前UI插件的根节点设置属性

  • 示例:

// 设置单个样式
this.setAttr('data-url', 'https://ixigua.com')
// 设置多个样式单位
this.setAttr({
  'data-id': 1,
  'data-name': 'name'
})

setHtml (htmlStr, callback)

  • 说明: 对当前根节点重置html结构

  • 示例:

// 设置单个样式
this.setHtml(`<div class="icon">重置icon</div>`, () => {
  console.log('dom重置完成')
})

静态枚举对象列表

Plugin.POSITIONS

插件在节点中挂载的位置position的枚举值,用于指定UI插件的dom挂载位置,具体值列表如下

Plugin.POSITIONS = {
  ROOT: 'root',                     //挂载在根节点上
  ROOT_LEFT: 'rootLeft',            //挂载在播放器容器的左侧边栏
  ROOT_RIGHT: 'rootRight',          //挂载在播放器容器的右侧边栏
  ROOT_TOP: 'rootTop',              //挂载在播放器容器的顶部边栏
  CONTROLS_LEFT: 'controlsLeft',    //挂载在播放器控制栏的左侧
  CONTROLS_RIGHT: 'controlsRight',  //挂载在播放器控制栏的右侧
  CONTROLS_CENTER: 'controlsCenter' //挂载在播放器控制栏的中间控制条位置
}