插件的使用

chimee 是一个简单的框架。如果需要让 chimee 发挥更强的能力,我们需要插件。本章将会介绍如何使用插件。

什么是插件

插件是 chimee 中的一部分,他主要用于解耦业务逻辑,方便功能模块化。它具有以下特性。

  • 拥有内置在播放器的 DOM 部分
  • 能够对原生 video 的属性进行操作
  • 能够对原生 video 的样式进行操作
  • 能够调用原生 video 方法
  • 能够获取到播放器的关键数据
  • 能够阻截用户或者其余插件的请求 如果你想详细了解插件,可以阅读 plugin api

如果你想了解如何编写插件,可以阅读如何编写一个插件

安装插件

在使用插件前,我们需要安装他。那样可以让我们多个 chimee 实例生成对应的插件实例。

安装方法十分简单,我们调用 Chimee 的静态方法 install 即可。

安装后我们可以使用 hasInstalled 方法进行检验。

  1. import popup from 'chimee-plugin-popup';
  2. import Chimee from 'chimee'
  3. Chimee.install(popup({
  4. name: 'ccPopup',
  5. title: '这是一个居中信息框',
  6. body: '这里是信息内容',
  7. offset: '50% 50%',
  8. width: '200px'
  9. }));
  10. Chimee.hasInstalled(popup.name); // true

使用插件

安装了插件之后我们就可以使用它了。

声明式调用

我们可以在新建实例时进行声明式调用。

  1. import Chimee from 'chimee';
  2. import ChimeePluginControlbar from 'chimee-plugin-controlbar';
  3. // 安装插件
  4. Chimee.install(ChimeeControlbar);
  5. const player = new Chimee({
  6. wrapper: '#wrapper',
  7. src: 'http://cdn.toxicjohann.com/lostStar.mp4',
  8. autoplay: true,
  9. // 使用插件
  10. plugin: [
  11. ChimeePluginControlbar.name // 或者 'chimeeControl'
  12. ],
  13. });

这样子这个实例就会使用 chimee-plugin-controlbar 这个插件。

动态调用

我们也可以在实例化后动态调用插件。

下面我们将演示如何动态使用一个中间弹窗组建。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '这是一个居中信息框',
  6. body: '这里是信息内容',
  7. offset: '50% 50%',
  8. width: '200px',
  9. }));
  10. const player = new Chimee({
  11. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  12. wrapper: '#wrapper',
  13. autoplay: true,
  14. controls: true,
  15. muted: true,
  16. });
  17. setTimeout(() => {
  18. player.use('cc_popup');
  19. }, 2000);

效果如下,我们可以看到两秒后,弹窗动态出现。

插件的使用 - 图1

传入配置

部分插件自身也会有对应的配置,我们可以在使用的时候通过一个对象参数传入。

  1. import Chimee from 'chimee';
  2. import ChimeePluginDanmu from 'chimee-plugin-danmu';
  3. // 安装插件
  4. Chimee.install(chimeeDanmu);
  5. const player = new Chimee({
  6. // ...
  7. // 使用插件
  8. plugin: [{
  9. name: ChimeePluginDanmu.name,
  10. mode: 'canvas',
  11. }],
  12. });

停用及卸载

我们可以使用 unuse 停用插件,并使用 uninstall 卸载之。

  1. import Chimee from 'chimee';
  2. import ChimeePluginControlbar from 'chimee-plugin-controlbar';
  3. // 安装插件
  4. Chimee.install(ChimeeControlbar);
  5. const player = new Chimee({
  6. wrapper: '#wrapper',
  7. src: 'http://cdn.toxicjohann.com/lostStar.mp4',
  8. autoplay: true,
  9. // 使用插件
  10. plugin: [
  11. ChimeePluginControlbar.name // 或者 'chimeeControl'
  12. ],
  13. });
  14. // 停用插件
  15. player.unuse(ChimeePluginControllbar.name);
  16. chimee.uninstall(ChimeePluginControllbar.name);
如果我们未停用插件就卸载插件。正在使用插件的实例不会受影响,但是卸载后新建的实例无法使用此插件。

获取插件

安装的插件我们可以通过 $plugins 直接获得。

  1. import Chimee from 'chimee';
  2. import ChimeePluginControlbar from 'chimee-plugin-controlbar';
  3. // 安装插件
  4. Chimee.install(ChimeeControlbar);
  5. const player = new Chimee({
  6. wrapper: '#wrapper',
  7. src: 'http://cdn.toxicjohann.com/lostStar.mp4',
  8. autoplay: true,
  9. // 使用插件
  10. plugin: [
  11. ChimeePluginControlbar.name // 或者 'chimeeControl'
  12. ],
  13. });
  14. const chimeePluginControllbar = play.$plugins[ChimeePluginControlbar.name];

