事件架构-1-w3c事件规范

DOM 事件浅析

DOM 事件处理机制

DOM 拥有四个级别:DOM0级、DOM1级、DOM2级、DOM3级

DOM 事件分为三个级别:DOM0级事件处理、DOM2级别事件处理、DOM3级别事件处理

DOM0 的 onType

el.onclick = function() {}

DOM2 的 addEventListener、removeEventListener、dispatchEvent

// el.addEventListener(event-name, callback, useCapture)
// event-name: 事件名称,可以是标准的DOM事件
// callback: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event
// useCapture: 默认是false,代表事件句柄在冒泡阶段执行(或者说注册的是冒泡事件),true表示事件句柄在捕获阶段执行 (或者说注册的是捕获事件)

DOM3 在DOM2的基础上提供了更多的事件类型

event. preventDefault() 如果调用这个方法,默认事件行为将不再触发。

event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行(一般我们认为stopPropagation是用来阻止事件冒泡的,其实该函数也可以阻止捕获事件)

stopImmediatePropagation 既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它监听器被触发。

事件调度机制和DOM事件流 (Event dispatch and DOM event flow)

Event flow is the process through which the an event originates from the DOM implementation and is passed into the Document Object Model.

Event Object 会被分派到 Event Target, 但在分派开始之前,首先需要确定Event Object 的传播路径。

这条传播路径其实就是 Root -> Event Target 所形成的 ordered list。传播路径可以反应文档的层次树结构。列表中最后一项是 Event Target, 列表中非最后一项称为 Event Target 的 ancestor, 倒数第二项称为 Event Target 的 parent。

确定传播路径以后,Event Target 就会经历一个或者多个事件阶段。有三个事件阶段:捕获阶段(capture phase)、目标阶段(target phase)、冒泡阶段(bubble phase)。Event Object会完成下面描述的这些阶段,如果不支持某些阶段或者Event Object的传播已经停止,则跳过对应阶段。例如:Event Object的bubbles属性设置为false,将跳过冒泡阶段;如果 stopPropagation() 被调用,剩下的阶段都会被跳过。

[注] 出于历史原因,IE设计的事件流是冒泡流,Netscape的事件流是捕获事件流,而W3C为了指定标准,采用了折中的方法,也就是先捕获后冒泡。

  1. 捕获阶段: 这个Event Object从Event Target的 ancestors传播到Event Target的Parent
  2. 目标阶段: 这个Event Object到达 Object的Event Target
  3. 冒泡阶段: 这个Event Object以和捕获阶段相反的的顺序进行传播,开始于Event Target的Parent,结束于Window

eventflow

[注] Event Target 的 事件流发生了变化

这个版本分界线是在 Chrome 89.0.4363.0 和 89.0.4358.0。

Chrome 89 更新事件触发顺序

Capturing event listeners are called during bubbling phase for shadow hosts

技巧

由于冒泡阶段会把事件上传到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方法叫做事件代理也叫事件委托。
优势:

  1. 减少内存消耗,提高性能(监视列表相应)
  2. 动态绑定事件

参考:事件代理

事件类型 (Event Types)

Dom Event Model 允许 DOM的实现 去支持多个事件模块,该模型允许将来添加新的事件模块。

Event

// Introduced in DOM Level 2:
interface Event {

  // PhaseType
  const unsigned short      CAPTURING_PHASE                = 1;
  const unsigned short      AT_TARGET                      = 2;
  const unsigned short      BUBBLING_PHASE                 = 3;

  readonly attribute DOMString        type;
  readonly attribute EventTarget      target;
  readonly attribute EventTarget      currentTarget;
  readonly attribute unsigned short   eventPhase;
  readonly attribute boolean          bubbles;
  readonly attribute boolean          cancelable;
  readonly attribute DOMTimeStamp     timeStamp;
  void               stopPropagation();
  void               preventDefault();
  void               initEvent(in DOMString eventTypeArg, 
                               in boolean canBubbleArg, 
                               in boolean cancelableArg);
};

stopPropagation 阻止捕获和冒泡阶段中当前事件的进一步传播。
但是,它不能防止任何默认行为的发生; 例如,对链接的点击仍会被处理。
如果要停止这些行为,请参见 preventDefault 方法,它可以阻止事件触发后默认动作的发生。

User Interface Events

User Interface Event module 包含了于用户界面和文档操作相关的基本事件类型。

UI Event interface

[Constructor(DOMString type, optional UIEventInit eventInitDict)]
interface UIEvent : Event {
  readonly attribute Window? view;
  readonly attribute long detail;
};

dictionary UIEventInit : EventInit {
  Window? view = null;
  long detail = 0;
};

UI Event Types

Type Interface Sync/Async bubbles Trusted Cancelable Default action Context(trusted events)
load 如果从user interface 生成,为UIEvent,否则为Event Async No Windows, Document, Element No None
unload 如果从user interface 生成,为UIEvent,否则为Event Sync No Windows, Document, Element No None
abort 如果从user interface 生成,为UIEvent,否则为Event Sync No Windows, Element No None
error 如果从user interface 生成,为UIEvent,否则为Event Async No Windows, Element No None
select 如果从user interface 生成,为UIEvent,否则为Event Sync No Element No None

Focus Event

本节参考:
W3C DOM-Level-3 标准
MDN Focus Event

Interface Focus Event

[Constructor(DOMString type, optional FocusEventInit eventInitDict)]
interface FocusEvent : UIEvent {
  readonly attribute EventTarget? relatedTarget;
};
dictionary FocusEventInit : UIEventInit {
  EventTarget? relatedTarget = null;
};
Event Type	Notes

