Chimee API 介绍

Chimee 本质上是对原生 video 元素的一个封装。因此在许多用法上都会和原生 video 元素一致。本文会介绍 Chimee 在 video 层级上的具体用法。

同时,Chimee 也是一个组件化框架,要理解这个框架的具体用法,请阅读为什么要将 Chimee 设计成一个组件化框架?

本文将分为以下几个部分进行阐述:

生成实例

我们直接调用new就可以生成一个 Chimee 实例。这个实例中我们需要使用者提供一个 dom 节点,我们称之为 wrapper。因此,在构造函数里我们接受三种形式的参数——string | HTMLElment | Object

我们可以直接传入 wrapper 的选择器。

const chimee = new Chimee('#wrapper');

也可以传入一个节点。

const wrapper = document.createElement('div');
const chimee = new Chimee(wrapper);

有的时候我们需要传入更多参数配置,我们可以传入一个对象。

const chimee = new Chimee({
  wrapper: '#wrapper',
  src: 'http://cdn.toxicjohann.com/lostStar.mp4',
  controls: false,
  autoplay: true
});

具体的可选参数包括:

wrapper

isLive

box

* preset 🚫(v0.4.0 废弃,更改为 kernels)

import Flv from 'chimee-kernel-flv';
const player = new Chimee({
  src: 'http://yunxianchang.live.ujne7.com/vod-system-bj/TL1ce1196bce348070bfeef2116efbdea6.flv',
  preset: {
    flv: Flv
  },
  // 编解码容器
  box: 'flv', // flv hls mp4
  // dom容器
  wrapper: '#wrapper',
  // video
  autoplay: true,
  controls: true
})

* kernels

import Flv from 'chimee-kernel-flv';
const player = new Chimee({
  src: 'http://yunxianchang.live.ujne7.com/vod-system-bj/TL1ce1196bce348070bfeef2116efbdea6.flv',
  kernels: {
    flv: Flv
  },
  // 编解码容器
  box: 'flv', // flv hls mp4
  // dom容器
  wrapper: '#wrapper',
  // video
  autoplay: true,
  controls: true
})

有的时候我们需要为 kernel 配置单独的参数。这个时候我们可以用如下方式传入参数。

