自定义模拟事件

本文整理自《JavaScript高级程序设计》第4版


我们可以使用document.createEvent()的方式创建一个Event对象。它接收一个字符串,表示要创建的事件类型。

在 DOM2 中,所有这些字符串都是英文复数形式,但在 DOM3 中,又把它们改成了英文单数形式。可用的字符串值是以下值之一。

  • UIEvents (DOM3 中是 UIEvent ):通用用户界面事件(鼠标事件和键盘事件都继承自这个事件)。
  • MouseEvents (DOM3 中是 MouseEvent ):通用鼠标事件。
  • HTMLEvents (DOM3 中没有):通用 HTML 事件(HTML 事件已经分散到了其他事件大类中)。

注意,键盘事件不是在 DOM2 Events 中规定的,而是后来在 DOM3 Events中增加的。

模拟鼠标事件

要创建鼠标 event 对象,可以调用 createEvent() 方法并传入 MouseEvents 参数。它会返回一个event对象,这个对象有一个initMouseEvent()方法,用于为新对象指定鼠标的特定信息。

initMouseEvent() 方法接收 15 个参数,分别对应鼠标事件会暴露的属性。这些参数列举如下。

参数类型说明
typestring要触发的事件类型,如 click
bubblesboolean表示事件是否冒泡。为精确模拟鼠标事件,应该设置为 true
cancelableboolean表示事件是否可以取消。为精确模拟鼠标事件,应该设置为 true
viewAbstractView与事件关联的视图。基本上始终是 document.defaultView
detailnumber关于事件的额外信息。只被事件处理程序使用,通常为 0
screenXnumber事件相对于屏幕的 x 坐标
screenYnumber事件相对于屏幕的 y 坐标
clientXnumber事件相对于视口的 x 坐标
clientYnumber事件相对于视口的 y 坐标
ctrlkeyboolean表示是否按下了 Ctrl 键。默认为 false
altkeyboolean表示是否按下了 Alt 键。默认为 false
shiftkeyboolean表示是否按下了 Shift 键。默认为 false
metakeyboolean表示是否按下了 Meta 键。默认为 false
buttonnumber表示按下了哪个按钮。默认为 0
relatedTargetobject与事件相关的对象。只在模拟 mouseovermouseout 时使用

模拟键盘事件

在 DOM3 中创建键盘事件的方式是给 createEvent() 方法传入参数 KeyboardEvent 。这样会返回一个 event 对象,这个对象有一个 initKeyboardEvent() 方法。这个方法接收以下参数。

参数类型说明
typestring要触发的事件类型,如 keydown
bubblesboolean表示事件是否冒泡。为精确模拟键盘事件,应该设置为 true
cancelableboolean表示事件是否可以取消。为精确模拟键盘事件,应该设置为 true
viewAbstractView与事件关联的视图。基本上始终是 document.defaultView
keystring按下按键的字符串代码
locationnumber按下按键的位置。0 表示默认键,1 表示左边,2 表示右边,3 表示数字键盘,4 表示移动设备(虚拟键盘),5 表示游戏手柄
modifiersstring空格分隔的修饰键列表,如 Shift
repeatnumber连续按了这个键多少次

模拟其他事件

模拟 HTML 事件要调用 createEvent() 方法并传入HTMLEvents,然后再使用返回对象的initEvent()方法来初始化:

let event = document.createEvent("HTMLEvents");
event.initEvent("focus", true, false);
target.dispatchEvent(event);

自定义DOM事件

要创建自定义事件,需要调用 createEvent("CustomEvent") 。返回的对象包含initCustomEvent() 方法,该方法接收以下 4 个参数。

参数类型说明
typestring要触发的事件类型,如 myevent
bubblesboolean表示事件是否冒泡
cancelableboolean表示事件是否可以取消
detailobject任意值。作为 event 对象的 detail 属性

说明

不过,createEvent使用的许多方法都被废弃了,使用的话,需要用新的API来代替,具体用法可以参见MDN文档

React的源码中,自定义事件也被用到过。

function invokeGuardedCallbackDev (func) {
  function handleWindowError (error) {
  }

  const event = document.createEvent('Event')
  const fakeNode = document.createElement('react')
  const evtType = 'fake-event'

  window.addEventListener('error', handleWindowError)

  function callCallback () {
    fakeNode.removeEventListener(evtType, callCallback, false)
    func()
  }

  fakeNode.addEventListener(evtType, callCallback, false)

  event.initEvent(evtType, false, false)

  fakeNode.dispatchEvent(event)

  window.removeEventListener('error', handleWindowError)
}

由于dispatchEvent是同步触发事件,而且在事件回调中抛出错误不会影响dispatchEvent的调用者,所以在React中,通过自定义事件的处理方式,可以在代码异常时不阻塞后续代码的执行。

如果您觉得本文对您有用,欢迎捐赠或留言~
微信支付
支付宝

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注