User shifts focus
1 focusin Sent before first target element receives focus
2 focus Sent after first target element receives focus
User shifts focus
3 focusout Sent before first target element loses focus
4 focusin Sent before second target element receives focus
5 blur Sent after first target element loses focus
6 focus Sent after second target element receives focus

Mouse Events

本节参考:
W3C DOM-Level-3 标准
MDN Mouse Event

Interface Mouse Event

[Constructor(DOMString type, optional MouseEventInit eventInitDict)]
interface MouseEvent : UIEvent {
  readonly attribute long screenX;
  readonly attribute long screenY;
  readonly attribute long clientX;
  readonly attribute long clientY;

  readonly attribute boolean ctrlKey;
  readonly attribute boolean shiftKey;
  readonly attribute boolean altKey;
  readonly attribute boolean metaKey;

  readonly attribute short button;
  readonly attribute unsigned short buttons;

  readonly attribute EventTarget? relatedTarget;

  boolean getModifierState(DOMString keyArg);
};

dictionary MouseEventInit : EventModifierInit {
  long screenX = 0;
  long screenY = 0;
  long clientX = 0;
  long clientY = 0;

  short button = 0;
  unsigned short buttons = 0;
  EventTarget? relatedTarget = null;
};

Wheel Events

本节参考:
W3C DOM-Level-3 标准
MDN Wheel Event

Interface Wheel Event

[Constructor(DOMString type, optional WheelEventInit eventInitDict)]
interface WheelEvent : MouseEvent {
  // DeltaModeCode
  const unsigned long DOM_DELTA_PIXEL = 0x00;
  const unsigned long DOM_DELTA_LINE  = 0x01;
  const unsigned long DOM_DELTA_PAGE  = 0x02;

  readonly attribute double deltaX;
  readonly attribute double deltaY;
  readonly attribute double deltaZ;
  readonly attribute unsigned long deltaMode;
};

WheelEvent 接口表示用户滚动鼠标滚轮或类似输入设备时触发的事件。

Input Events

本节参考:
W3C DOM-Level-3 标准
MDN InputEvent

Interface InputEvent

[Constructor(DOMString type, optional InputEventInit eventInitDict)]
interface InputEvent : UIEvent {
  readonly attribute DOMString data;
  readonly attribute boolean isComposing;
};

Keyboard Events

本节参考:
W3C DOM-Level-3 标准
MDN KeyboardEvent

Interface KeyboardEvent

[Constructor(DOMString type, optional KeyboardEventInit eventInitDict)]
interface KeyboardEvent : UIEvent {
  // KeyLocationCode
  const unsigned long DOM_KEY_LOCATION_STANDARD = 0x00;
  const unsigned long DOM_KEY_LOCATION_LEFT = 0x01;
  const unsigned long DOM_KEY_LOCATION_RIGHT = 0x02;
  const unsigned long DOM_KEY_LOCATION_NUMPAD = 0x03;

  readonly attribute DOMString key;
  readonly attribute DOMString code;
  readonly attribute unsigned long location;

  readonly attribute boolean ctrlKey;
  readonly attribute boolean shiftKey;
  readonly attribute boolean altKey;
  readonly attribute boolean metaKey;

  readonly attribute boolean repeat;
  readonly attribute boolean isComposing;

  boolean getModifierState(DOMString keyArg);
}

key: 保存了按下的键的键值。如果key是printed representation,必须是 non-empty unicode字符串;如果key是 control,必须是key values set中定义的键值之一;无法识别使用 Unidentified

code: 保存一个字符串,用于识别被按下的物理键,该值不受当前键盘布局或者修饰符状态的影响,因此特定键始终返回相同的值。

location: 包含key在设备上逻辑位置的表示 (DOM_KEY_LOCATION_STANDARD、DOM_KEY_LOCATION_LEFT、DOM_KEY_LOCATION_RIGHT、DOM_KEY_LOCATION_NUMPAD )

repeat:是否连续被按下

isComposing: 是否作为Composition Session的一部分发生

ctrlKey、shiftKey、altKey、metaKey:对应的修饰键是否被按下

initKeyEvent、initKeyboardEvent、char、keyCode、charCode、which、keyIdentifier、keyLocation 已被舍弃

Keyboard Event

keydown

同步、可冒泡、可取消、可组合

当key被按下的时候必须dispatch,keydown的事件类型是设备相关的,依赖于它们输入设备以及操作系统是如何映射的,必须在键映射以后生成,在beforeinput、input、keyup等关联在同一个键的事件dispatch之前被dispatch

默认操作:

  1. 如果key和character相关联,默认操作是调度beforeinput、input事件
  2. 如果key和 text composition system,默认操作是启动该系统
  3. 如果key是tab键,默认操作是将文档焦点从当前聚焦元素转移到新的聚焦元素上
  4. 如果key是Enter键或者空格,默认操作时调度click事件,如果支持还会调度DOMActivate

keyup
同步、可冒泡、可取消、可组合

样例: 请打开F12

Keyboard Events 依赖设备,即 它们依赖输入设备的能力和它们在操作系统中的映射方式

注意:Keyboard Events 提供了文本输入的一种方式,对于编辑场景,可以使用 Input Event 作为Keyboard Event的补充

Composition Event

本节参考
W3C DOM-Level-3 标准
MDN CompositionEvent

Interface CompositionEvent

[Constructor(DOMString type, optional CompositionEventInit eventInitDict)]
interface CompositionEvent : UIEvent {
  readonly attribute DOMString data;
};