import Flv from 'chimee-kernel-flv';
const player = new Chimee({
  src: 'http://yunxianchang.live.ujne7.com/vod-system-bj/TL1ce1196bce348070bfeef2116efbdea6.flv',
  kernels: {
    flv: {
      handler: Flv,
      stashSize: 1000 * 1000 * 1024,
  },
  // 编解码容器
  box: 'flv', // flv hls mp4
  // dom容器
  wrapper: '#wrapper',
  // video
  autoplay: true,
  controls: true
})

plugin

当我们安装一个插件后,我们可以直接在新建实例时传入其名称使用它,如下:

import popup from 'chimee-plugin-popup';
import Chimee from 'chimee'
Chimee.install(popup({
  name: 'ccPopup',
  title: '这是一个居中信息框',
  body: '这里是信息内容',
  offset: '50% 50%',
  width: '200px'
}));

const chimee = new Chimee({
  wrapper: '#wrapper',
  plugin: [popup.name]
});

有的时候,我们希望给插件传入一些参数,我们可以在 plugin 中传入一个对象,该对象中必须要包含一个 name 属性。

import popup from 'chimee-plugin-popup';
import Chimee from 'chimee'
Chimee.install(popup({
  name: 'ccPopup',
  title: '这是一个居中信息框',
  body: '这里是信息内容',
  offset: '50% 50%',
  width: '200px'
}));

const chimee = new Chimee({
  wrapper: '#wrapper',
  plugin: [{
    name: popup.name,
    theme: 'dark'
  }]
});

部分情况下,可能会出现插件名冲突的情况。又或者,你希望在该实例上重命名某个插件,这时候你可以利用重命名属性。

import popup from 'chimee-plugin-popup';
import Chimee from 'chimee'
Chimee.install(popup({
  name: 'ccPopup',
  title: '这是一个居中信息框',
  body: '这里是信息内容',
  offset: '50% 50%',
  width: '200px'
}));

const chimee = new Chimee({
  wrapper: '#wrapper',
  plugin: [{
    name: popup.name,
    alias: 'myui'
  }]
});

插件间具有优先级关系,在 plugin 数组中,插件的优先级由高到低排列。

优先级高的插件将在事件处理机制中优先获得事件,因此可以阻截后方插件获取事件。

要理解插件的具体用法,请阅读为什么要将 Chimee 设计成一个组件化框架?

要获知插件相关的 api, 请阅读Chimee 插件 API 介绍

container (v0.5.0 后)

{
  "width": "100%",
  "height": "100%",
  "position": "relative",
  "display": "block",
}

videoRequiredGuardedAttributes(v0.10.0 后)

noDefaultContextMenu(v0.10.1 后)

video属性

除了以上几个用于 Chimee 内部使用的配置,我们还可以传入一些 video 元素需要用到的参数。

属性 含义 类型 默认值 备注
src 播放地址 string '' 假如 autoloadtrue,则当我们设置 src 后,该地址会加载到 video 元素上,并作出相应加载。若果 autoloadfalse, 则意味着我们仅仅在 videoConfig 上设置了地址,此时可以手动调用 load 方法进行
autoplay 是否自动播放 boolean false autoplay 指在分配 src 后自动播放,即调用chimee.load()后。
controls 是否展示控制条 boolean false 在没有安装任何皮肤插件时,该属性控制是否展示原生控制条。若果安装了皮肤插件,则意味着是否展示皮肤自带的控制条。
width video 的宽度 number \ string '100%'
height video 的高度 number \ string '100%'
crossOrigin 是否跨域 boolean undefined
loop 是否循环 boolean false
muted 是否静音 boolean false
preload 是否预加载 string 'auto'
poster 封面 string ''
playsInline 是否内联 boolean false 我们会为此添加 playsinle webkit-playsinline x5-playsinline
xWebkitAirplay 是否添加 x-webkit-airplay boolean false
x5VideoPlayerFullscreen 是否添加x5-video-play-fullscreen boolean false
x5VideoOrientation x5-video-orientation string \ void undefined 可选 landscape 和 portrait
x5VideoPlayerType x5-video-player-type 'h5' \ void undefined
playbackRate 回放速率 number 1 大于1加速,小于1减速
defaultPlaybackRate 默认回放速率 number 1 大于1加速,小于1减速
autoload 设置src时是否进行自动加载 boolean true
defaultMuted 是否是默认静音 boolean false 对应于 video 上的 muted 标签
disableRemotePlayback 是否不展示远程回放标志 boolean false 对应于 video 上的 disableRemotePlayback 标签
volume 音量 number 原 video 的音量

注意

1)autoplay 属性在并不是在所有情况下都会生效。但是通过一些配置,我们可以使其在大部分模式下生效。

  1. 在 iOS 下需要 inline 的模式下才能自动播放,因此在传入的时候需要设置 playsInline: true。我们会为你设置playsinline="true" webkit-playsinline="true"
  2. 然而并不是所有 iOS 的 webview 都支持该模式,如果你的 iOS 版本比较旧,请检查 webView 上有否设置 webview.allowsInlineMediaPlayback = YES;
  3. 在腾讯的 X5 浏览器也需要同理,设为 inline: true,我们会为你设置 x5-playsinline
  4. 部分浏览器必须要一开始就添加 video 元素,此时,请将 wrapper 的 html 写成如下格式。
<div id="wrapper">
  <container>
    <video></video>
  </container>
</div>

2)以上所有属性均可以在 chimee 实例上直接自上使用,如this.src

video元素相关方法

* 前缀为 chimee 自定义方法

我们可以把 chimee 实例理解为 video 元素的子集映射。因此我们可以通过 chimee 实例直接操作video。而 chimee 上也有相应的 video 方法。

load

参数

