此文是W3C UI Events标准的阅读笔记。UI Events是一些列预定好的DOM事件,主要用来跟用户交互。

UI Events,后称UI事件体系,定义了一套用于用户交互的UI事件,以及该系列事件如何与DOM树交互。同时,UI事件体系还定义了了触发它们的图形控件们,以便不同的浏览器都实现一套具有相同事件属性的控件。

3. DOM事件架构

3. DOM Event Architecture

3.1章节描述了事件的派发机制,有一个非常直观的图。应用可以通过dispatchEvent派发一个事件。根据图形系统的工作机制,交互事件(鼠标、键盘)一般是先由窗口捕获,然后再通过宿主语言(HTML、XML、SVG等等)的DOM结构向后继节点派发,知道到达目标节点只会再反弹。这个传播的过程一共有三个阶段:前往目标节点途中(capture phase)、到达目标节点(target phase)、从目标节点返回(bubble phase)。事件对象带有propagation path属性,会记录其传播路径(从顶层节点到目标节点)。事件的传播是可控制的。事件可以被途中的某个节点截获,从而停止传播;也可以一开始就设置禁止事件的返回阶段。

事件可以有副作用。比如一个点击事件到达一个表单按键之后,默认会提交这个表单。默认的副作用可以被preventDefault()避免,避免之后defaultPrevented会返回true。具有这种特性的事件称为一个可撤销事件,其cancelable属性返回true。如果事件是通过dispatchEvent派发的,那么被撤销的事件会导致此函数返回false。

有一些事件的受众是共享资源,比如那些修改DOM树的事件。这些事件就需要进行协调,而协调是采用一种同步的机制。这些事件会被排在一个队列中,依次发送作用,这些事件称为同步事件。另外一些事件产生的效果互不影响,这些事件可以同时进行,这些事件称为异步事件。

事件可以有不同的来源,对于用户代理(User Agent,也就是浏览器)自己产生的事件比外部产生的事可信度要高。这些事件的isTrusted 会返回true。其他对于createEvent() initEvent() dispatchEvent() 等方法产生的事件,其isTrusted 返回false。可信事件对可以修改的资源范围大,权限高;而非可信事件则相反,通常没有默认动作,就像是preventDefault()被调用了的感觉。

一个反例是click事件,即便不可信,也会触发默认动作。

一些事件对象带有默认的事件激发行为( activation behavior )。比如当一个click事件作用于一个<a>元素,会激发其默认效果,也就是打开一个链接。基于事件的激发器大概有几种控制模式,定时控制、条件控制以及状态控制。

对于键盘事件和鼠标事件,它们的类型KeyboardEvent和MouseEvent在构造的时候可以接收额外的参数EventModifierInit ,主要用来表示在击键的时候,是否按下了修饰按键(比如CTRL、ALT、SHIFT等等)。随后可以通过getModifierState() 来获取修饰按键的状态。

dictionary EventModifierInit : UIEventInit {
  boolean ctrlKey = false;
  boolean shiftKey = false;
  boolean altKey = false;
  boolean metaKey = false;

  boolean modifierAltGraph = false;
  boolean modifierCapsLock = false;
  boolean modifierFn = false;
  boolean modifierFnLock = false;
  boolean modifierHyper = false;
  boolean modifierNumLock = false;
  boolean modifierScrollLock = false;
  boolean modifierSuper = false;
  boolean modifierSymbol = false;
  boolean modifierSymbolLock = false;
};

事件类型

4. Event Types

DOM支持多种事件组(Event Module)。UIEvents定义了下层设备相关的事件组,以及用于修改DOM文档的事件组。

用户界面事件组(UI Event Types)

用户界面事件的类型定义如下:

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

事件罗列(值得反复参考):

  • load(资源加载成功时派发)
  • unload(资源卸载时派发)
  • abort(资源加载失败)
  • error(无法解析加载的资源)
  • select(当用户选中一些文字)

有趣的是load是异步事件,而unload以及abort是同步事件。

输入焦点事件组(Focus Events)

事件定义如下:

[Constructor(DOMString type, optional FocusEventInit eventInitDict), Exposed=Window]
interface FocusEvent : UIEvent {
  readonly attribute EventTarget? relatedTarget;
};

焦点事件有时候会涉及到两个事件对象。比如焦点从一个输入框跳到另一个输入框的时候,这两个输入框都是相关的事件对象。relatedTarget参数用来添加第二事件对象。

焦点是操作系统提供的服务,用于指示当前接收键盘事件的对象。本规范中只定义的焦点事件范围仅限于浏览器的DOM的document之内。document可以有一至多个focus ring,用来把多个能接收焦点的子元素组织在一起。可以用TAB来在一个focus ring中切换焦点。不是所有的HTML元素都能够接收焦点。对于某个能够接收焦点的HTML元素,也不是所有状态下都能够接收焦点。

焦点事件类型:

  • blur
  • focus
  • focusin
  • focusout

这几个事件都是同步的

下面是无焦点 =》焦点已到目标一 =》 焦点移到目标二过程中产生的事件:

  1. focusin (目标一快要接收焦点)
  2. focus (目标一接收焦点)
  3. focusout(目标一快要丢失焦点)
  4. focusin(目标二快要接收焦点)
  5. blur(目标一丢失焦点)
  6. focus(目标二接收焦点)

(本篇完)