1. 基础设施
本规范依赖于现行标准的基础设施标准。[INFRA]
本规范中使用的一些术语在编码、选择器、受信任类型、Web IDL、XML和XML中的命名空间中有定义。 [ENCODING] [SELECTORS4] [TRUSTED-TYPES] [WEBIDL] [XML] [XML-NAMES]
当需要扩展时,可以相应地更新 DOM 标准,或者可以编写一个新标准,该标准可以利用为 适用的规范 提供的可扩展性钩子。
1.1. 树
树 是一个有限的层次树结构。树的顺序是对树的先序、深度优先遍历。
参与树的对象有一个父节点,它要么是 null,要么是一个对象,并且有子节点,它是一个对象的有序集合。对象A的父节点是对象B,则A是B的子节点。
对象的根是它自己,如果它的父为null,否则它的根是它的父的根。树的根是参与该树的任意对象,而该对象的父为null。
如果对象A是对象B的子,或者对象A是对象C的子,而C是B的后代,则对象A被称为对象B的后代。
包含后代是指一个对象或其后代之一。
当且仅当B是A的后代时,称对象A为对象B的祖先。
包含祖先是指一个对象或其祖先之一。
当且仅当B和A共享相同的非空父节点时,称对象A为对象B的同胞。
包含同胞是指一个对象或其同胞之一。
如果A和B在同一个树中,并且A在树的顺序中位于B之前,则称对象A先于对象B。
如果A和B在同一个树中,并且A在树的顺序中位于B之后,则称对象A继于对象B。
一个对象的第一个子节点是其第一个子节点,如果它没有子节点,则为 null。
一个对象的最后一个子节点是其最后一个子节点,如果它没有子节点,则为 null。
一个对象的前一个同胞是指其第一个先于的同胞,如果没有,则为 null。
一个对象的下一个同胞是指其第一个继于的同胞,如果没有,则为 null。
1.2. 有序集合
有序集合解析器接受一个字符串input,然后执行以下步骤:
-
令inputTokens为在 ASCII 空白字符处分割input的结果。
-
令tokens为一个新的有序集合。
- 返回tokens。
有序集合序列化器接受一个set,并返回使用U+0020 SPACE连接的set的串联结果。
1.3. 选择器
给定字符串 selectors 和 节点 node,作用域匹配选择器字符串 的步骤如下:
-
令 selector 为 解析选择器 selectors 的结果。 [SELECTORS4]
-
如果 selector 返回失败,则 抛出一个 "
SyntaxError"DOMException。 -
返回 selector 与 node 的 根节点 通过 作用域根 node 进行 在树中匹配选择器 的结果。[SELECTORS4]。
不打算支持在选择器中使用命名空间,也不会添加此功能。
1.4. 名称验证
当一个字符串name满足下列步骤返回 true 时,称为有效的元素本地名:
此概念用于在通过 DOM API 构建时验证元素的本地名称。其意图是允许任何可以使用 HTML 解析器构造的名称(第一个码点是ASCII 字母的分支),以及一些额外的可能性。对于那些额外的可能性,出于历史原因,ASCII 范围受到限制,但超出 ASCII 的任何内容都是允许的。
以下与 JavaScript 兼容的正则表达式是有效元素本地名称的实现:
/^(?:[A-Za-z][^\0\t\n\f\r\u0020/>]*|[:_\u0080-\u{10FFFF}][A-Za-z0-9-.:_\u0080-\u{10FFFF}]*)$/u
一个字符串,如果它不包含ASCII 空白字符、 U+0000 NULL 或 U+003E (>),则它是一个有效的文档类型名称。
空字符串是一个有效的文档类型名称。
要验证并提取一个 namespace 和 qualifiedName,给定一个 context:
-
如果 namespace 是空字符串,则将其设置为 null。
-
将 prefix 设置为 null。
-
将 localName 设置为 qualifiedName。
-
如果 qualifiedName 包含 U+003A (:):
-
将 splitResult 设置为运行 严格拆分的结果,参数为 qualifiedName 和 U+003A (:)。
-
将 prefix 设置为 splitResult[0]。
-
将 localName 设置为 splitResult[1]。
-
如果 prefix 不是一个 有效的命名空间前缀,则 抛出一个 "
InvalidCharacterError"DOMException。
-
-
如果 context 是 "
attribute" 并且 localName 不是 有效的属性本地名称,则 抛出一个 "InvalidCharacterError"DOMException。 -
如果 context 是 "
element" 并且 localName 不是 有效的元素本地名称,则 抛出一个 "InvalidCharacterError"DOMException。 -
如果 prefix 不为 null 且 namespace 为 null,则 抛出一个 "
NamespaceError"DOMException。 -
如果 prefix 是 "
xml" 且 namespace 不是 XML 命名空间,则 抛出一个 "NamespaceError"DOMException。 -
如果 qualifiedName 或 prefix 是 "
xmlns" 并且 namespace 不是 XMLNS 命名空间,则 抛出一个 "NamespaceError"DOMException。 -
如果 namespace 是 XMLNS 命名空间 并且 qualifiedName 和 prefix 均不是 "
xmlns",则 抛出一个 "NamespaceError"DOMException。 -
返回 (namespace, prefix, localName)。
本规范中的各种 API 过去对命名空间前缀、属性本地名称、元素本地名称和文档类型名称的验证更为严格。这样做的方式与各种 XML 相关规范保持一致。(尽管并非所有这些规范中的规则都被强制执行。)
这被发现对 Web 开发人员来说很烦人,特别是因为这意味着有些名称可以通过 HTML 解析器创建,但不能通过 DOM API 创建。因此,验证已放宽到仅限于上述描述的那些。
2. 事件
2.1. “DOM 事件”简介
在整个 Web 平台中,事件被派发到对象,以标识发生的事件,例如网络活动或用户交互。这些对象实现了EventTarget接口,因此可以通过调用addEventListener()来添加事件监听器以观察事件:
obj. addEventListener( "load" , imgFetched) function imgFetched( ev) { // great success …}
事件监听器可以通过使用removeEventListener()方法删除,传递相同的参数。
或者,也可以通过将AbortSignal传递给addEventListener(),然后调用控制器上持有信号的abort()来删除事件监听器。
事件也是对象,并实现了Event接口(或派生接口)。在上面的例子中,ev是事件。ev作为参数传递给事件监听器的回调(通常是如上所示的JavaScript函数)。事件监听器通过事件的type属性值(上例中的"load")来区分事件。事件的target属性值返回事件被派发到的对象(如上例中的obj)。
虽然事件通常由用户代理在用户交互或某些任务完成时派发,但应用程序可以通过使用通常称为合成事件的方式派发事件。
// add an appropriate event listener obj. addEventListener( "cat" , function ( e) { process( e. detail) }) // create and dispatch the event var event= new CustomEvent( "cat" , { "detail" : { "hazcheeseburger" : true }}) obj. dispatchEvent( event)
除了用于传递信号外,事件有时也用于让应用程序控制操作中的后续步骤。例如,作为表单提交的一部分,type属性值为"submit"的事件被派发。如果调用了该事件的preventDefault()方法,则表单提交将被终止。希望通过应用程序事件(合成事件)派发该功能的应用程序,可以使用dispatchEvent()方法的返回值。
if ( obj. dispatchEvent( event)) { // event was not canceled, time for some magic …}
当一个事件被派发到一个参与树(例如,一个元素)的对象时,它也可以到达该对象的祖先上的事件监听器。实际上,该对象的所有包含祖先中捕获为true的事件监听器都将按照树的顺序被调用。然后,如果事件的bubbles为true,则该对象的所有包含祖先中捕获为false的事件监听器将按照相反的树的顺序被调用。
<!doctype html> < html > < head > < title > Boring example</ title > </ head > < body > < p > Hello< span id = x > world</ span > !</ p > < script > function test( e) { debug( e. target, e. currentTarget, e. eventPhase) } document. addEventListener( "hey" , test, { capture: true }) document. body. addEventListener( "hey" , test) var ev= new Event( "hey" , { bubbles: true }) document. getElementById( "x" ). dispatchEvent( ev) </ script > </ body > </ html >
debug函数将被调用两次。每次事件的target属性值将是span元素。第一次currentTarget属性值将是document,第二次将是body元素。eventPhase属性值将从CAPTURING_PHASE切换到BUBBLING_PHASE。如果为span元素注册了一个事件监听器,eventPhase属性值将是AT_TARGET。
2.2. 接口 Event
[Exposed=*]interface {Event (constructor DOMString ,type optional EventInit = {});eventInitDict readonly attribute DOMString type ;readonly attribute EventTarget ?target ;readonly attribute EventTarget ?srcElement ; // legacyreadonly attribute EventTarget ?currentTarget ;sequence <EventTarget >composedPath ();const unsigned short NONE = 0;const unsigned short CAPTURING_PHASE = 1;const unsigned short AT_TARGET = 2;const unsigned short BUBBLING_PHASE = 3;readonly attribute unsigned short eventPhase ;undefined stopPropagation ();attribute boolean cancelBubble ; // legacy alias of .stopPropagation()undefined stopImmediatePropagation ();readonly attribute boolean bubbles ;readonly attribute boolean cancelable ;attribute boolean