load 方法会将地址设置到 video 元素上。之后才能进行相应的播放。我们可以利用load完成如下需求。

如一开始未设地址,利用 load 添加地址。

import Chimee from 'chimee';
const chimee = new Chimee('#wrapper');
chimee.load('http://cdn.toxicjohann.com/lostStar.mp4');

或已设地址,利用 load 附着到 video 上。

import Chimee from 'chimee';
const chimee = new Chimee({
  wrapper: '#wrapper',
  src:'http://cdn.toxicjohann.com/lostStar.mp4'
});
chimee.load();

又或者运行时更换地址。

import Chimee from 'chimee';
const chimee = new Chimee('#wrapper');
chimee.load('http://cdn.toxicjohann.com/lostStar.mp4');
.....
chimee.load('http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4');

甚至是播放不同类型的视频。

import Chimee from 'chimee';
import ChimeeKernelFlv from 'chimee-kernel-flv';
const chimee = new Chimee({
  wrapper: '#wrapper',
  src:'http://cdn.toxicjohann.com/lostStar.mp4',
  autoplay: true
});
...
chimee.load('http://yunxianchang.live.ujne7.com/vod-system-bj/TL1ce1196bce348070bfeef2116efbdea6.flv', {
  box: 'flv',
  kernels: {
    flv: ChimeeKernelFlv
  }
})

load 在 v0.7.1 后支持更简便的写法。

import Chimee from 'chimee';
import ChimeeKernelFlv from 'chimee-kernel-flv';
const chimee = new Chimee({
  wrapper: '#wrapper',
  src:'http://cdn.toxicjohann.com/lostStar.mp4',
  autoplay: true
});
...
chimee.load({
  src: 'http://yunxianchang.live.ujne7.com/vod-system-bj/TL1ce1196bce348070bfeef2116efbdea6.flv',
  box: 'flv',
  kernels: {
    flv: ChimeeKernelFlv
  }
})

同样的,因为我们传入的是 kernels ,所以我们也可以定义一些 kernels 的参数。

import Chimee from 'chimee';
import ChimeeKernelFlv from 'chimee-kernel-flv';
const chimee = new Chimee({
  wrapper: '#wrapper',
  src:'http://cdn.toxicjohann.com/lostStar.mp4',
  autoplay: true
});
...
chimee.load({
  src: 'http://yunxianchang.live.ujne7.com/vod-system-bj/TL1ce1196bce348070bfeef2116efbdea6.flv',
  box: 'flv',
  kernels: {
    flv: {
      handler: ChimeeKernelFlv,
      stashSize: 1000 * 1000 * 1024,
    },
  }
})

load 方法会触发 load 系列事件,你可以通过插件 beforeLoad 阻截或挂起事件,也可以通过load事件阻止冒泡等。要了解更多相关知识,可以阅读插件的事件机制

load 会在以下情况切换内部 kernel。

  • 播放的 box 不是 native
  • 播放的 box 和原 box 不一致
  • 传入新的 option 参数的时候

play

播放视频的函数。

play 方法会触发 play 系列事件,你可以通过插件 beforePlay 阻截或挂起事件,也可以通过play事件阻止冒泡等。要了解更多相关知识,可以阅读插件的事件机制

pause

暂停视频播放的函数

pause 方法会触发 pause 系列事件,你可以通过插件 beforePasue 阻截或挂起事件,也可以通过pause事件阻止冒泡等。要了解更多相关知识,可以阅读插件的事件机制

seek

参数

seek函数本质等同于设置 video 上的 currentTime。一般用于快进后退。在 chimee 上也可以直接设置 currentTime,并不一定需要运用此函数。

seek 方法会触发 seek 系列事件,你可以通过插件 beforeSeek 阻截事件,也可以通过seek事件阻止冒泡等。要了解更多相关知识,可以阅读插件的事件机制

startLoad

开始视频源的加载(现在只有 hls 和 native 模式支持)

stopLoad

暂停视频源的加载

其中 chimee-kernel-flv.js 和 native 模式均是将 src 移除。