其中插件的是以对象的方式存储,我们可以通过其 id 获取。

id 一般是 name 的驼峰形式。

id 会在 use 的时候返回。

插件的使用顺序问题

我们可以看到在声明式使用插件的时候,我们传入的是一个数组。数组中插件的顺序与后期的插件的一些顺序也有关。

层级顺序

用户越早安装的插件,层级越低。我们用一个例子体会一下。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '第一个信息框',
  6. body: '我是第一个信息框',
  7. offset: '60% 50%',
  8. width: '200px',
  9. }));
  10. Chimee.install(chimeePluginPopup({
  11. name: 'cc_popup_2',
  12. title: '第二个信息框',
  13. body: '我是第二个信息框',
  14. offset: '50% 50%',
  15. width: '300px',
  16. }));
  17. const player = new Chimee({
  18. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  19. wrapper: '#wrapper',
  20. plugin: [ 'cc_popup', 'cc_popup_2' ],
  21. autoplay: true,
  22. controls: true,
  23. muted: true,
  24. });

我们执行这段代码,可以看到第二个信息框叠在第一个信息框上。这证明第二个信息框的层次比第一个信息框要高。

插件的使用 - 图2

那么假如我们第二个信息框是动态添加的呢?我们修改一下代码。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '第一个信息框',
  6. body: '我是第一个信息框',
  7. offset: '60% 50%',
  8. width: '200px',
  9. }));
  10. Chimee.install(chimeePluginPopup({
  11. name: 'cc_popup_2',
  12. title: '第二个信息框',
  13. body: '我是第二个信息框',
  14. offset: '50% 50%',
  15. width: '300px',
  16. }));
  17. const player = new Chimee({
  18. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  19. wrapper: '#wrapper',
  20. plugin: [ 'cc_popup' ],
  21. autoplay: true,
  22. controls: true,
  23. muted: true,
  24. });
  25. setTimeout(() => {
  26. player.use('cc_popup_2');
  27. }, 2000);

我们可以看到第二个信息框依然覆盖在第一个信息框上。

插件的使用 - 图3

这是因为动态添加的插件比声明式添加的插件顺序靠后,所以他们的层次相对较高。

事件分发顺序

chimee 的 plugin 具有事件拦截功能,所以事件分发的顺序也尤其重要。我们继续利用 popup 进行模拟。

首先我们先模拟正常行为。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '第一个信息框',
  6. body: '我是第一个信息框',
  7. offset: '60% 50%',
  8. width: '200px',
  9. events: {
  10. pause() {
  11. this.close();
  12. },
  13. },
  14. }));
  15. Chimee.install(chimeePluginPopup({
  16. name: 'cc_popup_2',
  17. title: '第二个信息框',
  18. body: '我是第二个信息框',
  19. offset: '50% 50%',
  20. width: '300px',
  21. events: {
  22. pause() {
  23. this.close();
  24. },
  25. },
  26. }));
  27. const player = new Chimee({
  28. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  29. wrapper: '#wrapper',
  30. plugin: [ 'cc_popup', 'cc_popup_2' ],
  31. autoplay: true,
  32. controls: true,
  33. muted: true,
  34. });

以上代码会在暂停的时候关闭弹窗。

插件的使用 - 图4

下面我们再修改一下代码,在第一个弹窗插件中对 pause 事件进行拦截。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '第一个信息框',
  6. body: '我是第一个信息框',
  7. offset: '60% 50%',
  8. width: '200px',
  9. events: {
  10. pause() {
  11. this.close();
  12. // 插件中的拦截机制
  13. return false;
  14. },
  15. },
  16. }));
  17. Chimee.install(chimeePluginPopup({
  18. name: 'cc_popup_2',
  19. title: '第二个信息框',
  20. body: '我是第二个信息框',
  21. offset: '50% 50%',
  22. width: '300px',
  23. events: {
  24. pause() {
  25. this.close();
  26. },
  27. },
  28. }));
  29. const player = new Chimee({
  30. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  31. wrapper: '#wrapper',
  32. plugin: [ 'cc_popup', 'cc_popup_2' ],
  33. autoplay: true,
  34. controls: true,
  35. muted: true,
  36. });

我们可以看到第一个弹窗关闭了,但是第二个弹窗并没有消失。这时候我们可以假设第一个插件拦截了第二个插件的暂停事件。

插件的使用 - 图5

