Skip to content

Latest commit

 

History

History
184 lines (117 loc) · 6 KB

design.md

File metadata and controls

184 lines (117 loc) · 6 KB

设计文档

背景

短视频业务兴起,web player 不可或缺,市面上已有的播放器太过"成熟",一个 SDK 中包含了大而全的功能,动辄几百 KB。

在业务相对简单时,可能还需要费劲去剔除部分功能;在开发业务定制功能时,没有一个规范而舒适的方式来开发与组织,随着业务扩展代码难以管理。

因此设计这样一个简单并且易扩展的播放器,用以支持业务从简单到复杂的演变。

名词解释

设计目标

  • 简单,对于简单的场景提供简单的解决方案,理解代码洁癖患者,同时避免不必要的维护成本
  • 易扩展,随着业务发展渐进增强

设计思路

  • HTML5 技术选型,接口、属性、行为交互等方面参考 W3C WHATWG 标准
  • 对内采用 DOM Event 作为通信机制
  • 对外采用插件机制实现依赖反转,在播放器扩展时尽可能减少各功能间的耦合

播放器设计

基本介绍

初始化参数及提供的 api

结构图及说明

如下图所示,播放器主要由以下几个模块组成:

  • Html5 处理 html5 video 兼容性问题,基于 video 已有的方法,提供自定义 api
  • Event 事件机制,代理原生事件并提供自定义事件的能力
  • Plugin 插件机制,为不同类型的插件提供接口及运行机制
  • Helper 辅助模块

larkplayer player structure

下面详细再介绍下 Event 和 Plugin 模块

Event 模块

由于大量的事件都是通过与用户交互触发,因此直接使用 DOM 的 Event 机制即可

  • 使用 addEventListener、removeEventListener 完成事件绑定与注销
  • 使用 CustomEvent 实现自定义事件功能
  • 使用 dispatchEvent 实现手动触发事件功能

Plugin 模块

插件分为 3 类:

  • UI 插件,样式相关
  • MediaSource 插件,基于 MSE 提供更多视频格式支持
  • 其他插件

UI 插件

特点

  • 与 DOM 交互
  • 与播放器交互
  • 组件化
    • 逻辑与视图的结合
    • 组件间组合    * 支持 jsx 语法,写起来方便点

实现

提供 Component 类:

  • 构造函数
    • 接收 player 和 props 参数
    • 提供 this.player 与播放器交互
    • 提供 this.options 获取组件参数
    • 提供 this.el 指向组件 DOM 元素
    • 组件的逻辑写在构造函数里(别说了,没有其他生命周期)
  • 方法
    • createEl: 返回组件 DOM 元素(提供 jsx 语法支持)
    • dispose: 销毁组件
    • static createElement: 用于实现组件间组合,不过通过 js 手写实在是不方便,已经通过 jsx 语法糖掩盖(突然感觉有点像巧克力味的屎)
    • static register 绑定组件
  • 其他
    • larkplayer 有一些工具方法提供,编写插件时会方便点
      • DOM 提供一些对 DOM 的便捷操作
      • Events 提供事件相关方法

如何编写插件

  • 继承 Component 类并实现 createEl dispose 方法,在构造函数中书写组件逻辑
  • 通过 Component.register(class, options) 绑定插件(插件名默认为首字母小写的类名,options.name 可手动指定插件名)
  • 播放器初始化时通过 options.UI.name 传递参数
  • 播放器初始化完成后通过 player.UI.name 访问插件实例

详见 《UI 插件编写示例》

初始化时机

播放器构造函数中初始化,所有绑定的组件都会被渲染并添加到播放器 DOM 容器中

注意事项

  • 在组件构造函数中,如果要选择 this.el 的子元素,需要将上下文设置为 this.el,因为此时元素还未被插入到 html 中

MediaSource 插件

特点

影响播放器对视频资源的解析及播放

实现

提供 MediaSourceHandler 类

  • 构造函数
    • 接收 player 和 options 参数
    • 提供 this.player 与播放器交互
    • 提供 this.options 接收参数
  • 方法
    • src: 处理视频资源
    • play: 播放视频
    • dispose: 销毁插件
    • static canPlay: 判断能否支持当前视频类型
    • static select: 筛选能支持当前视频类型的插件
    • static register: 绑定插件

如何编写插件

  • 继承 MediaSourceHandler 类并实现 src play dispose 方法,以及 canPlay 静态方法
  • 通过 MediaSourceHandler.register(class, options) 绑定(插件名默认为首字母小写的类名,options.name 可手动指定插件名)
  • 播放器初始化时通过 options.MS.name传递参数

详见 《MediaSource 插件编写》

初始化及调用时机

  • 播放器初始化时,如果存在视频资源,则选择合适的插件处理视频
  • 视频链接改变时,选择合适的插件处理视频
  • 视频播放时,如果当前有 MediaSource 插件正在运行,优先调用插件的 play 方法

普通插件

特点

没想好有什么特点,姑且认为他们只是简单的调用播放器的 api,比如断点续播之类的

实现

提供 Plugin 类

  • 构造函数
    • 接收 player options 参数
    • 提供 this.player
    • 提供 this.options
  • 方法
    • dispose: 销毁插件
    • static register: 静态方法,绑定插件

如何编写插件

  • 继承 Plugin 类,并实现 dispose 方法
  • 通过 Plugin.register(class, options) 绑定,options.name 可指定插件名(插件名默认为首字母小写的类名,options.name 可手动指定插件名)
  • 播放器初始化时通过 options.plugin.name 传递参数
  • 播放器初始化完成后通过 player.plugin.name 访问插件实例

详见 《普通插件编写》

初始化时机

播放器构造函数中初始化插件

plugin store

有负责插件存取的方法即可,不予详述