而 chimee-kernel-flv 和 chimes-kernel-hls 则是暂停加载。

focus

自动聚焦到 video 元素上。

canPlayType

参数

返回

* $silentLoad

静默加载视频。视频在规定时间内加载成功,则无缝切换视频源,多用于清晰度切换。

若视频加载失败可进行重试。

无缝切换的本质是,在后台打开一个新视频源并加载到约定时间,当主视频播放到约定时间后进行切换。

参数

我们可以利用 $silentLoad 完成以下需求。

  1. 无缝切换同种视频
import Chimee from 'chimee';
const player = new Chimee({
  src: 'http://cdn.toxicjohann.com/lostStar.mp4',
  wrapper: '#wrapper',
  autoplay: true
});
player.$silentLoad('http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4');
  1. 多次尝试切换
import Chimee from 'chimee';
const player = new Chimee({
  src: 'http://cdn.toxicjohann.com/lostStar.mp4',
  wrapper: '#wrapper',
  autoplay: true
});
player.$silentLoad('http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4', {repeatTimes: 5, increment: 2});

在上例中,若加载失败将会重试多达四次。每次尝试时间分别是3、5、7、9、11秒。

  1. 切换不同种类的视频
import Chimee from 'chimee';
import chimeeKernelFlv from 'chimee-kernel-flv';
const player = new Chimee({
  src: 'http://cdn.toxicjohann.com/lostStar.mp4',
  wrapper: '#wrapper',
  autoplay: true
});
player.$silentLoad('http://yunxianchang.live.ujne7.com/vod-system-bj/TL1ce1196bce348070bfeef2116efbdea6.flv', {
  box: 'flv',
  kernels: {
    flv: chimeeKernelFlv
  }
});
  1. 加载途中放弃
import Chimee from 'chimee';
const player = new Chimee({
  src: 'http://cdn.toxicjohann.com/lostStar.mp4',
  wrapper: '#wrapper',
  autoplay: true
});
const option = {};
player.$silentLoad('http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4', option);
...
option.abort = true;

requestPictureInPicture(v0.11.0后支持)

画中画指 Picture-in-Picture Api。点击此处可观看 google chrome 最新的 demo。

为此, chimee 也给用户提供了相关的 api。

在不支持画中画功能的浏览器上,我们使用 canvas 模拟画中画图标。

该函数为异步函数,无需传入参数。

调用此方法会触发enterpictureinpicture事件。

exitPictureInPicture(v0.11.0后支持)

退出画中画模式。

同步函数,无需传入参数。

调用此方法会触发leavepictureinpicture事件。

video元素相关属性

* 前缀为 chimee 自定义属性

我们可以把 chimee 实例理解为 video 元素的子集映射。因此我们可以通过 chimee 实例直接操作video。而 chimee 上也有相应的 video 属性。

src

默认情况下可以如此操作。

const chimee = new Chimee('#wrapper');
chimee.src = 'http://cdn.toxicjohann.com/lostStar.mp4';

又或者自行手动加载。

const chimee = new Chimee('#wrapper');
chimee.autoload = false;
chimee.src = 'http://cdn.toxicjohann.com/lostStar.mp4';
.....
chimee.load();

* isLive

* box

* preset 🚫(v0.4.0废弃,请不要修改)

import Flv from 'chimee-kernel-flv';
const player = new Chimee({
  src: 'http://yunxianchang.live.ujne7.com/vod-system-bj/TL1ce1196bce348070bfeef2116efbdea6.flv',
  preset: {
    flv: Flv
  },
  // 编解码容器
  box: 'flv', // flv hls mp4
  // dom容器
  wrapper: '#wrapper',
  // video
  autoplay: true,
  controls: true
})

buffered

duration

volume

currentTime

autoplay

controls

width

height

crossOrigin

loop

defaultMuted

muted

preload

poster

playsInline

x5VideoPlayerFullscreen

x5VideoOrientation

xWebkitAirplay

playbackRate

defaultPlaybackRate

disableRemotePlayback

