事件机制

可用方法

在插件上可以调用的事件函数

  • $on 绑定事件
  • $off 解绑事件
  • $once 一次性绑定事件
  • $emit 触发事件
  • $emitSync 触发事件,以同步的方式

监听对象

利用上述方法进行事件监听,监听的对象均为原生 video 对象。

有的时候我们需要监听 container 和 wrapper 的相关事件,此时我们需要在监听事件时,传入对应的 option。

如:

  • chimee.on('mousemove', evt => console.log(evt), { target: 'container' };, 在 container 上绑定 mousemove 事件
  • chimee.on('mousemove', evt => console.log(evt), { target: 'wrapper' };, 在 wrapper 上绑定 mouse move 事件
官方提供的事件绑定方法主要目的是搭建插件间沟通桥梁,和插件对 video, container, wrapper 三者的监听。当然大家可以自定义相关事件,只要不涉及到相应保留前缀即可。

事件触发流程

鉴于插件间,插件和 video 间没有层级关系,不提供不捕获监听选项。

但是插件间仍然会存在逻辑关系。故在播放器事件内部仍然有相应的事件逻辑。

异步事件

一个完整的事件流程包括以下几部分

假设我们使用 $emit 触发了事件 play

  • 首先触发 beforePlay 事件, 进入 before 阶段。
    • 各个插件收到 beforePlay 事件,进行相应的处理,如果返回的是 false 或者 Promise.reject(), 则事件被阻截。
    • 如果返回的是处于 pending 状态的 Promise, 则可以理解为事件被挂起。
  • 如果 before 流程顺利执行完毕,则进入 process 阶段。
    • 此时内部会判断是否是对 video 进行操作。
    • 若是,则执行该操作,等待触发的相应事件,然后进入 main 阶段
    • 否则,直接进入 main 阶段
    • 在本例中,play 是原生 video 操作,此时我们会触发 video.play()。并在原生 video 的 play 事件触发后继续原流程。
  • 进入 main 阶段后,会执行各插件的 play 事件。
    • 插件同样可以利用上述方式挂起或阻截。一般而言,如播放广告的时候,广告会将相应事件阻截,防止造成后者误会。
  • main 阶段结束后,则进入 after 阶段,执行各插件的 afterPlay 事件。
    • 同上,after 阶段也可以使用上述方式进行阻截或者挂起操作。从而模拟相应的逻辑关系。
  • 最后,进入副作用阶段,执行各插件的 _play 事件。
    • 该事件只要事件流程进入过 main 阶段就必定会触发。
    • 该事件为广播同步分发,没有阻截等概念。
    • 该事件一般用于获取自己的事件是否触发成功和被拦截,一般插件无需使用。

同步事件

以上为异步事件流程,其有几大弊端。

  • 异步,导致理解上有部分困难
  • 异步,故不能执行 event.stopPropagation() 和 event.preventDefault() 事件
    因此,和 DOM 有关的操作,我们建议使用 $emitSync事件。

与异步流程相同,也分为相应的五个阶段,假设我们使用 $emitSync 触发了 sync 事件。

  • before => beforeClick
    • 假如插件返回 false, 则可以阻截事件发生。因为同步,无法挂起事件
  • processor => video.click()
  • main => click
    • 插件会收到原生的事件对象
    • 插件可以调用 event.preventDefault() 阻止原生默认事件
    • 插件可以调用 event.stopPropagation() 阻止原生 DOM 节点的冒泡
    • 插件可以返回 false 阻止插件间的冒泡,并阻截事件进入下个阶段
  • after => afterClick
    • 插件会收到原生的事件对象
    • 插件可以调用 event.preventDefault() 阻止原生默认事件
    • 插件可以调用 event.stopPropagation() 阻止原生 DOM 节点的冒泡
    • 插件可以返回 false 阻止插件间的冒泡,并阻截事件进入下个阶段
  • sideEffect => _click
    • 插件会收到原生的事件对象
    • 插件可以调用 event.preventDefault() 阻止原生默认事件
    • 插件可以调用 event.stopPropagation() 阻止原生 DOM 节点的冒泡
    • 此阶段只要事件进入 main 阶段就必定会触发。
    • 此阶段不能阻止插件间冒泡。
注意,因为同步的优势,一般发生在 video 上的 DOM 事件,都会以同步的方式传输回来。换言之,假如我们进行如下操作

  1. this.$emit('click'); // 理解为模拟对 video 的点击


- 首先会触发异步的 before 事件- 进入 process 阶段,点击 video- video 返回 click 事件,使用同步(triggerSync)的方式传播,分别触发,click, (afterClick), _click事件。
注意,processor 只会处理 video 上的事件。换言之this.$emitSync('click') 会触发 video.click(), 而this.$emitSync('c_click')并不会触发 container.click()