为了验证我们的假设是否正确,我们这次在第二个弹窗处拦截事件。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '第一个信息框',
  6. body: '我是第一个信息框',
  7. offset: '60% 50%',
  8. width: '200px',
  9. events: {
  10. pause() {
  11. this.close();
  12. // 插件中的拦截机制
  13. return false;
  14. },
  15. },
  16. }));
  17. Chimee.install(chimeePluginPopup({
  18. name: 'cc_popup_2',
  19. title: '第二个信息框',
  20. body: '我是第二个信息框',
  21. offset: '50% 50%',
  22. width: '300px',
  23. events: {
  24. pause() {
  25. this.close();
  26. },
  27. },
  28. }));
  29. const player = new Chimee({
  30. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  31. wrapper: '#wrapper',
  32. plugin: [ 'cc_popup', 'cc_popup_2' ],
  33. autoplay: true,
  34. controls: true,
  35. muted: true,
  36. });

插件的使用 - 图6

可以看到此次两个弹窗同时消失了。换言之,第一个插件的优先级更高,事件更加优先传递到他的手上。

而事实上,事件确实是按照插件安装的顺序派发。越早安装的插件会越早接触到事件。

因此我们鼓励将诸如广告插件等需要具有拦截功能的插件优先安装。

使用 level 值调整层级

但是上述两条规则有一条悖论,如果我又希望我的插件具有优先权,但又希望他附着在最上层。怎么办?

此时我们可以使用 level 这个选项。在我们安装插件后,level值较高者的层级位置永远在level值较低者之上。

依旧是那两个弹窗,我们希望第一个弹窗能够出现在第二个弹窗之上。那么我们可以在安装的时候赋予其 level 值。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '第一个信息框',
  6. body: '我是第一个信息框',
  7. offset: '60% 50%',
  8. width: '200px',
  9. level: 1,
  10. events: {
  11. pause() {
  12. this.close();
  13. return false;
  14. },
  15. },
  16. }));
  17. Chimee.install(chimeePluginPopup({
  18. name: 'cc_popup_2',
  19. title: '第二个信息框',
  20. body: '我是第二个信息框',
  21. offset: '50% 50%',
  22. width: '300px',
  23. events: {
  24. pause() {
  25. this.close();
  26. },
  27. },
  28. }));
  29. const player = new Chimee({
  30. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  31. wrapper: '#wrapper',
  32. plugin: [ 'cc_popup', 'cc_popup_2' ],
  33. autoplay: true,
  34. controls: true,
  35. muted: true,
  36. });

插件的使用 - 图7

我们可以看到此时第一个弹窗的层级在第二个弹窗上了。

动态调整层级

刚刚举的例子都是静态声明层级,那么如果我们有动态需求怎么实现呢?

我们可以使用 $bumpToTop 来实现我们的需求,$bumpToTo 是插件上的方法,它可以将任意插件置顶。

我们可以使用以下示例代码。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '第一个信息框',
  6. body: '我是第一个信息框',
  7. offset: '60% 50%',
  8. width: '200px',
  9. events: {
  10. pause() {
  11. this.$bumpToTop();
  12. },
  13. },
  14. }));
  15. Chimee.install(chimeePluginPopup({
  16. name: 'cc_popup_2',
  17. title: '第二个信息框',
  18. body: '我是第二个信息框',
  19. offset: '50% 50%',
  20. width: '300px',
  21. }));
  22. const player = new Chimee({
  23. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  24. wrapper: '#wrapper',
  25. plugin: [ 'cc_popup', 'cc_popup_2' ],
  26. autoplay: true,
  27. controls: true,
  28. muted: true,
  29. });

插件的使用 - 图8

我们可以看到第一个弹窗在暂停后置顶了。

当然我们也可以直接获取插件实例进行操作。

  1. import Chimee from 'chimee';
  2. import chimeePluginPopup from 'chimee-plugin-popup';
  3. Chimee.install(chimeePluginPopup({
  4. name: 'cc_popup',
  5. title: '第一个信息框',
  6. body: '我是第一个信息框',
  7. offset: '60% 50%',
  8. width: '200px',
  9. }));
  10. Chimee.install(chimeePluginPopup({
  11. name: 'cc_popup_2',
  12. title: '第二个信息框',
  13. body: '我是第二个信息框',
  14. offset: '50% 50%',
  15. width: '300px',
  16. }));
  17. const player = new Chimee({
  18. src: 'http://cdn.toxicjohann.com/%E4%BA%8E%E6%98%AF.mp4',
  19. wrapper: '#wrapper',
  20. plugin: [ 'cc_popup', 'cc_popup_2' ],
  21. autoplay: true,
  22. controls: true,
  23. muted: true,
  24. });
  25. setTimeout(() => {
  26. player.$plugins.ccPopup.$bumpToTop();
  27. }, 2000);

插件的使用 - 图9

获取所有插件的顺序

我们可以通过 $pluginOrder 获取所有插件的顺序列表。其中列表中储存的为插件 id 。