inPictureInPictureMode(v0.11.0后支持)

container元素相关属性

在 v0.5.0 后,chimee 提供入口直接操作 container 的配置。

现在提供四个 css 样式,分别为 width, height, display, block.

你可以采取如下方式直接更改 container 的宽度

import Chimee from 'chimee';
const chimee = new Chimee({
  wrapper: '#wrapper',
});
chimee.container.width = '90%';

事件监听相关方法

chimee 作为 video 的映射,自然也是可以监听 video 上的事件。包括 video 上的所有 video 事件和 dom 事件。我们提供了以下几个接口。

on

利用 on 可以直接监听任何发生在 video 上的事件。

但是 video 只是 chimee 上的一部分。chimes 分为 wrapper, container, video 三个层级。

其中要监听特定的事件,请按照如下建议配置参数

  • 监听内核事件, target 为 kernel
  • 监听 container 事件, target 为 container
  • 监听 wrapper 事件,target 为 wrapper
  • 监听插件间自定义事件,target 为 plugin
  • 监听全凭相关事件,target 为 'esFullscreen' (不建议配置,代码会自动分析)
  • 监听 video 上的 dom 事件,如 click ,target 为 'video-dom' (不建议配置,代码会自动分析)
  • 监听 video 自身事件,如 play,target 为 video (不建议配置,代码会自动分析)

如果要监听 wrapper 上的事件,请添加前缀 w_

如果要监听 container 上的事件,请添加前缀 c_

要理解 chimee 的事件体系,请阅读《为什么要将 Chimee 设计成一个组件化框架?》中的事件体系部分

off

once

emit

一般用于触发如 play, pause 等行为,和直接调用playpause等方法一致。也可以利用此和插件进行沟通。

emitSync

一般用于触发 dom 事件。

registerEvents

用于注册新事件,现阶段仅支持在 kernel 上注册。

例如,我们像监听 kernel 上的 test 事件。可以这么做

import Chimee from 'chimee'

Chimee.registerEvents({
  name: 'test',
  target: 'kernel',
});

数据监听相关方法

$watch

$watch 可用于监听特定属性的变化。当属性变化时,会执行传入的回调函数,回调函数会接收到新的属性值和原属性值。

参数

例子:

你可以轻易监听 video 上的一些属性。

import Chimee from 'chimme';
const player = new Chimee({
  wrapper: 'body',
  plugin: ['plugin']
});
player.$watch('controls', (newVal, oldVal) => console.log(newVal, oldVal));
player.controls = true; // true, false

又或者自定义属性:

import Chimee from 'chimme';
const player = new Chimee({
  wrapper: 'body',
  plugin: ['plugin']
});
player.test = 1;
player.$watch('test', (newVal, oldVal) => console.log(newVal, oldVal));
player.test = 2; // 2, 1

你也可以深度监听数组,直接调用数组的操作方法:

import Chimee from 'chimme';
const player = new Chimee({
  wrapper: 'body',
  plugin: ['plugin']
});
player.test = [1, 2, 3];
player.$watch('test', (newVal, oldVal) => console.log(newVal, oldVal), {deep: true});
player.plugin.test.push(4); // [1, 2, 3, 4], [1, 2, 3, 4]

同理你也可以深度监听对象,但是对新增元素或者删除元素需要使用 $set$del 进行辅助。

import Chimee from 'chimme';
const player = new Chimee({
  wrapper: 'body',
  plugin: ['plugin']
});
player.test = {foo: 1};
player.$watch('test', (newVal, oldVal) => console.log(newVal, oldVal), {deep: true});
player.plugin.test.foo = 2; // {foo: 2}, {foo: 2}
player.$set(test, 'bar', 1); // {foo: 2, bar: 1}, {foo: 2, bar: 1}
player.$del(test, 'bar'); // {foo: 2}, {foo: 2}

注意:

  1. 并非所有 video 相关属性都可以监听。现阶段只支持监听$videoConfig 中除src 以外的部分。

src 的值因为涉及到 video 播放核心的变换,以及事件拦截等,建议采取事件驱动模式编写。

paused 等 video 只读属性,因为需要监听原生 video,故暂不提供。且以上属性大部分可以通过事件获取。

  1. 采取深度监听时,子元素修改后回调函数并不会获得原有对象快照
  2. 深度监听时需要使用 $set$del 进行辅助。

$set

设置对象或者数组的值, 可以触发$watch 的回调函数

参数

$del

删除对象或者数组的值, 可以触发$watch 的回调函数

参数

全屏相关方法

* $fullscreen

全屏和退出全屏的相关操作。

关于全屏对象的设置可到Chimee 插件 API 介绍中的插件位置部分了解更多

requestFullscreen

进入全屏

exitFullscreen

退出全屏

全屏相关属性

isFullscreen

若实例中的任意一个子节点全屏,则返回 true

fullscreenElement

如果全屏的是 containerwrappervideo 三者之一,则直接返回字符串。

否则返回正在全屏的对象。

若无全屏则为 undefined

fullscreenchange

如果需要监听全屏事件。只要监听 fullscreenchange 即可。

player.on('fullscreenchange', evt => {
  console.log('wowo, fullscreen', evt);
});

插件操作

在 chimee 中我们会使用插件来实现业务需求,因此我们要进行插件安装。在 chimee 上有以下几个方法。

install

要使用一个插件,我们首先得利用该方法安装插件,要注意该方法是一个静态方法。

import popup from 'chimee-plugin-popup';
import Chimee from 'chimee'
Chimee.install(popup({
  name: 'ccPopup',
  title: '这是一个居中信息框',
  body: '这里是信息内容',
  offset: '50% 50%',
  width: '200px'
}));

hasInstalled

import popup from 'chimee-plugin-popup';
import Chimee from 'chimee'
Chimee.install(popup({
  name: 'ccPopup',
  title: '这是一个居中信息框',
  body: '这里是信息内容',
  offset: '50% 50%',
  width: '200px'
}));
Chimee.hasInstalled(popup.name); // true
Chimee.hasInstalled('something else'); // false

uninstall

卸载插件后,正在使用该插件的实例不受影响。卸载后新建的实例无法使用此插件。

getPluginConfig

use

该函数其实就是新建实例时传入的 plugin选项所使用的方法。利用此函数可以动态安装插件。

import popup from 'chimee-plugin-popup';
import danmu from 'chimee-plugin-danmu';
import Chimee from 'chimee'
Chimee.install(popup({
  name: 'ccPopup',
  title: '这是一个居中信息框',
  body: '这里是信息内容',
  offset: '50% 50%',
  width: '200px'
}));
Chimee.install(danmu)

const chimee = new Chimee('#wrapper');
chimee.use(popup.name);
chimee.use({
  name: danmu.name,
  theme: 'white'
});

unuse

全局设置

我们可以通过 Chimee.config 这个静态属性配置一些全局设置。

log

log 中可以配置全局的 log 级别。默认设置如下:

log: {
    error: true,
    info: true,
    warn: true,
    debug: true,
    verbose: true,
  }

我们可以直接修改,例如关闭 verbose。

Chimee.log.verbose = false;

silent

如果你不想逐个更改,也可以使用 silent 属性统一关闭所有 log.

Chimee.silent = true;

errorHandler

你还可以通过 errorHandler 配置自己的错误处理勾子。

Chimee.errorHandler = error => console.log('wow, an error!!!', error.message)

useStyleFullscreen

在某些特殊的情况下,浏览器的全屏效果不是特别好。此时我们可以通过 css 的样式模拟全屏。

Chimee.config.useStyleFullscreen = true;

进阶使用

随着业务发展越来越复杂,我们会发现我们需要实现众多功能。这些功能彼此耦合关联,难以维护。这时候我们需要将功能模块化使用,那样便于我们进行灰度和 debug。此时我们需要使用 chimee 自身的插件体系。让我们进入下一部分,为什么要将 Chimee 设计成一个组件化框架?