版权所有 © 2026 万维网联盟 (W3C)。W3C® 法律免责声明、商标及宽松文档许可规则适用。
指针事件规范定义了一个统一的、与硬件无关的框架,用于处理来自各种设备的输入,包括鼠标、触摸屏和触控笔。通过提供单一的事件集(例如 pointerdown、pointermove、pointerup),它允许开发者支持多种输入方式,而无需为每种设备编写特定的逻辑。
本规范还定义了鼠标和滚轮事件,以及将鼠标事件映射到其他指针设备类型的方法。
本节描述了本文件发布时的状态。当前的 W3C 出版物列表和本技术报告的最新版本可以在 W3C 标准和草案索引中找到。
本规范是对 [PointerEvents3] 规范的更新。它还包含了之前位于 [UIEVENTS] 规范中的鼠标和滚轮事件。
本修订版包含的新特性:
persistentDeviceId:为输入设备提供在多次交互中保持一致的标识符。touch-action 值:pan-left、pan-right、pan-up、pan-down本文档由 指针事件工作组 (Pointer Events Working Group) 作为工作草案发布,采用 推荐标准流程 (Recommendation track)。
发布为工作草案并不意味着 W3C 及其成员的认可。
这是一份草案文件,可能随时被其他文件更新、替换或废弃。将其作为进展中的工作以外的引用是不恰当的。
本文档由在 W3C 专利政策下运作的组织编写。W3C 维护一份与该组交付成果相关的专利披露公开列表;该页面还包括披露专利的说明。任何知悉某项专利并认为其包含 必要权利要求 (Essential Claim(s)) 的个人,必须按照 W3C 专利政策第 6 节的要求披露该信息。
本文件受 2025 年 8 月 18 日 W3C 流程文档约束。
本节是非规范性的。
目前,大多数 [HTML] 内容均与鼠标输入一起使用或为此设计。那些以自定义方式处理输入的通常会按照 [UIEVENTS] 的鼠标事件进行编码。然而,当今较新的计算设备集成了其他输入形式,包括触摸屏和手写笔输入。已经提出了分别处理这些输入形式的事件类型。但是,这种方法在添加新输入类型支持时,通常会导致逻辑重复和事件处理开销。当内容仅针对一种设备类型编写时,这往往会产生兼容性问题。此外,为了与现有的基于鼠标的内容兼容,大多数 用户代理 (user agents) 会针对所有输入类型触发鼠标事件。这使得鼠标事件代表的是真实的鼠标设备,还是为了兼容性由其他输入类型产生的,变得难以区分,从而难以同时针对两种设备类型进行编码。
为了降低针对多种输入类型进行编码的成本,并缓解上述鼠标事件的歧义,本规范定义了一种更抽象的输入形式,称为 指针 (pointer)。指针可以是鼠标光标、触控笔、触摸(包括多点触控)或其他指针输入设备在屏幕上产生的任何接触点。这种模型使得编写在用户使用任何硬件时都能良好运行的网站和应用程序变得更加容易。对于需要设备特定处理的场景,本规范还定义了用于检查产生事件的设备类型的属性。主要目标是提供一组统一的事件和接口,以便更轻松地编写跨设备的指针输入,同时仅在必要时才允许进行特定于设备的处理以提升体验。
另一个关键目标是使多线程用户代理能够在不阻塞脚本执行的情况下处理用于平移和缩放(例如在触摸屏上用手指或触控笔)的 直接操作 (direct manipulation) 行为。
虽然本规范为各种指针输入定义了一个统一的事件模型,但该模型并未涵盖键盘或类键盘接口等其他形式的输入(例如在仅限触摸屏的设备上运行的屏幕阅读器或类似的辅助技术,它允许用户在可聚焦的控件和元素之间进行顺序导航)。虽然用户代理可能会选择针对这些接口也生成指针事件,但本规范并未涵盖此场景。
首先,鼓励作者通过响应高级事件(如 focus、blur 和 click)来为所有输入形式提供等效功能。然而,当使用低级事件(如指针事件)时,鼓励作者确保支持所有类型的输入。对于键盘和类键盘接口,这可能需要添加显式的键盘事件处理。有关详细信息,请参阅 [WCAG22] 中的 键盘可访问性 (Keyboard Accessible)。
用于处理通用指针输入的事件看起来与鼠标事件非常相似:pointerdown、pointermove、pointerup、pointerover、pointerout 等。这促进了内容从鼠标事件到指针事件的轻松迁移。指针事件除了提供鼠标事件中常见的所有属性(包括客户端坐标、目标元素、按钮状态)外,还提供了用于其他输入形式(如压力、接触几何形状、倾斜)的新属性。作者可以轻松地编写指针事件逻辑,在合理的情况下共享不同输入类型之间的逻辑,并仅在必要时自定义特定类型的输入以获得最佳体验。
虽然指针事件源自各种输入设备,但它们并未定义为由其他设备特定的事件集生成。尽管为了兼容性可能会且受鼓励这样做,但本规范并不要求支持其他设备特定的事件(例如鼠标事件或触摸事件)。用户代理可以在不支持任何其他设备事件的情况下支持指针事件。为了与针对鼠标特定事件编写的内容兼容,本规范确实提供了一个可选章节,描述了如何根据除鼠标以外的设备的指针输入来生成 兼容性鼠标事件 (compatibility mouse events)。
本规范未提供关于支持触摸事件(如 [TOUCH-EVENTS] 中定义的)和指针事件的用户代理的预期行为的任何建议。有关这两个规范之间关系的更多信息,请参阅 触摸事件社区组 (Touch Events Community Group)。
除了标记为非规范性的章节外,本规范中的所有创作指南、图表、示例和注释均为非规范性内容。本规范中的其他所有内容均为规范性内容。
本文档中的关键词 MAY(可能)、MUST(必须)、MUST NOT(不得)、OPTIONAL(可选)和 SHOULD(应该)仅在全大写显示时,按照 [RFC2119] 和 [RFC8174] 中的描述进行解释。
本节是非规范性的。
以下是演示作者如何使用本规范中部分 API 的基础示例。此外,本文档的相关章节中提供了更具体的示例。
/* Bind to either Pointer Events or traditional touch/mouse */
if (window.PointerEvent) {
// if Pointer Events are supported, only listen to pointer events
target.addEventListener("pointerdown", function(e) {
// if necessary, apply separate logic based on e.pointerType
// for different touch/pen/mouse behavior
...
});
...
} else {
// traditional touch/mouse event handlers
target.addEventListener('touchstart', function(e) {
// prevent compatibility mouse events and click
e.preventDefault();
...
});
...
target.addEventListener('mousedown', ...);
...
}
// additional event listeners for keyboard handling
...
window.addEventListener("pointerdown", detectInputType);
function detectInputType(event) {
switch(event.pointerType) {
case "mouse":
/* mouse input detected */
break;
case "pen":
/* pen/stylus input detected */
break;
case "touch":
/* touch input detected */
break;
default:
/* pointerType is empty (could not be detected)
or UA-specific custom type */
}
}
<div style="position:absolute; top:0px; left:0px; width:100px;height:100px;"></div>
<script>
window.addEventListener("pointerdown", checkPointerSize);
function checkPointerSize(event) {
event.target.style.width = event.width + "px";
event.target.style.height = event.height + "px";
}
</script>
const event1 = new PointerEvent("pointerover",
{ bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500
});
eventTarget.dispatchEvent(event1);
let pointerEventInitDict =
{
bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500,
};
const p1 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.clientX += 10;
const p2 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.coalescedEvents = [p1, p2];
const event2 = new PointerEvent("pointermove", pointerEventInitDict);
eventTarget.dispatchEvent(event2);
<div style="position:absolute; top:0px; left:0px; width:100px;height:100px;"></div>
<script>
window.addEventListener("pointerdown", assignPenColor);
window.addEventListener("pointermove", assignPenColor);
const colorMap = new Map();
function assignPenColor(event) {
const uniqueId = event.persistentDeviceId;
// Check if a unique Id exists.
if (uniqueId == 0) {
return;
}
// Check if a color has been assigned to the device.
if (map.has(uniqueId)) {
return;
}
// Assign a color to the device.
let newColor = getNewColor();
map.set(uniqueId, newColor);
return newColor;
}
function getNewColor() {
/* return some color value */
}
</script>
鼠标事件模块源自 [HTML401] 的 onclick、ondblclick、onmousedown、onmouseup、onmouseover、onmousemove 和 onmouseout 属性。此事件模块专门为鼠标或轨迹球等指针输入设备而设计。
引入于 DOM Level 2,在本规范中进行了修改。
MouseEvent 接口提供了与鼠标事件相关的具体上下文信息。
对于嵌套元素,鼠标事件始终以嵌套最深的元素为目标。
目标元素的祖先可以使用事件冒泡来获得在其后代元素内发生的鼠标事件的通知。
要创建 MouseEvent 接口的实例,请使用 MouseEvent 构造函数,并传入可选的 MouseEventInit 字典。
当使用 initMouseEvent 初始化 MouseEvent 对象时,实现可以使用客户端坐标 clientX 和 clientY 来计算其他坐标(例如 DOM Level 0 实现暴露的目标坐标或其他专有属性,如 pageX)。
WebIDL[Exposed=Window]
interface MouseEvent : UIEvent {
constructor(DOMString type, optional MouseEventInit eventInitDict = {});
readonly attribute long screenX;
readonly attribute long screenY;
readonly attribute long clientX;
readonly attribute long clientY;
readonly attribute long layerX;
readonly attribute long layerY;
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;
boolean getModifierState(DOMString keyArg);
};
screenX事件发生的水平坐标,相对于屏幕坐标系统的原点。
此属性的 未初始化值 (un-initialized value) MUST 为 0。
screenY事件发生的垂直坐标,相对于屏幕坐标系统的原点。
此属性的 未初始化值 (un-initialized value) MUST 为 0。
clientX事件发生的水平坐标,相对于与该事件关联的视口。
此属性的 未初始化值 (un-initialized value) MUST 为 0。
clientY事件发生的垂直坐标,相对于与该事件关联的视口。
此属性的 未初始化值 (un-initialized value) MUST 为 0。
layerX相对于最近的 祖先 元素的水平偏移,该祖先元素必须是 堆叠上下文 (stacking context)、已 定位 (positioned),或在 绘制堆叠上下文 时在定位阶段进行绘制。
此属性的 未初始化值 (un-initialized value) MUST 为 0。
layerY相对于最近的 祖先 元素的垂直偏移,该祖先元素必须是 堆叠上下文、已 定位,或在 绘制堆叠上下文 时在定位阶段进行绘制。
此属性的 未初始化值 (un-initialized value) MUST 为 0。
ctrlKey参考 KeyboardEvent 的 ctrlKey 属性。
此属性的 未初始化值 MUST 为 false。
shiftKey参考 KeyboardEvent 的 shiftKey 属性。
此属性的 未初始化值 MUST 为 false。
altKey参考 KeyboardEvent 的 altKey 属性。
此属性的 未初始化值 MUST 为 false。
metaKey参考 KeyboardEvent 的 metaKey 属性。
此属性的 未初始化值 MUST 为 false。
button在按下或释放鼠标按钮引起的鼠标事件期间,button MUST 用于指示哪个指针设备按钮改变了状态。
button 属性的值 MUST 如下:
0 MUST 表示设备的主按钮(通常是左键或单键设备上的唯一按钮,用于激活用户界面控件或选择文本)或未初始化值。1 MUST 表示辅助按钮(通常是中键,常与鼠标滚轮结合使用)。2 MUST 表示次要按钮(通常是右键,常用于显示上下文菜单)。3 MUST 表示 X1(后退)按钮。4 MUST 表示 X2(前进)按钮。某些指针设备提供或模拟更多按钮状态,MAY 使用大于 2 或小于 0 的值来表示此类按钮。
button 的值不会为非鼠标按钮按下/释放引起的事件更新。在这些场景中,请注意不要将值 0 解释为左键,而应将其视为默认值。
某些与 mousedown 和 mouseup 等事件相关的 默认行为 (default actions) 取决于所使用的特定鼠标按钮。
此属性的 未初始化值 (un-initialized value) MUST 为 0。
按钮在任何鼠标事件期间,buttons MUST 用于指示当前按下鼠标按钮的组合,以位掩码 (bitmask) 的形式表示。
尽管命名相似,buttons 属性和 button 属性的值截然不同。button 的值在 mousedown / mouseup 事件处理程序期间被认为是有效的,而 buttons 属性反映了任何受信任的 MouseEvent 对象在被分发时鼠标按钮的状态(因为它能表示“当前无激活按钮”状态,即 0)。
buttons 属性的值 MUST 如下:
0 MUST 表示当前没有激活的按钮。1 MUST 表示设备的主按钮(通常是左键或单键设备上的唯一按钮,用于激活用户界面控件或选择文本)。2 MUST 表示次要按钮(通常是右键,常用于显示上下文菜单),如果存在的话。4 MUST 表示辅助按钮(通常是中键,常与鼠标滚轮结合使用)。一些指针设备提供或模拟更多按钮。为了表示此类按钮,对于每个连续的按钮,该值 MUST 加倍(按照二进制系列 8, 16, 32, ...)。
因为任何一组按钮值的总和都是唯一的数字,所以内容作者可以使用按位运算来确定当前按下了多少个按钮以及是哪些按钮,即使设备上有任意数量的鼠标按钮。例如,值 3 表示当前同时按下了左键和右键,而值 5 表示当前同时按下了左键和中键。
此属性的 未初始化值 (un-initialized value) MUST 为 0。
relatedTarget用于识别与 UI 事件相关的次要 EventTarget,具体取决于事件类型。
此属性的 未初始化值 MUST 为 null。
使用键值查询修饰符的状态。
如果是修饰键且该修饰符已激活,则返回 true,否则返回 false。
DOMString keyArgKeyboardEvent 的 getModifierState() 方法。WebIDLdictionary MouseEventInit : EventModifierInit {
long screenX = 0;
long screenY = 0;
long clientX = 0;
long clientY = 0;
short button = 0;
unsigned short buttons = 0;
};
screenX将 MouseEvent 对象的 screenX 属性初始化为用户屏幕上鼠标指针所需的水平相对位置。
将事件对象初始化为给定的鼠标位置不得移动用户的鼠标指针到初始化位置。
screenY将 MouseEvent 对象的 screenY 属性初始化为用户屏幕上鼠标指针所需的垂直相对位置。
将事件对象初始化为给定的鼠标位置不得移动用户的鼠标指针到初始化位置。
clientX将 MouseEvent 对象的 clientX 属性初始化为鼠标指针相对于用户浏览器客户端窗口所需的水平位置。
将事件对象初始化为给定的鼠标位置不得移动用户的鼠标指针到初始化位置。
clientY将 MouseEvent 对象的 clientY 属性初始化为鼠标指针相对于用户浏览器客户端窗口所需的垂直位置。
将事件对象初始化为给定的鼠标位置不得移动用户的鼠标指针到初始化位置。
button将 MouseEvent 对象的 button 属性初始化为表示鼠标按钮所需状态的数字。
值 0 用于表示主要鼠标按钮,1 用于表示辅助/中鼠标按钮,2 用于表示右侧鼠标按钮。大于 2 的数字也是可能的,但在本文档中未指定。
按钮将 MouseEvent 对象的 buttons 属性初始化为表示被视为激活的一个 或多个 鼠标按钮的数字。
buttons 属性是一个位字段。如果掩码值 1 在应用于位字段值时为真,则主鼠标按钮已按下。如果掩码值 2 在应用于位字段值时为真,则右侧鼠标按钮已按下。如果掩码值 4 在应用于位字段值时为真,则辅助/中间按钮已按下。
在 JavaScript 中,要将 buttons 属性初始化为仿佛右键 (2) 和中键 (4) 同时被按下,可以将 buttons 值指定为
{ buttons: 2 | 4 }
或者
{ buttons: 6 }
relatedTargetrelatedTarget 应初始化为鼠标指针刚刚离开其边界的元素(在 mouseover 或 mouseenter 事件的情况下),或者是鼠标指针正进入的元素(在 mouseout 或 mouseleave 或 focusout 事件的情况下)。对于其他事件,此值不需要分配(默认为 null)。
实现 MUST 在生成鼠标事件时维护 当前点击计数 (current click count)。这 MUST 是一个非负整数,指示在特定时间内指向设备按钮的连续点击次数。重置计数之前的延迟取决于环境配置。
本节中的算法假设原生平台操作系统将提供以下内容:
对于这些事件,操作系统将能够提供以下信息:
本节需要修订。
通常,当 Event 接口或继承自 Event 接口的接口的构造函数被调用时,应遵循 [DOM] 中描述的步骤。但是,MouseEvent 接口提供了额外的字典成员,用于初始化 Event 对象的按键修饰符内部状态:具体而言,是使用 getModifierState() 方法查询的内部状态。本节补充了 [DOM] 中初始化新的 MouseEvent 对象以包含这些可选修饰符状态的步骤。
为了构建 MouseEvent 或使用以下算法从这些对象派生的对象,所有 MouseEvent 及派生对象都具有 内部按键修饰符状态 (internal key modifier state),可以使用 [UIEvents-Key] 中 修饰键表格 (Modifier Keys table) 中描述的 按键修饰符名称 (key modifier names) 进行设置和检索。
以下步骤补充了 [DOM] 中定义的构造事件的算法:
Event 是 MouseEvent 对象或从其派生的对象,并且构造函数提供了 EventModifierInit 参数,则执行以下子步骤:EventModifierInit 参数,如果字典成员以字符串 "modifier" 开头,则让 按键修饰符名称 (key modifier name) 为字典成员名称(去掉前缀 "modifier"),并将 Event 对象的 内部按键修饰符状态 中匹配该 按键修饰符名称 的项设置为相应的值。本节需要修订。
UA 必须维护以下在整个用户代理中共享的值:
一个用于追踪鼠标按钮当前状态的 鼠标按钮位掩码 (mouse button bitmask)。
UA 必须维护以下在窗口中共享的值:
一个 上一个鼠标元素 (last mouse element) 值(初始未定义),用于追踪我们发送 MouseEvent 到的上一个 Element。
一个 上一个鼠标 DOM 路径 (last mouse DOM path) 值(初始为空),该值包含最近一次发送鼠标事件时 上一个鼠标元素 的祖先 Element 元素的快照。
本节需要修订。
MouseEvent 具有以下用于追踪各种修饰键状态的内部标志:Shift 标志、Control 标志、Alt 标志、AltGraph 标志 和 Meta 标志。如果在鼠标事件发生时按下了相应的修饰键,则设置这些标志。
本节需要修订。
elementFromPoint() 作用于 pos 的结果(pos 处最前面的 DOM 元素)。为了考虑 惰性 (inert) 或 禁用 (disabled) 元素,这应调用 elementsFromPoint() 并拒绝无效元素。
MouseEvent本节需要修订。
要使用 event、eventType、eventTarget、bubbles 和 cancelable 初始化 MouseEvent,请执行以下步骤:
screenX 设置为事件发生的坐标相对于桌面原点的 x 坐标。screenY 设置为事件发生的坐标相对于桌面原点的 y 坐标。clientX 设置为事件发生的坐标相对于 视口 (viewport) 原点的 x 坐标。clientY 设置为事件发生的坐标相对于 视口 原点的 y 坐标。button 设置为 0。buttons 设置为 鼠标按钮位掩码。我们应该为 PointerLock 提供一个钩子,而不是在这里硬编码它。
本节需要修订。
MouseEvent。shiftKey 设置为 true,否则为 false。ctrlKey 设置为 true,否则为 false。altKey 设置为 true,否则为 false。metaKey 设置为 true,否则为 false。本节需要修订。
MouseEvent 类型的 DOMString。EventTarget。MouseEvent 创建事件 的结果。本节需要修订。
MouseEvent 类型的 DOMString。EventTarget。MouseEvent 创建事件 的结果。本节需要修订。
MouseEvent。待办 (TODO)。
type 是 [ mousedown, mouseup ] 之一,则:button 设置为 计算 MouseEvent button 属性 的结果(传入 mbutton)。本节需要修订。
其他按钮可以从 0x08 开始添加。
本节需要修订。
其他鼠标事件可能发生在 mousedown 和 mouseup 之间。
本节需要修订。
本节需要修订。
EventTarget。screenX 不是整数值,则四舍五入。screenY 不是整数值,则四舍五入。有关使用指针事件和舍入坐标的浏览器的信息,请参阅 pointerevents/100。
任何“默认行为”在分发期间通过触发目标的 激活行为 (activation behavior) 算法来处理。因此,无需在此处处理。但是,需要验证现有规范是否处理了已禁用/css-pointer-events/惰性/...的情况。
要处理 HTMLelement.click(),请以 native = null 和 target = HTMLelement 调用此算法。
要处理键盘触发的点击,请以 native = null 和 target = 当前聚焦元素调用此算法。
本节需要修订。
对于生成双击的鼠标点击,应在“处理原生鼠标点击”之后立即调用此算法。
screenX 不是整数值,则四舍五入。screenY 不是整数值,则四舍五入。本节需要修订。
此算法对指针事件的分发做出了假设,因为它们目前尚未明确指定。一旦 pointerevents/285 得到解决,这可能需要更新。
待办:从 native 设置 mouseout 属性。+CSSOM 属性。
验证取消时的行为(似乎没有影响)。
处理 element 已被删除的情况。以及它已被移动的情况:DOM 变异是否应该触发 mouseleave 事件?我们现在应该发送它吗?它应该被丢弃吗?需要验证当前浏览器的行为。
Event.composed = false。检查兼容性:event.composed 的值。规范说 false。Chrome/Linux = true。Firefox/Linux = false。
待办:从 native 设置 mouseout 属性。+CSSOM 属性。
需要验证取消时的行为(似乎没有影响)。
处理 element 已被删除或移动的情况。
Event.composed = false。检查兼容性:event.composed 的值。规范说 false。Chrome/Linux = true。Firefox/Linux = false。
检查 Shadow DOM 元素的兼容性。Chrome/Linux 在元素和 shadow root 上触发此事件。
本规范定义的某些鼠标事件 MUST 相互以特定顺序发生。以下显示了当指向设备的指针移动到元素上时 MUST 发生的事件序列:
| # | 事件类型 | 元素 | 注 |
|---|---|---|---|
| 1 | mousemove
| ||
| 指针设备移动到元素 A 中... | |||
| 2 | mouseover
| A | |
| 3 | mouseenter
| A | |
| 4 | mousemove
| A | 多个 mousemove 事件 |
| 指针设备移动到元素 A 外... | |||
| 5 | mouseout
| A | |
| 6 | mouseleave
| A |
当指针设备移动到一个元素 A 中,然后进入嵌套元素 B,再移出时,MUST 发生以下事件序列:
| 事件类型 | 元素 | 注 | |
|---|---|---|---|
| 1 | mousemove
| ||
| 指针设备移动到元素 A 中... | |||
| 2 | mouseover
| A | |
| 3 | mouseenter
| A | |
| 4 | mousemove
| A | 多个 mousemove 事件 |
| 指针设备移动到嵌套元素 B 中... | |||
| 5 | mouseout
| A | |
| 6 | mouseover
| B | |
| 7 | mouseenter
| B | |
| 8 | mousemove
| B | 多个 mousemove 事件 |
| 指针设备从元素 B 移动到 A 中... | |||
| 9 | mouseout
| B | |
| 10 | mouseleave
| B | |
| 11 | mouseover
| A | |
| 12 | mousemove
| A | 多个 mousemove 事件 |
| 指针设备移动到元素 A 外... | |||
| 13 | mouseout
| A | |
| 14 | mouseleave
| A |
有时元素可以使用 CSS 在视觉上重叠。在下面的示例中,标记为 A、B 和 C 的三个元素在网页上具有相同的尺寸和绝对位置。在 DOM 中,元素 C 是 B 的子元素,B 是 A 的子元素:
当指针设备从元素堆栈外部移动到标记为 C 的元素,然后再次移出时,MUST 发生以下事件系列:
| 事件类型 | 元素 | 注 | |
|---|---|---|---|
| 1 | mousemove
| ||
| 指针设备移动到元素 C 中,它是堆栈中的最顶层元素 | |||
| 2 | mouseover
| C | |
| 3 | mouseenter
| A | |
| 4 | mouseenter
| B | |
| 5 | mouseenter
| C | |
| 6 | mousemove
| C | 多个 mousemove 事件 |
| 指针设备移动到元素 C 外... | |||
| 7 | mouseout
| C | |
| 8 | mouseleave
| C | |
| 9 | mouseleave
| B | |
| 10 | mouseleave
| A |
mouseover/mouseout 事件仅触发一次,而 mouseenter/mouseleave 事件触发了三次(每个元素一次)。
以下是当定点设备(例如鼠标或触控板)的关联按钮在元素上方按下并释放时,典型的时间序列。
| 事件类型 | 注 | |
|---|---|---|
| 1 | mousedown
| |
| 2 | mousemove
| 可选,多个事件,存在一些限制 |
| 3 | mouseup
| |
| 4 | click
| |
| 5 | mousemove
| 可选,多个事件,存在一些限制 |
| 6 | mousedown
| |
| 7 | mousemove
| 可选,多个事件,存在一些限制 |
| 8 | mouseup
| |
| 9 | click
| |
| 10 | dblclick
|
在 mousedown 和 mouseup 事件之间允许的 mousemove 事件的滞后时间、程度、距离和数量,在触发 click 或 dblclick 事件时,将取决于具体实现、设备和平台。这种容差可以帮助那些手部不稳等有身体残障的用户在使用定点设备时进行交互。
每个实现都将确定适当的 滞后(hysteresis) 容差,但通常情况下 应该 在关联的 mousedown 和 mouseup 事件的目标元素相同时,且中间没有 mouseout 或 mouseleave 事件介入时,触发 click 和 dblclick 事件;当关联的 mousedown 和 mouseup 事件的目标元素不同时,应该 在最近的共同包含祖先元素上触发 click 和 dblclick 事件。
如果 mousedown 事件的目标是 HTML 文档的 body 元素,而对应的 mouseup 事件的目标是 文档元素,那么 click 事件将被分派给 文档元素,因为它是最近的共同包含祖先。
如果在鼠标事件序列期间 目标(例如目标元素)被从 DOM 中移除,则该序列的其余事件 不得 在该元素上触发。
如果目标元素因 mousedown 事件而从 DOM 中移除,则不会为该元素分派后续的 mouseup、click 或 dblclick 事件,也不会分派任何默认激活事件。但是,mouseup 事件仍会在初始目标元素被移除后暴露在鼠标下的元素上分派。同样,如果目标元素在 mouseup 事件分派期间被从 DOM 中移除,则 click 及后续事件将不会被分派。
| 类型 | auxclick
|
|---|---|
| Interface | PointerEvent
|
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 是 |
| 可组合(Composed) | 是 |
| 默认操作 | 不同 |
| 上下文 (受信任事件) |
|
auxclick 事件类型 必须 在用户按下并释放非主要指针按钮,或以模拟此类操作的方式激活指针时,在由指针指示的 最顶层事件目标 上分派。鼠标按钮的触发方式取决于指针设备和环境配置,例如,它 可能 取决于屏幕位置或定点设备按钮按下与释放之间的延迟。
auxclick 事件应仅针对非主要指针按钮触发(即当 button 值不为 0,buttons 值大于 1 时)。主要按钮(如标准鼠标上的左键) 不得 触发 auxclick 事件。有关关联主要按钮的相应事件,请参阅 click。
auxclick 事件之前 可能 会在同一元素上伴随 mousedown 和 mouseup 事件,而不考虑其他节点类型(例如文本节点)之间的变化。根据环境配置,如果 mouseover、mousemove 和 mouseout 中的一个或多个事件类型在定点设备按钮按下与释放之间发生,则 可能 会分派 auxclick 事件。
auxclick 事件类型的 默认操作 根据事件的 目标 以及 button 或 buttons 属性的值而有所不同。auxclick 事件类型的典型 默认操作 如下:
myLink.addEventListener("auxclick", function(e) {
if (e.button === 1) {
// This would prevent the default behavior which is for example
// opening a new tab when middle clicking on a link.
e.preventDefault();
// Do something else to handle middle button click like taking
// care of opening link or non-link buttons in new tabs in a way
// that fits the app. Other actions like closing a tab in a tab-strip
// which should be done on the click action can be done here too.
}
});
对于右键,auxclick 事件在任何 contextmenu 事件之后分派。请注意,某些用户代理在显示上下文菜单时会吞掉所有输入事件,因此在这种情况下,auxclick 可能无法被应用程序获取。请参阅 示例 7 以获取更多说明。
myDiv.addEventListener("contextmenu", function(e) {
// This call makes sure no context menu is shown
// to interfere with page receiving the events.
e.preventDefault();
});
myDiv.addEventListener("auxclick", function(e) {
if (e.button === 2) {
// Do something else to handle right button click like opening a
// customized context menu inside the app.
}
});
| 类型 | click
|
|---|---|
| Interface | PointerEvent
|
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 是 |
| 可组合(Composed) | 是 |
| 默认操作 | 不同 |
| 上下文 (受信任事件) |
|
click 事件类型 必须 在用户按下并释放主要指针按钮,或以模拟此类操作的方式激活指针时,在由指针指示的 最顶层事件目标 上分派。鼠标按钮的触发方式取决于指针设备和环境配置,例如,它 可能 取决于屏幕位置或定点设备按钮按下与释放之间的延迟。
click 事件应仅针对主要指针按钮触发(即当 button 值是 0,buttons 值是 1 时)。次要按钮(如标准鼠标上的中键或右键) 不得 触发 click 事件。有关关联非主要按钮的相应事件,请参阅 auxclick。
click 事件之前 可能 会在同一元素上伴随 mousedown 和 mouseup 事件,而不考虑其他节点类型(例如文本节点)之间的变化。根据环境配置,如果 mouseover、mousemove 和 mouseout 中的一个或多个事件类型在定点设备按钮按下与释放之间发生,则 可能 会分派 click 事件。click 事件之后 可能 还会紧随 dblclick 事件。
如果用户在一个 <p> 元素的文本节点子项上按下鼠标(该元素已使用较大的 line-height 设置样式),稍微移动鼠标使其不再覆盖包含文本的区域,但仍在该 <p> 元素的包含块内(即指针位于同一文本块的行之间,但并未直接覆盖文本节点本身),然后随后释放鼠标,这很可能会触发 click 事件(如果它落在 click 的正常时间 滞后(hysteresis) 范围内),因为用户仍保留在同一元素的作用域内。请注意,用户代理生成的鼠标事件不会在文本节点上分派。
除了与指针设备关联外,click 事件类型 必须 作为元素激活的一部分进行分派。
为了实现最大的可访问性,鼓励内容作者在为自定义控件定义激活行为时使用 click 事件类型,而不是其他更具设备特异性的定点设备事件类型(如 mousedown 或 mouseup)。尽管 click 事件类型起源于指针设备(如鼠标),但后续的实现增强已将其扩展到该关联之外,它可以被视为一种用于元素激活的设备无关事件类型。
click 事件类型的 默认操作 根据事件的 目标 以及 button 或 buttons 属性的值而有所不同。click 事件类型的典型 默认操作 如下:
| 类型 | dblclick |
|---|---|
| Interface | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 是 |
| 可组合(Composed) | 是 |
| 默认操作 | 无 |
| 上下文 (受信任事件) |
|
当定点设备的主要按钮在元素上方被点击两次时,用户代理 必须 分派此事件。双击的定义取决于环境配置,除了事件目标 必须 在 mousedown、mouseup 和 dblclick 之间保持相同。如果点击和双击同时发生,此事件类型 必须 在 click 事件类型之后分派,否则在 mouseup 事件类型之后分派。
与 click 事件一样,dblclick 事件应仅针对主要指针按钮触发。次要按钮 不得 触发 dblclick 事件。
click 事件类型一样,dblclick 事件类型的 默认操作 根据事件的 目标 以及 button 或 buttons 属性的值而有所不同。dblclick 事件类型的典型 默认操作 与 click 事件类型的操作匹配。| 类型 | mousedown
|
|---|---|
| Interface | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 是 |
| 可组合(Composed) | 是 |
| 默认操作 | 不同:开始拖放操作;开始文本选择;开始滚动/平移交互(如果支持,结合鼠标中键使用) |
| 上下文 (受信任事件) |
|
| 类型 | mouseenter
|
|---|---|
| Interface | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | No |
| 受信任的目标 | 元素 |
| 可取消 | No |
| 可组合(Composed) | No |
| 默认操作 | 无 |
| 上下文 (受信任事件) |
|
mouseover,但区别在于它不会冒泡,并且当指针设备从一个元素移动到其后代元素的边界时,不得 分派此事件。此事件类型与 CSS :hover 伪类 [CSS2] 之间有相似之处。另请参阅 mouseleave 事件类型。
| 类型 | mouseleave
|
|---|---|
| Interface | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | No |
| 受信任的目标 | 元素 |
| 可取消 | No |
| 可组合(Composed) | No |
| 默认操作 | 无 |
| 上下文 (受信任事件) |
|
mouseout,但区别在于它不会冒泡,并且直到定点设备离开该元素及其所有子元素的边界之前,不得 分派此事件。此事件类型与 CSS :hover 伪类 [CSS2] 之间有相似之处。另请参阅 mouseenter 事件类型。
| 类型 | mousemove
|
|---|---|
| Interface | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 是 |
| 可组合(Composed) | 是 |
| 默认操作 | 无 |
| 上下文 (受信任事件) |
|
mousemove 事件,而不是为每次鼠标移动触发单个事件。鼓励各实现确定最佳频率,以平衡响应性和性能。在某些实现环境(如浏览器)中,如果用户开始了拖拽操作(例如按下了鼠标按钮)并且定点设备离开了用户代理的边界,mousemove 事件可能会继续触发。
此事件在 DOM Level 2 Events 中曾被指定为不可取消,但后来更改为反映用户代理之间现有的互操作性。
| 类型 | mouseout
|
|---|---|
| Interface | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 是 |
| 可组合(Composed) | 是 |
| 默认操作 | 无 |
| 上下文 (受信任事件) |
|
mouseleave,但不同之处在于它会冒泡,且当定点设备从一个元素移动到其子元素边界上时,它 必须被分发。另请参阅 mouseover 事件类型。
| 类型 | mouseover
|
|---|---|
| Interface | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 是 |
| 可组合(Composed) | 是 |
| 默认操作 | 无 |
| 上下文 (受信任事件) |
|
mouseenter,但不同之处在于它会冒泡,且当定点设备移动到其祖先元素为同一 事件监听器 实例的 目标 的元素边界上时,它 必须被分发。另请参阅 mouseout 事件类型。
| 类型 | mouseup
|
|---|---|
| Interface | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 是 |
| 可组合(Composed) | 是 |
| 默认操作 | 无 |
| 上下文 (受信任事件) |
|
在某些实现环境(如浏览器)中,即使定点设备已经离开了用户代理的边界,也可以分发 mouseup 事件,例如如果用户在按下鼠标按钮的情况下启动了拖拽操作。
WebIDLdictionary PointerEventInit : MouseEventInit {
long pointerId = 0;
double width = 1;
double height = 1;
float pressure = 0;
float tangentialPressure = 0;
long tiltX;
long tiltY;
long twist = 0;
double altitudeAngle;
double azimuthAngle;
DOMString pointerType = "";
boolean isPrimary = false;
long persistentDeviceId = 0;
sequence<PointerEvent> coalescedEvents = [];
sequence<PointerEvent> predictedEvents = [];
};
[Exposed=Window]
interface PointerEvent : MouseEvent {
constructor(DOMString type, optional PointerEventInit eventInitDict = {});
readonly attribute long pointerId;
readonly attribute double width;
readonly attribute double height;
readonly attribute float pressure;
readonly attribute float tangentialPressure;
readonly attribute long tiltX;
readonly attribute long tiltY;
readonly attribute long twist;
readonly attribute double altitudeAngle;
readonly attribute double azimuthAngle;
readonly attribute DOMString pointerType;
readonly attribute boolean isPrimary;
readonly attribute long persistentDeviceId;
[SecureContext] sequence<PointerEvent> getCoalescedEvents();
sequence<PointerEvent> getPredictedEvents();
};
pointerId导致事件的指针的唯一标识符。用户代理 可以为主要鼠标指针保留 0 或 1 的通用 pointerId 值。-1 的 pointerId 值 必须被保留,用于指示由非定点设备生成的事件。对于任何其他指针,用户代理可以自由实施不同的策略和方法来分配 pointerId 值。然而,顶级浏览上下文(由 [HTML] 定义)中的所有 活动指针 必须是唯一的,且该标识符 绝不能受到任何其他顶级浏览上下文的影响(即,一个顶级浏览上下文不能假设当指针移动到浏览上下文之外并进入另一个顶级浏览上下文时,其 pointerId 是相同的)。
用户代理 可以回收之前已停用的 pointerId 值,或者对于特定的定点设备总是重用相同的 pointerId(例如,在多用户协作应用中唯一标识来自特定用户的特定笔/手写笔输入)。但在后一种情况下,为了最大限度地减少跨页面或域进行指纹识别和跟踪的机会,pointerId 必须仅在页面/会话的生命周期内显式地与该特定定点设备关联,并且在下次新会话中再次使用该特定定点设备时,必须选择一个新的随机化 pointerId。
pointerId 选择算法是特定于实现的。作者不能假设这些值传达了除唯一标识指针之外的任何特定含义。例如,用户代理可以简单地按顺序为任何活动的指针分配从 0 开始的数字——但不能保证这些值是单调递增的。由于为特定定点设备重用相同的 pointerId 取决于具体实现,因此强烈建议作者不要依赖它,而应参考 persistentDeviceId。
width以 CSS 像素(参见 [CSS21])为单位的指针 接触几何 的宽度(X 轴上的量级)。此值 可以在给定指针的每个事件上更新。对于通常缺乏接触几何的输入(如传统鼠标),以及在硬件未检测到输入实际几何形状的情况下,用户代理 必须返回默认值 1。
height以 CSS 像素(参见 [CSS21])为单位的指针 接触几何 的高度(Y 轴上的量级)。此值 可以在给定指针的每个事件上更新。对于通常缺乏接触几何的输入(如传统鼠标),以及在硬件未检测到输入实际几何形状的情况下,用户代理 必须返回默认值 1。
pressure在 [0,1] 范围内的归一化指针输入压力,其中 0 和 1 分别代表硬件能够检测到的最小和最大压力。对于不支持压力的硬件和平台,当处于 活动按钮状态 时,该值 必须为 0.5,否则为 0。
tangentialPressure在 [-1,1] 范围内的归一化切向压力(也称为桶形压力),通常由附加控件(如喷枪手写笔上的指轮)设置,其中 0 是控件的中性位置。请注意,某些硬件可能仅支持 [0,1] 范围内的正值。对于不支持切向压力的硬件和平台,该值 必须为 0。
tiltXY-Z 平面与包含传感器(例如笔/手写笔)轴和 Y 轴的平面之间的平面角(以度为单位,范围为 [-90,90])。正的 tiltX 向右,朝向 X 值增加的方向。tiltX 可以与 tiltY 一起使用,以表示转换器远离数字化仪法线的倾斜度。对于不支持报告倾斜或角度的硬件和平台,该值 必须为 0。
tiltX。tiltYX-Z 平面与包含传感器(例如笔/手写笔)轴和 X 轴的平面之间的平面角(以度为单位,范围为 [-90,90])。正的 tiltY 朝向用户,朝向 Y 值增加的方向。tiltY 可以与 tiltX 一起使用,以表示转换器远离数字化仪法线的倾斜度。对于不支持报告倾斜或角度的硬件和平台,该值 必须为 0。
tiltY。twist传感器(例如笔/手写笔)绕其自身主轴的顺时针旋转(以度为单位,范围为 [0,359])。对于不支持报告扭转的硬件和平台,该值 必须为 0。
altitudeAngle传感器(例如笔/手写笔)的仰角(以弧度为单位),范围为 [0,π/2] —— 其中 0 平行于表面(X-Y 平面),π/2 垂直于表面。对于不支持报告倾斜或角度的硬件和平台,该值 必须为 π/2。
altitudeAngle 默认值为 π/2,即传感器垂直于表面的位置。这与 Touch Events - Level 2 规范对 altitudeAngle 属性的定义不同,该属性的默认值为 0。
altitudeAngle 为 π/4 的示例(距离 X-Y 平面 45 度)。azimuthAngle传感器(例如笔/手写笔)的方位角(以弧度为单位),范围为 [0, 2π] —— 其中 0 代表传感器笔帽指向 X-Y 平面上 X 值增加的方向(从正上方俯视指向“3 点钟”),且值随着顺时针方向逐渐增加(π/2 在“6 点钟”,π 在“9 点钟”,3π/2 在“12 点钟”)。当传感器完全垂直于表面(altitudeAngle 为 π/2)时,该值 必须为 0。对于不支持报告倾斜或角度的硬件和平台,该值 必须为 0。
azimuthAngle 为 π/6 的示例(“4 点钟”)。pointerType指示导致事件的设备类型(如鼠标、笔、触摸)。如果用户代理要为鼠标、笔/手写笔或触摸输入设备 触发指针事件,则 pointerType 的值 必须符合下表
| 指针设备类型 | pointerType 值 |
|---|---|
| 鼠标 | 鼠标 |
| 笔 / 手写笔 | pen |
| 触摸接触 | touch |
如果用户代理无法检测到设备类型,则该值 必须为空字符串。如果用户代理支持上述列表之外的指针设备类型,则 pointerType 的值 应使用供应商前缀,以避免不同设备类型之间的名称冲突。未来的规范 可以为其他设备类型提供额外的规范值。
pointerType 如何使用的基本演示。还要注意,开发者应包含某种形式的默认处理,以覆盖可能已实现其自定义 pointerType 值的用户代理,以及 pointerType 仅为空字符串的情况。isPrimary指示该指针是否代表此指针类型的 主要指针。
persistentDeviceId定点设备的唯一标识符。如果硬件支持多个指针,则只有当这些指针在会话期间是唯一可标识的情况下,由定点设备生成的指针事件 必须才获取 persistentDeviceId。如果指针是唯一可标识的,则分配给该定点设备的 persistentDeviceId 在会话的剩余时间内保持不变。persistentDeviceId 值 0 必须被保留,用于指示其生成设备无法标识的事件。与 pointerId 一样,为了最大限度地减少跨页面或域进行指纹识别和跟踪的机会,persistentDeviceId 必须仅在页面/会话的生命周期内显式地与该特定定点设备关联,并且在下次新会话中再次使用该特定定点设备时,必须选择一个新的随机化 persistentDeviceId。
persistentDeviceId。例如,设备可能无法及时向数字化仪报告其硬件 ID,以使 pointerdown 拥有 persistentDeviceId。在这种情况下,persistentDeviceId 可能最初为 0 并更改为有效值。getCoalescedEvents()返回 合并事件 列表的方法。
getPredictedEvents()返回 预测事件 列表的方法。
PointerEventInit 字典由 PointerEvent 接口的构造函数使用,以提供一种构建不受信任(合成)指针事件的机制。它继承自 [UIEVENTS] 中定义的 MouseEventInit 字典。请参见 示例 以获取演示如何触发不受信任指针事件的示例代码。
PointerEvent 的 事件构造步骤 将 PointerEventInit 的 coalescedEvents 克隆到 合并事件列表,并将 PointerEventInit 的 predictedEvents 克隆到 预测事件列表。
PointerEvent 接口继承自 UI Events 中定义的 MouseEvent。还要注意 CSSOM View Module 中的拟议扩展,它将各种坐标属性从 long 更改为 double,以允许小数坐标。对于已经为 PointerEvent(而非普通 MouseEvent)实施此拟议扩展的用户代理,在涉及 click、auxclick 和 contextmenu 事件 时有额外的要求。在多指针(例如多点触控)场景中,isPrimary 属性用于识别每种指针类型的一组 活动指针 中的主指针。
pointerType 一个)被视为主要。例如,同时移动触摸接触和鼠标光标将产生都被视为主要指针的指针。isPrimary 值为 false 的指针事件。要 触发名为 e 的指针事件,意味着使用 PointerEvent 触发名为 e 的事件,其属性设置如 PointerEvent 接口和 属性和默认操作 中定义。
如果事件不是 gotpointercapture、lostpointercapture、click、auxclick 或 contextmenu 事件,则对此 PointerEvent 运行 处理待处理指针捕获 的步骤。
确定触发事件的目标 如下
设 targetDocument 为目标的 节点文档 [DOM]。
如果事件是 pointerdown、pointermove 或 pointerup,则将事件的 pointerId 的 活动文档 设置为 targetDocument。
如果事件是 pointerdown,关联设备是直接操作设备,且目标是 Element,则为此 pointerId 设置指针捕获 到目标元素,如 隐式指针捕获 中所述。
在触发此事件之前,为了 确保事件顺序 [UIEVENTS],用户代理 应将目标视为定点设备已从 previousTarget 移动到该目标上。如果设置了 needsOverEvent 标志,则即使目标元素相同,也需要 pointerover 事件。
将事件触发到确定的目标。
将确定的目标保存为给定指针的 previousTarget,并将 needsOverEvent 标志重置为 false。如果 previousTarget 在任何时候不再 连接 [DOM],则将 previousTarget 更新为沿对应于向 previousTarget 分发事件的事件路径,最近的仍然 连接 [DOM] 的父级,并将 needsOverEvent 标志设置为 true。
本规范中定义的事件类型的 bubbles 和 cancelable 属性以及默认操作出现在下表中。每个这些事件类型的详细信息在 指针事件类型 中提供。
| 事件类型 | 冒泡 | 可取消 | 默认操作 |
|---|---|---|---|
pointerover |
是 | 是 | 无 |
pointerenter |
No | No | 无 |
pointerdown |
是 | 是 | 变化:当指针是主要的,mousedown 事件的所有默认操作取消此事件也会阻止随后触发 兼容性鼠标事件。 |
pointermove |
是 | 是 | 变化:当指针是主要的,mousemove 的所有默认操作 |
pointerrawupdate |
是 | No | 无 |
pointerup |
是 | 是 | 变化:当指针是主要的,mouseup 的所有默认操作 |
pointercancel |
是 | No | 无 |
pointerout |
是 | 是 | 无 |
pointerleave |
No | No | 无 |
gotpointercapture |
是 | No | 无 |
lostpointercapture |
是 | No | 无 |
视口操作(平移和缩放)——通常作为 直接操作 交互的结果——有意地不是指针事件的默认操作,这意味着这些行为(例如在触摸屏上移动手指导致平移页面)不能通过取消指针事件来抑制。作者必须改用 touch-action 来显式地 声明文档区域的直接操作行为。消除对事件取消的这种依赖有助于用户代理进行性能优化。
对于 pointerenter 和 pointerleave 事件,composed [DOM] 属性 应为 false;对于上表中的所有其他指针事件,该属性 应为 true。
对于上表中的所有指针事件,detail [UIEVENTS] 属性 应为 0。
fromElement 和 toElement 以支持遗留内容。我们鼓励这些用户代理将 PointerEvents 中那些(继承的)属性的值设置为 null,以引导作者使用标准化替代方案(target 和 relatedTarget)。类似于 MouseEvent relatedTarget,relatedTarget 应初始化为指针刚离开其边界的元素(在 pointerover 或 pointerenter 事件的情况下),或指针正在进入其边界的元素(在 pointerout 或 pointerleave 的情况下)。对于其他指针事件,此值将默认为 null。请注意,当元素接收到指针捕获时,该指针的所有后续事件都被视为在捕获元素的边界内。
对于 gotpointercapture 和 lostpointercapture 事件,除上表定义的属性外,所有属性应与导致用户代理运行 处理待处理指针捕获 步骤并触发 gotpointercapture 和 lostpointercapture 事件的指针事件相同。
用户代理 必须在 隐式释放指针捕获 时以及触发非 gotpointercapture 或 lostpointercapture 的指针事件时运行以下步骤。
lostpointercapture 的指针事件。gotpointercapture 的指针事件。如 click、auxclick 和 contextmenu 事件 节中所定义,即使在 lostpointercapture 事件分发后,对应的 click、auxclick 或 contextmenu 事件(如有)仍将分发给捕获目标。
用户代理 必须在检测到网页不太可能继续接收具有特定 pointerId 的指针事件时 抑制指针事件流。以下任何场景都满足此条件(可能还有其他场景)
touch-action CSS 属性的节。pointercancel 事件。pointerout 事件。pointerleave 事件。相对于屏幕表面移动或经历其任何属性发生变化的定点设备,会根据 指针事件类型 定义触发各种事件。对于静止的定点设备(相对于屏幕表面既未移动也未经历任何属性变化的定点设备),用户代理 必须在影响了指针 命中测试 目标的布局更改后触发某些边界事件,详情请参见 pointerover、pointerenter、pointerout 和 pointerleave。用户代理 可能因性能原因(例如避免由边界事件监听器引起过多的命中测试或布局更改)延迟触发这些边界事件。
pointermove 事件。指针事件包括两组互补的属性,以表示转换器相对于 X-Y 平面的方向:tiltX / tiltY(在原始指针事件规范中引入),以及 azimuthAngle / altitudeAngle(采用自 Touch Events - Level 2 规范)。
根据特定的硬件和平台,用户代理很可能只会收到一组用于转换器相对于屏幕平面方向的值——要么是 tiltX / tiltY,要么是 altitudeAngle / azimuthAngle。用户代理 必须使用以下算法来转换这些值。
当用户代理从 azimuthAngle / altitudeAngle 计算 tiltX / tiltY 时,它 应使用 Math.round [ECMASCRIPT] 规则对最终整数值进行四舍五入。
/* Converting between tiltX/tiltY and altitudeAngle/azimuthAngle */
function spherical2tilt(altitudeAngle, azimuthAngle) {
const radToDeg = 180/Math.PI;
let tiltXrad = 0;
let tiltYrad = 0;
if (altitudeAngle == 0) {
// the pen is in the X-Y plane
if (azimuthAngle == 0 || azimuthAngle == 2*Math.PI) {
// pen is on positive X axis
tiltXrad = Math.PI/2;
}
if (azimuthAngle == Math.PI/2) {
// pen is on positive Y axis
tiltYrad = Math.PI/2;
}
if (azimuthAngle == Math.PI) {
// pen is on negative X axis
tiltXrad = -Math.PI/2;
}
if (azimuthAngle == 3*Math.PI/2) {
// pen is on negative Y axis
tiltYrad = -Math.PI/2;
}
if (azimuthAngle>0 && azimuthAngle<Math.PI/2) {
tiltXrad = Math.PI/2;
tiltYrad = Math.PI/2;
}
if (azimuthAngle>Math.PI/2 && azimuthAngle<Math.PI) {
tiltXrad = -Math.PI/2;
tiltYrad = Math.PI/2;
}
if (azimuthAngle>Math.PI && azimuthAngle<3*Math.PI/2) {
tiltXrad = -Math.PI/2;
tiltYrad = -Math.PI/2;
}
if (azimuthAngle>3*Math.PI/2 && azimuthAngle<2*Math.PI) {
tiltXrad = Math.PI/2;
tiltYrad = -Math.PI/2;
}
}
if (altitudeAngle != 0) {
const tanAlt = Math.tan(altitudeAngle);
tiltXrad = Math.atan(Math.cos(azimuthAngle) / tanAlt);
tiltYrad = Math.atan(Math.sin(azimuthAngle) / tanAlt);
}
return {"tiltX":tiltXrad*radToDeg, "tiltY":tiltYrad*radToDeg};
}
function tilt2spherical(tiltX, tiltY) {
const tiltXrad = tiltX * Math.PI/180;
const tiltYrad = tiltY * Math.PI/180;
// calculate azimuth angle
let azimuthAngle = 0;
if (tiltX == 0) {
if (tiltY > 0) {
azimuthAngle = Math.PI/2;
}
else if (tiltY < 0) {
azimuthAngle = 3*Math.PI/2;
}
} else if (tiltY == 0) {
if (tiltX < 0) {
azimuthAngle = Math.PI;
}
} else if (Math.abs(tiltX) == 90 || Math.abs(tiltY) == 90) {
// not enough information to calculate azimuth
azimuthAngle = 0;
} else {
// Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
const tanX = Math.tan(tiltXrad);
const tanY = Math.tan(tiltYrad);
azimuthAngle = Math.atan2(tanY, tanX);
if (azimuthAngle < 0) {
azimuthAngle += 2*Math.PI;
}
}
// calculate altitude angle
let altitudeAngle = 0;
if (Math.abs(tiltX) == 90 || Math.abs(tiltY) == 90) {
altitudeAngle = 0
} else if (tiltX == 0) {
altitudeAngle = Math.PI/2 - Math.abs(tiltYrad);
} else if (tiltY == 0) {
altitudeAngle = Math.PI/2 - Math.abs(tiltXrad);
} else {
// Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
altitudeAngle = Math.atan(1.0/Math.sqrt(Math.pow(Math.tan(tiltXrad),2) + Math.pow(Math.tan(tiltYrad),2)));
}
return {"altitudeAngle":altitudeAngle, "azimuthAngle":azimuthAngle};
}
PointerEvent要使用 event、eventType 和 eventTarget、bubbles 以及 cancelable 初始化 PointerEvent,请运行以下步骤
PointerEvent 值。PointerEvent要使用 eventType 和 eventTarget、bubbles 以及 cancelable 创建 PointerEvent,请运行以下步骤
PointerEvent 创建事件 的结果DOMStringMouseEventPointerEvent 创建事件 的结果targetMouseEvent 属性从 mouseevent 复制到 eventMouseEvent待办 (TODO)。
targetMouseEvent待办 (TODO)。
targetMouseEvent待办 (TODO)。
targetMouseEvent待办 (TODO)。
targetMouseEvent这能发送 pointermove 和 pointerrawupdate 吗?还是我们需要 2 个方法?
正确定义 pointermove 事件如何合并需要什么?
待办 (TODO)。
targetMouseEvent与 mousedown 事件不同,当按下多个按钮时,pointerdown 事件不会嵌套。传递 MouseEvent 是为了可以将字段复制到 PointerEvent 中。
待办 (TODO)。
targetMouseEventtargetMouseEvent与 mouseup 事件不同,当按下多个按钮时,pointerup 事件不会嵌套。传递 MouseEvent 是为了可以将字段复制到 PointerEvent 中。
待办 (TODO)。
target下面是本规范中定义的事件类型。
在 主要指针 的情况下,这些事件(gotpointercapture 和 lostpointercapture 除外)也可能触发 兼容性鼠标事件。
当发生以下任一情况时,用户代理 必须 触发一个名为 pointerover 的指针事件
pointerdown 事件之前(参见 pointerdown)。当发生以下任何情况时,用户代理必须触发一个指针事件,其名称为 pointerenter:
pointerdown 事件之前(参见 pointerdown)。当指针进入活动按钮状态时,用户代理必须触发一个指针事件,其名称为 pointerdown。对于鼠标,这是指设备从没有按钮按下转换到至少一个按钮按下时。对于触摸,这是指与数字化仪发生物理接触时。对于触控笔,这是指触控笔在没有任何按钮按下的情况下与数字化仪发生物理接触,或者在悬停时从没有按钮按下转换到至少一个按钮按下时。
对于不支持悬停的输入设备,在分发 pointerdown 事件之前,用户代理还必须触发一个指针事件,其名称为 pointerover,随后紧跟一个名为 pointerenter 的指针事件。
pointerdown 事件(若 isPrimary 属性为 true)来阻止某些兼容鼠标事件的触发。这会设置指针上的 PREVENT MOUSE EVENT 标志。但请注意,这并不能阻止 mouseover、mouseenter、mouseout 或 mouseleave 事件的触发。当指针更改了任何不触发 pointerdown 或 pointerup 事件的属性时,用户代理必须触发一个指针事件,其名称为 pointermove。这包括对坐标、压力、切向压力、倾斜、扭转、接触几何形状(width 和 height)或和弦按钮的任何更改。
用户代理可以延迟分发 pointermove 事件(例如,出于性能原因)。合并事件信息将通过单个已分发的 pointermove 事件的 getCoalescedEvents 方法公开。此类事件的最终坐标应被用于查找事件目标。
当指针更改了任何不触发 pointerdown 或 pointerup 事件的属性时,用户代理必须触发一个名称为 pointerrawupdate 的指针事件,且仅在安全上下文内触发。有关此类属性的列表,请参阅 pointermove 事件。
与 pointermove 不同,用户代理应在 JavaScript 能够处理事件时,尽可能快且尽可能频繁地分发 pointerrawupdate 事件。
pointerrawupdate 事件的 target 可能与 pointermove 事件不同,这是因为 pointermove 事件可能会被延迟或合并,且用于查找 target 的事件最终位置可能与已合并事件的最终位置不同。
请注意,如果 事件循环中已存在另一个具有相同 pointerId 且尚未分发的 pointerrawupdate,用户代理可以将新的 pointerrawupdate 与该事件合并,而不是创建一个新的任务。这可能会导致 pointerrawupdate 具有合并事件,一旦该事件在事件循环中被处理,它们都将作为单一 pointerrawupdate 事件的合并事件进行传递。有关更多信息,请参见 getCoalescedEvents。
关于 pointerrawupdate 和 pointermove 的顺序,如果用户代理收到了来自平台导致同时触发 pointerrawupdate 和 pointermove 事件的更新,则用户代理必须在相应的 pointermove 之前分发 pointerrawupdate 事件。
除了 target 外,自上次 pointermove 事件以来所有已分发的 pointerrawupdate 事件的合并事件列表连接,在其他事件属性方面与下一个 pointermove 事件的合并事件相同。pointerrawupdate 的属性大多与 pointermove 相同,除了 cancelable,对于 pointerrawupdate 来说,该属性必须为 false。
用户代理不应为 pointerrawupdate 触发兼容鼠标事件。
pointerrawupdate 事件添加监听器可能会对网页的性能产生负面影响。对于大多数用例,其他指针事件类型应该足够了。只有在 JavaScript 需要高频事件且能够同样快速处理它们时,才应添加 pointerrawupdate 监听器。在这些情况下,可能无需监听其他类型的指针事件。当指针离开活动按钮状态时,用户代理必须触发一个指针事件,其名称为 pointerup。对于鼠标,这是指设备从至少一个按钮按下转换到没有按钮按下时。对于触摸,这是指物理接触从数字化仪上移除时。对于触控笔,这是指触控笔在没有按钮按下的情况下从与数字化仪的物理接触中移除,或者在悬停时从至少一个按钮按下转换到没有按钮按下时。
对于不支持悬停的输入设备,用户代理在分发 pointerup 事件后,还必须触发一个指针事件,其名称为 pointerout,随后紧跟一个名为 pointerleave 的指针事件。
所有 pointerup 事件的 pressure 值均为 0。
当用户代理检测到需要抑制指针事件流的情况时,必须触发一个指针事件,其名称为 pointercancel。
pointercancel 事件的下列属性值必须与具有相同 pointerId 的上一个已分发指针事件的值匹配:width、height、pressure、tangentialPressure、tiltX、tiltY、twist、altitudeAngle、azimuthAngle、pointerType、isPrimary,以及继承自 [UIEVENTS] 的坐标。在 pointercancel 事件中,coalescedEvents 和 predictedEvents 列表必须为空,且事件的 cancelable 属性必须为 false。
当发生以下任何情况时,用户代理必须触发一个指针事件,其名称为 pointerout:
当发生以下任何情况时,用户代理必须触发一个指针事件,其名称为 pointerleave:
pointerup 事件之后(参见 pointerup)。当元素接收到指针捕获时,用户代理必须触发一个指针事件,其名称为 gotpointercapture。该事件在接收到指针捕获的元素上触发。该指针的后续事件将在该元素上触发。参见设置指针捕获和处理挂起的指针捕获章节。
在指针的捕获被释放后,用户代理必须触发一个指针事件,其名称为 lostpointercapture。此事件必须在捕获释放后,该指针的任何后续事件之前触发。该事件在被移除指针捕获的元素上触发。除了 click、auxclick 和 contextmenu 事件外,该指针的所有后续事件都遵循常规的命中测试机制(超出本规范范围)来确定事件目标。参见释放指针捕获、隐式释放指针捕获和处理挂起的指针捕获章节。
用户的环境可能配置为将垂直滚动与沿 y 轴的旋转关联,将水平滚动与沿 x 轴的旋转关联,并将缩放与沿 z 轴的旋转关联。
WheelEvent 对象的 deltaX、deltaY 和 deltaZ 属性指示沿其相应轴的测量值,单位为像素、行或页。报告的测量值是在特定于环境的算法将滚轮设备的实际旋转/移动转换为适当的值和单位之后提供的。用户的环境设置可以自定义,以不同方式解释滚轮设备的实际旋转/移动。常见“齿轮”鼠标滚轮的一次移动可以产生 162 像素的测量值(162 仅是一个示例值,实际值可能取决于用户代理当前的屏幕尺寸)。但用户可以更改其默认环境设置来加速鼠标滚轮,从而增加该数值。此外,一些鼠标滚轮软件可以支持加速(滚轮旋转/移动越快,每次测量的增量越大)甚至亚像素旋转测量。因此,作者不能假设在一个用户代理中给定的旋转量会在所有用户代理中产生相同的增量值。
wheel 事件的多次分发之间必须保持一致。如果用户代理将滚动作为 wheel 事件的默认操作,则增量的符号应由右手坐标系给出,其中正 X、Y 和 Z 轴分别指向文档的最右侧边缘、最底部边缘和最深处(远离用户)。个别用户代理可以(取决于其环境和硬件配置)对滚轮上的相同物理用户交互进行不同的解释。例如,在触控板边缘从上到下的垂直滑动可以被解释为滚轮操作,旨在向下滚动页面或向上平移页面(即分别导致正或负的 deltaY 值)。
如果一系列针对可滚动元素的滚轮事件起始于子元素上方,则同一用户手势的后续事件可能会在子元素上方发生。
WheelEvent 接口提供了与 wheel 事件关联的具体上下文信息。要创建 WheelEvent 接口的实例,请使用 WheelEvent 构造函数,并传入可选的 WheelEventInit 字典。WebIDL[Exposed=Window]
interface WheelEvent : MouseEvent {
constructor(DOMString type, optional WheelEventInit eventInitDict = {});
// 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;
};
DOM_DELTA_PIXELDOM_DELTA_LINEDOM_DELTA_PAGEdeltaXwheel 事件的默认操作是滚动的用户代理中,该值必须是事件未被取消时沿 x 轴滚动的测量值(单位为像素、行或页)。否则,这是围绕 x 轴移动滚轮设备的特定于实现的测量值(单位为像素、行或页)。该属性的未初始化值必须为 0.0。deltaYwheel 事件的默认操作是滚动的用户代理中,该值必须是事件未被取消时沿 y 轴滚动的测量值(单位为像素、行或页)。否则,这是围绕 y 轴移动滚轮设备的特定于实现的测量值(单位为像素、行或页)。该属性的未初始化值必须为 0.0。deltaZwheel 事件的默认操作是滚动的用户代理中,该值必须是事件未被取消时沿 z 轴滚动的测量值(单位为像素、行或页)。否则,这是围绕 z 轴移动滚轮设备的特定于实现的测量值(单位为像素、行或页)。该属性的未初始化值必须为 0.0。deltaModedeltaMode 属性包含对增量值测量单位的指示。默认值为 DOM_DELTA_PIXEL(像素)。此属性必须设置为 DOM_DELTA 常量之一,以指示增量值的测量单位。精确的测量值特定于设备、操作系统和应用程序配置。该属性的未初始化值必须为 0。WebIDLdictionary WheelEventInit : MouseEventInit {
double deltaX = 0.0;
double deltaY = 0.0;
double deltaZ = 0.0;
unsigned long deltaMode = 0;
};
deltaXdeltaZ 属性。deltaYdeltaZ 属性。deltaZdeltaZ 属性的 WheelEvent 对象。该属性(以及 deltaX 和 deltaY 属性)的相对正值由右手坐标系给出,其中 X、Y 和 Z 轴分别指向文档的最右侧边缘、最底部边缘和最深处(远离用户)。负相对值在各自的相反方向。deltaModedeltaMode 属性的 WheelEvent 对象,设置为枚举值 0、1 或 2,如果滚轮的旋转导致滚动,则分别表示滚动的像素量(DOM_DELTA_PIXEL)、滚动行数(DOM_DELTA_LINE)或滚动页数(DOM_DELTA_PAGE)。| 类型 | wheel |
|---|---|
| Interface | WheelEvent |
| 同步 / 异步 | 异步 |
| 冒泡 | 是 |
| 受信任的目标 | 元素 |
| 可取消 | 不同 |
| 可组合(Composed) | 是 |
| 默认操作 | 滚动(或缩放)文档 |
| 上下文 (受信任事件) |
|
wheel 事件,或作为每个非零轴的单独 wheel 事件传递。wheel 事件类型的典型默认操作是以指示的量滚动(或在某些情况下,缩放)文档。如果该事件被取消,实现绝不能滚动或缩放文档(或执行与此事件类型关联的任何其他特定于实现的默认操作)。
在滚轮事件上调用 preventDefault 可以阻止或中断滚动。为了获得最大滚动性能,用户代理可能不会等待与滚动关联的每个滚轮事件处理完毕以查看其是否会被取消。在这种情况下,用户代理应该生成 wheel 事件,其 cancelable 属性为 false,表明 preventDefault 不能用于阻止或中断滚动。否则,cancelable 将为 true。
特别地,当用户代理观察到不存在非被动监听器时,它应该仅生成不可取消的 wheel 事件。
以下章节描述了对现有 Element 接口的扩展,以促进设置和释放指针捕获。
WebIDLpartial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
setPointerCapture()为参数 pointerId 所标识的指针,在调用此方法的元素上设置指针捕获。对于该指针的后续事件,捕获目标将替代常规的命中测试结果,如同指针始终在该捕获目标上方一样,并且直到捕获被释放,它们必须始终针对该元素。指针必须处于其活动按钮状态才能使此方法生效,否则它将静默失败。当所提供方法参数与任何活动指针不匹配时,抛出 "NotFoundError" DOMException。
releasePointerCapture()在调用此方法的元素上,为参数 pointerId 所标识的指针释放指针捕获。指针的后续事件遵循常规命中测试机制(超出本规范范围)来确定事件目标。当所提供方法参数与任何活动指针不匹配时,抛出 "NotFoundError" DOMException。
hasPointerCapture指示调用此方法的元素是否为参数 pointerId 所标识的指针持有指针捕获。特别是,如果 pointerId 的挂起的指针捕获目标覆盖设置为调用此方法的元素,则返回 true,否则返回 false。
setPointerCapture() 后立即返回 true,即使该元素尚未接收到 gotpointercapture 事件。因此,它可以用于在 pointerdown 事件监听器内部检测隐式指针捕获。以下章节描述了对现有 GlobalEventHandlers mixin 的扩展,以促进事件处理器注册。
WebIDLpartial interface mixin GlobalEventHandlers {
attribute EventHandler onpointerover;
attribute EventHandler onpointerenter;
attribute EventHandler onpointerdown;
attribute EventHandler onpointermove;
[SecureContext] attribute EventHandler onpointerrawupdate;
attribute EventHandler onpointerup;
attribute EventHandler onpointercancel;
attribute EventHandler onpointerout;
attribute EventHandler onpointerleave;
attribute EventHandler ongotpointercapture;
attribute EventHandler onlostpointercapture;
};
onpointeroverpointerover 事件类型的事件处理器 IDL 属性。onpointerenterpointerenter 事件类型的事件处理器 IDL 属性。onpointerdownpointerdown 事件类型的事件处理器 IDL 属性。onpointermovepointermove 事件类型的事件处理器 IDL 属性。onpointerrawupdatepointerrawupdate 事件类型的事件处理器 IDL 属性。onpointeruppointerup 事件类型的事件处理器 IDL 属性。onpointercancelpointercancel 事件类型的事件处理器 IDL 属性。onpointeroutpointerout 事件类型的事件处理器 IDL 属性。onpointerleavepointerleave 事件类型的事件处理器 IDL 属性。ongotpointercapturegotpointercapture 事件类型的事件处理器 IDL 属性。onlostpointercapturelostpointercapture 事件类型的事件处理器 IDL 属性。如 属性和默认操作中所述,视口操作(平移和缩放)无法通过取消指针事件来抑制。相反,作者必须使用 touch-action CSS 属性,以声明方式定义他们想要允许的行为以及想要抑制的行为。
touch-action CSS 属性看起来似乎仅指触摸输入,但它实际上适用于所有允许平移和缩放直接操作的指针输入形式。| 名称 | touch-action |
|---|---|
| 值 | auto | none | [ [ pan-x | pan-left | pan-right ] || [ pan-y | pan-up | pan-down ] ] | manipulation |
| 初始值 | auto |
| 应用于 | 除以下元素外的所有元素:非替换内联元素、表格行、行组、表格列和列组 |
| 可继承 | 否 |
| 百分比 | 不适用 |
| 媒体 | 视觉 |
| 计算值 | 与指定值相同 |
| 规范顺序 | 按语法 |
| 动画类型 | 不可动画 |
touch-action CSS 属性决定了直接操作交互(尽管属性名称如此,但并不限于触摸)是否可以触发用户代理的平移和缩放行为。参见关于 touch-action 值的章节。
在开始平移或缩放之前,如果满足以下所有条件,用户代理必须抑制指针事件流:
pointerdown 事件,并且pointerdown 的)pointerup 或 pointercancel 事件。touch-action 不适用于/级联到嵌入的浏览上下文中。例如,即使将 touch-action 应用于 <iframe>,也不会对 <iframe> 内部平移和缩放的直接操作交互行为产生任何影响。当用户使用直接操作指针(如触摸屏上的触摸或触控笔)与元素交互时,该输入的效果由 touch-action 属性的值以及元素及其祖先的默认直接操作行为决定,具体如下:
touch-action。请注意,如果应用了 CSS 变换,元素的坐标空间可能与屏幕坐标有所不同,从而影响此处的符合性;例如,相对于屏幕旋转 90 度的元素的 X 轴将平行于屏幕坐标的 Y 轴。touch-action 属性,则该交互得到支持。document 元素(如 [HTML] 中定义)之间每个元素的 touch-action 属性,则该交互得到支持。touch-action 相关值的任何更改在操作期间都将被忽略。例如,在 pointerdown 处理器脚本中,以编程方式将元素的 touch-action 值从 auto 更改为 none,并不会导致用户代理在指针处于活动状态期间放弃或抑制针对该输入的任何平移或缩放行为。pan-* 的各种 touch-action 值,一旦用户代理在手势开始时确定是否直接处理手势,在该指针处于活动状态期间,同一手势方向的后续变化应被用户代理忽略。例如,如果元素已设置为 touch-action: pan-y(意味着只有垂直平移由用户代理处理),而触摸手势从水平开始,如果用户在手指仍然触摸屏幕时将手势方向更改为垂直,则不应发生垂直平移。touch-action 值的方法超出了本规范的范围。touch-action 属性涵盖了与视口平移和缩放相关的直接操作行为。任何其他用户代理行为,例如文本选择/高亮显示,或激活链接和表单控件,绝不能受到此 CSS 属性的影响。
auto 或 none 值的行为的交互或手势,超出了本规范的范围。pan-x 或 pan-y)时,平移期间无法更改轴。touch-action 值在 [COMPAT] 中定义。特定于方向的平移值对于自定义某些滚动越界(overscroll)行为非常有用。例如,要实现简单的“下拉刷新”效果,当滚动位置为 0 时,可以将文档的 touch-action 设置为 pan-x pan-down,否则设置为 pan-x pan-y。这允许指针事件处理器定义从文档顶部开始的向上平移/滚动行为。
特定于方向的平移值还可用于组合组件,这些组件在支持原生滚动的元素内(或反之)通过指针事件处理实现自定义平移。例如,图片轮播组件可以使用 pan-y,以确保其接收任何水平平移操作的指针事件,且不会干扰文档的垂直平移。当轮播组件到达最右侧边界时,它可以将其 touch-action 更改为 pan-y pan-right,以便随后在其边界之外的滚动操作能够在视口范围内滚动文档(如果可能的话)。在平移/滚动操作进行时,无法更改其行为。
auto 时,用户代理通常会在 click 事件前增加 300 毫秒的延迟,以处理双击手势。在这种情况下,显式设置 touch-action: none 或 touch-action: manipulation 将移除此延迟。请注意,确定点击或双击手势的方法超出了本规范的范围。<div style="touch-action: none;">
This element receives pointer events for all direct manipulation interactions that otherwise lead to panning or zooming.
</div>
<div style="touch-action: pan-x;">
This element receives pointer events when not panning in the horizontal direction.
</div>
<div style="overflow: auto;">
<div style="touch-action: none;">
This element receives pointer events for all direct manipulation interactions that otherwise lead to panning or zooming.
</div>
<div>
Direct manipulation interactions on this element MAY be consumed for manipulating the parent.
</div>
</div>
<div style="overflow: auto;">
<div style="touch-action: pan-y;">
<div style="touch-action: pan-x;">
This element receives pointer events for all direct manipulation interactions because
it allows only horizontal panning yet an intermediate ancestor
(between it and the scrollable element) only allows vertical panning.
Therefore, no direct manipulation behaviors for panning/zooming are
handled by the user agent.
</div>
</div>
</div>
<div style="overflow: auto;">
<div style="touch-action: pan-y pan-left;">
<div style="touch-action: pan-x;">
This element receives pointer events when not panning to the left.
</div>
</div>
</div>
本节是非规范性的。
指针捕获允许将特定指针的事件(包括任何兼容鼠标事件)重定向到特定元素,而不是指针位置的常规命中测试 (hit test)结果。这在自定义滑动条控件(例如类似于 [HTML] 中的 <input type="range"> 控件)等场景中非常有用。指针捕获可以设置在滑动条的滑块元素上,允许用户即使在指针滑出滑块区域时,也能继续来回滑动该控件。
pointerdown 后,可以使用指针捕获来允许用户即使在指针移出滑块时也能继续滑动它。指针捕获是通过调用 element.setPointerCapture(pointerId) 方法设置在 Element 类型的元素上的。当调用此方法时,用户代理必须执行以下步骤:
pointerId 与任何活动指针不匹配,则抛出一个 "NotFoundError" DOMException。pointerId 所指定的活动指针。InvalidStateError" DOMException。pointerLockElement),则抛出一个 "InvalidStateError" DOMException。pointerId,将待处理指针捕获目标覆盖 (pending pointer capture target override) 设置为调用此方法的 Element。pointerdown 监听器处释放隐式指针捕获的失败尝试,此规则同样适用。指针捕获是通过显式调用 element.releasePointerCapture(pointerId) 方法在元素上释放的。当调用此方法时,用户代理必须执行以下步骤:
pointerId 与任何活动指针不匹配,且这些步骤并非因隐式释放指针捕获而调用,则抛出一个 "NotFoundError" DOMException。Element 对于指定的 pointerId 的 hasPointerCapture 为 false,则终止这些步骤。pointerId,清除待处理指针捕获目标覆盖(如果已设置)。实现用于平移和缩放的直接操作交互的输入(例如触摸屏上的触摸或触控笔)应当表现得就像在调用任何 pointerdown 监听器之前,在目标元素上调用了 setPointerCapture 一样。hasPointerCapture API 可用于(例如在 pointerdown 监听器中)确定是否发生了这种情况。如果在下一个指针事件触发之前未调用 releasePointerCapture,则会向目标分发一个 gotpointercapture 事件(正常情况下),指示捕获处于活动状态。
在触发 pointerup 或 pointercancel 事件后,用户代理必须清除刚刚分发的 pointerup 或 pointercancel 事件对应的 pointerId 的待处理指针捕获目标覆盖,然后运行处理待处理指针捕获步骤,以便在必要时触发 lostpointercapture。在运行处理待处理指针捕获步骤后,如果该指针支持悬停,用户代理必须发送相应的边界事件,以反映在无捕获状态下指针的当前位置。
当指针捕获目标覆盖不再连接 [DOM] 时,指针捕获目标覆盖应当设置为文档。
当待处理指针捕获目标覆盖不再连接 [DOM] 时,待处理指针捕获目标覆盖节点应当被清除。
lostpointercapture 事件。当一个元素成功应用了指针锁定 [PointerLock] 时,用户代理必须执行相应的步骤,就如同已经调用了 releasePointerCapture 方法,如果此时有任何元素被捕获或处于待捕获状态。
出于性能原因,用户代理可能选择不在指针的每次可测量属性(如坐标、压力、切向压力、倾斜、扭转或接触几何形状)更新时都发送 pointermove 事件。相反,它们可能会将多次更改合并为一个 pointermove 或 pointerrawupdate 事件。虽然这种方法有助于减少用户代理必须执行的事件处理量,但它自然会降低跟踪指针位置时的粒度和保真度,特别是在快速和大幅度移动的情况下。使用 getCoalescedEvents 方法,应用程序可以访问原始的、未合并的位置变化。这允许更精确地处理指针移动数据。例如,对于绘图应用程序,未合并的事件可用于绘制与指针实际运动更贴合的平滑曲线。
pointermove 事件中的合并坐标(灰色圆点),曲线明显呈角状且锯齿状;使用 getCoalescedEvents() 提供的更细粒度的点绘制相同的线条(红色圆圈),可以得到更平滑的指针运动近似值。PointerEvent 具有关联的合并事件列表(零个或多个 PointerEvent 的列表)。对于可信的 pointermove 和 pointerrawupdate 事件,该列表是所有合并到此事件中的 PointerEvent 的序列。“父级”可信 pointermove 和 pointerrawupdate 事件代表了这些合并事件的累积,但可能经过了额外的处理(例如为了与显示刷新率对齐)。因此,这些事件的合并事件列表始终包含至少一个事件。对于所有其他可信事件类型,它是一个空列表。不可信事件的合并事件列表被初始化为传递给构造函数的值。
可信事件的合并事件列表中的事件将具有:
timeStamp 值 [DOM] —— 所有合并事件的 timeStamp 都小于或等于调用了 getPredictedEvents 方法的分发指针事件的 timeStamp。合并事件列表必须按 timeStamp 进行时间顺序排序,因此第一个事件将具有最小的 timeStamp。pointerId、pointerType 和 isPrimary。<style>
/* Disable intrinsic user agent direct manipulation behaviors (such as panning or zooming)
so that all events on the canvas element are given to the application instead. */
canvas { touch-action: none; }
</style>
<canvas id="drawSurface" width="500px" height="500px" style="border:1px solid black;"></canvas>
<script>
const canvas = document.getElementById("drawSurface"),
context = canvas.getContext("2d");
canvas.addEventListener("pointermove", (e)=> {
if (e.getCoalescedEvents) {
for (let coalesced_event of e.getCoalescedEvents()) {
paint(coalesced_event); // Paint all raw/non-coalesced points
}
} else {
paint(e); // Paint the final coalesced point
}
});
function paint(event) {
if (event.buttons>0) {
context.fillRect(event.clientX, event.clientY, 5, 5);
}
}
</script>
所有这些分发事件的顺序必须与原始事件的实际顺序相匹配。例如,如果一个 pointerdown 事件导致了合并的 pointermove 事件的分发,用户代理必须首先分发一个包含所有该 pointerId 的合并事件的 pointermove 事件,随后分发该 pointerdown 事件。
以下是实际发生事件及不断增加的 timeStamp 值以及用户代理分发的事件的示例:
| 实际事件 | 分发事件 |
|---|---|
指针(pointerId=2)坐标改变 | pointerrawupdate(pointerId=2),带有 1 个合并事件 |
指针(pointerId=1)坐标改变 | pointerrawupdate(pointerId=1),带有 1 个合并事件 |
指针(pointerId=2)坐标改变 | pointerrawupdate(pointerId=2),带有 1 个合并事件 |
指针(pointerId=2)坐标改变 | pointerrawupdate(pointerId=2),带有 1 个合并事件 |
指针(pointerId=1)坐标改变 | pointerrawupdate(pointerId=1),带有 1 个合并事件 |
指针(pointerId=2)坐标改变 | pointerrawupdate(pointerId=2),带有 1 个合并事件 |
指针(pointerId=1)按钮按下 |
pointermove(pointerId=1),带有 2 个合并事件pointermove(pointerId=2),带有 4 个合并事件pointerdown(pointerId=1),带有 0 个合并事件 |
指针(pointerId=2)坐标改变 | pointerrawupdate(pointerId=2),带有 1 个合并事件 |
指针(pointerId=2)坐标改变 | pointerrawupdate(pointerId=2),带有 1 个合并事件 |
指针(pointerId=1)按钮释放 |
pointermove(pointerId=2),带有 2 个合并事件pointerup(pointerId=1),带有 0 个合并事件 |
一些用户代理具有内置算法,在经过一系列确认的指针移动后,可以进行预测(基于当前手势的前序事件以及移动的速度/轨迹),预测未来的指针移动位置可能在哪里。应用程序可以使用此信息结合 getPredictedEvents 方法,推测性地“超前绘制”到预测位置以减少感知延迟,并在实际点收到后丢弃这些预测点。
pointermove 事件中的合并坐标,显示用户代理预测的未来点(灰色圆圈)。PointerEvent 具有关联的预测事件列表(零个或多个 PointerEvent 的列表)。对于可信的 pointermove 事件,它是用户代理预测在未来将跟随此事件的 PointerEvent 序列。对于所有其他可信事件类型,它是一个空列表。不可信事件的预测事件列表被初始化为传递给构造函数的值。
列表中的事件数量以及它们距离当前时间戳有多远,由用户代理及其使用的预测算法决定。
可信事件的预测事件列表中的事件将具有:
timeStamp 值 [DOM] —— 所有预测事件的 timeStamp 都大于或等于调用了 getPredictedEvents 方法的分发指针事件的 timeStamp。预测事件列表必须按 timeStamp 进行时间顺序排序,因此第一个事件将具有最小的 timeStamp。pointerId、pointerType 和 isPrimary。请注意,作者应仅将预测事件视为有效的预测,直到下一个指针事件被分发为止。根据用户代理预测未来事件的程度,可能会出现常规指针事件比一个或多个预测事件的时间戳更早分发的情况。
let predicted_points = [];
window.addEventListener("pointermove", function(event) {
// Clear the previously drawn predicted points.
for (let e of predicted_points.reverse()) {
clearPoint(e.pageX, e.pageY);
}
// Draw the actual movements that happened since the last received event.
for (let e of event.getCoalescedEvents()) {
drawPoint(e.pageX, e.pageY);
}
// Draw the current predicted points to reduce the perception of latency.
predicted_points = event.getPredictedEvents();
for (let e of predicted_points) {
drawPoint(e.pageX, e.pageY);
}
});
当创建可信 PointerEvent 时,用户代理应当对合并事件列表和预测事件列表中的每个事件运行以下步骤:
pointerId、pointerType、isPrimary 和 isTrusted 设置为与“父级”指针事件的相应属性相匹配。cancelable 和 bubbles 设置为 false(因为这些事件绝不会单独分发)。PointerEvent 值。当可信 PointerEvent 的 target 发生更改时,用户代理应当对合并事件列表和预测事件列表中的每个事件:
现有的绝大多数 Web 内容仅使用鼠标事件进行编码。以下描述了一种算法,说明用户代理可以如何将通用指针输入映射到鼠标事件,以实现与此类内容的兼容。
与鼠标事件的兼容性映射是本规范的一项可选功能。鼓励用户代理支持此功能,以实现与现有遗留内容的最大兼容性。
从高层次来看,兼容鼠标事件旨在与它们各自的指针事件“交错”分发。但是,这种特定的顺序并非强制性的,且实现了兼容鼠标事件的用户代理可以决定延迟或合并鼠标事件的分发,只要它们的相对顺序是一致的。
特别是在触摸屏输入的情况下,用户代理可以应用额外的手势识别启发式方法(除非作者通过 touch-action 显式禁止)。在 pointerdown 事件和 pointerup 事件之间的事件序列期间,手势识别可能必须等到 pointerup 事件才能检测或忽略手势。因此,如果用户代理确定交互不被视为特定手势,则整个序列的兼容鼠标事件可能会在最后一个 pointerup 事件之后一起分发。这些用户代理手势识别的具体细节未在本规范中定义,且不同实现之间可能存在差异。
无论是否支持兼容鼠标事件,用户代理必须始终支持 click、auxclick 和 contextmenu 事件,因为这些事件的类型为 PointerEvent,因此它们不是兼容鼠标事件。在指针事件期间调用 preventDefault 绝不能对 click、auxclick 或 contextmenu 是否触发产生影响。
某些高级事件(如 contextmenu、focus、blur)与指针事件之间的相对顺序是未定义的,并且在不同用户代理之间存在差异。例如,在某些用户代理中,contextmenu 通常会在 pointerup 之后,而在另一些中,它通常会在 pointerup 或 pointercancel 之前,在某些情况下,它可能会在没有任何相应指针事件的情况下触发(例如,作为键盘交互的结果)。
此外,用户代理可能会应用其自己的启发式方法来确定是否应触发 click、auxclick 或 contextmenu 事件。如果存在相同类型的其他(非主要)指针或不同类型的其他主要指针,一些用户代理可能选择不触发这些事件。用户代理可能会确定特定的操作不是一个“干净”的点击、单击或长按(例如,如果触摸屏上的手指交互在手指接触屏幕时包含了过多的移动),并决定不触发 click、auxclick 或 contextmenu 事件。用户代理行为的这些方面未在本规范中定义,且不同实现之间可能存在差异。
除非另有说明,任何映射的鼠标事件的目标应当与相应的指针事件目标相同,除非该目标不再参与其 ownerDocument 的树结构中。在这种情况下,鼠标事件应在原始目标的最接近的祖先节点(在从树中移除时)触发,该祖先节点仍参与其 ownerDocument 的树,这意味着为鼠标事件构建了新的事件路径(基于新的目标节点)。
作者可以通过取消 pointerdown 事件来阻止某些兼容鼠标事件的产生。
鼠标事件只能在指针处于按下状态时被阻止。悬停的指针(例如未按下任何按钮的鼠标)无法阻止其鼠标事件。
mouseover、mouseout、mouseenter 和 mouseleave 事件永远不会被阻止(即使指针已按下)。
当指针事件 EventListener 被设置为 passive [DOM] 时,无法阻止兼容鼠标事件。
虽然只有主要指针才能产生兼容鼠标事件,但多个主要指针可以同时处于活动状态,每个指针产生其自己的兼容鼠标事件。为了与依赖 MouseEvents 的脚本兼容,鼠标转换事件(mouseover、mouseout、mouseenter 和 mouseleave)应当模拟单个遗留鼠标输入的移动。这意味着根据 [UIEVENTS],每个事件目标的进入/离开状态是有效的。用户代理应当通过在文档中维护遗留鼠标指针的有效位置来保证这一点,具体如下。
在分发 pointerdown、pointerup 或 pointermove 事件,或者在 window 上分发 pointerleave 事件之前,用户代理应当运行以下步骤:
pointerdown、pointerup 或 pointermove 事件的目标。对于 pointerleave 事件,取消设置 T。mouseover、mouseout、mouseenter 和 mouseleave 事件。将当前遗留鼠标指针的有效位置或 T 的未设置值视为窗口外的鼠标位置。遗留鼠标指针的有效位置模拟了这样一个事实:我们不能总是将指针转换事件(pointerover、pointerout、pointerenter 和 pointerleave)直接映射到相应的遗留鼠标转换事件(mouseover、mouseout、mouseenter 和 mouseleave)。以下动画说明了一个用户代理需要分发比指针转换事件更多的遗留鼠标转换事件的情况,以便能够协调两个使用单个遗留鼠标输入的主要指针。
在此动画中,请注意鼠标点击和触摸点击之间的时间段。按钮 1 没有接收到 pointerout 事件(因为“真实”鼠标指针在此期间没有离开按钮矩形),但当遗留鼠标指针的有效位置在触摸点击时移动到按钮 2 时,按钮 1 会接收到一个 mouseout 事件。同样,在触摸点击和鼠标离开按钮 1 之前的时间段内,按钮 1 出于同样的原因没有接收到 pointerover 事件,但当遗留鼠标指针的有效位置移回按钮 1 内部时,按钮 1 会接收到一个 mouseover 事件。
每当用户代理要为一个支持悬停的设备分发指针事件时,它应当执行以下步骤:
isPrimary 属性为 false,则分发该指针事件并终止这些步骤。pointerdown、pointerup 或 pointermove 事件,或者在 window 上分发的 pointerleave 事件,则按跟踪遗留鼠标指针的有效位置中所述分发兼容鼠标转换事件。pointerdown 且事件的已取消标志已设置,则为此 pointerType 设置 PREVENT MOUSE EVENT 标志。pointerType 设置 PREVENT MOUSE EVENT 标志,且分发的指针事件是:pointerdown,则触发 mousedown 事件。pointermove,则触发 mousemove 事件。pointerup,则触发 mouseup 事件。pointercancel,则在 window 上触发 mouseup 事件。pointerup 或 pointercancel,则清除此 pointerType 的 PREVENT MOUSE EVENT 标志。某些设备(例如大多数触摸屏)不支持在不处于活动状态时悬停坐标(或坐标集)。许多编码为鼠标事件的现有内容假设鼠标正在产生事件,因此某些质量通常是真的:
mousemove 事件。这要求用户代理为这些类型的输入设备提供不同的映射。每当用户代理要为一个不支持悬停的设备分发指针事件时,它应当执行以下步骤:
isPrimary 属性为 false,则分发该指针事件并终止这些步骤。pointerover 且此指针的 pointerdown 事件尚未分发,则触发 mousemove 事件(为了与遗留的鼠标特定代码兼容)。pointerdown、pointerup 或 pointermove 事件,或者在 window 上分发的 pointerleave 事件,则按跟踪遗留鼠标指针的有效位置中所述分发兼容鼠标转换事件。pointerdown 且事件的已取消标志已设置,则为此 pointerType 设置 PREVENT MOUSE EVENT 标志。pointerType 设置 PREVENT MOUSE EVENT 标志,且分发的指针事件是:pointerdown,则触发 mousedown 事件。pointermove,则触发 mousemove 事件。pointerup,则触发 mouseup 事件。pointercancel,则在 window 上触发 mouseup 事件。pointerup 或 pointercancel,则清除此 pointerType 的 PREVENT MOUSE EVENT 标志。如果用户代理同时支持触摸事件(如 [TOUCH-EVENTS] 中所定义)和指针事件,则用户代理绝不能同时生成本节所述的兼容鼠标事件,以及 [TOUCH-EVENTS] 中概述的回退鼠标事件。
使用不支持悬停的主要指针激活元素(click)(例如触摸屏上的单指)通常会产生以下事件序列:
mousemovepointeroverpointerentermouseovermouseenterpointerdownmousedownpointermove 和 mousemove 事件,具体取决于指针的移动pointerupmouseuppointeroutpointerleavemouseoutmouseleaveclick然而,如果在此交互期间设置了 pointerdown 事件的已取消标志,则事件序列将为:
mousemovepointeroverpointerentermouseovermouseenterpointerdownpointermove 事件,具体取决于指针的移动pointeruppointeroutpointerleavemouseoutmouseleaveclick本附录讨论了 Pointer Events 实现的安全和隐私注意事项。讨论仅限于直接由本规范中定义的事件模型、API 和事件实现所引起的安全和隐私问题。
本规范中定义的许多事件类型都是响应用户操作而分发的。这使得恶意的事件监听器能够访问用户通常认为机密的信息,例如用户在与页面交互时鼠标/触控笔/手指的确切路径/移动。
指针事件包含额外信息(在用户设备支持的情况下),例如握持笔时的角度或倾斜度、接触面的几何形状,以及施加在触控笔或触摸屏上的压力。关于角度、倾斜、几何形状和压力信息直接与用户设备上的传感器相关,这意味着本规范允许源访问这些传感器。
这些传感器数据,以及确定所使用的输入机制(鼠标、触摸、笔)的能力,可能会被用于推断用户、用户设备及其环境的特征。这些推断出的特征以及任何设备/环境信息本身可能是敏感的——例如,它们可能允许恶意站点进一步推断用户是否在使用辅助技术。这些信息也有可能被用于构建用户画像和/或尝试“指纹识别”并跟踪特定用户。
作为缓解措施,用户代理可以考虑包含允许用户禁用对特定传感器数据(如角度、倾斜、压力)的访问的能力,和/或仅在获得用户明确许可后才使其可用。
本规范定义了作者可以访问“预测事件”的方法。本规范本身并未定义用户代理应使用的预测算法。规范作者设想这些算法仅依赖于用户执行的当前手势的相关前序指针事件。用户代理有责任确保其特定的预测算法实现不依赖于任何额外的数据——例如跨不同站点的用户完整交互历史——这些数据可能揭示用户的敏感信息或被用于“指纹识别”并跟踪他们。
除了这些考虑因素外,工作组认为本规范:
本节是非规范性的。
buttons 属性值的状态。对于鼠标,这是指设备至少有一个按钮被按下。对于触摸,这是指与数字化仪(digitizer)有物理接触。对于笔,这是指笔与数字化仪有物理接触,或者在悬停时至少有一个按钮被按下。pointerId 标识)有可能在文档内产生额外事件,则该指针仍被视为活动。示例:WheelEvent 接口的输入设备(如鼠标滚轮或触摸板)的物理移动而滚动或缩放页面的估计滚动量(以像素、行或页为单位)。增量的值(例如 deltaX、deltaY 或 deltaZ 属性)应在当前 deltaMode 属性的上下文中解释。滚轮(或其他设备)的物理移动与增量是正还是负之间的关系取决于环境和设备。但是,如果用户代理作为默认动作进行滚动,则增量的正负号由右手坐标系给出,其中正 X、Y 和 Z 轴分别指向文档的最右侧边缘、最底部边缘和最深处(远离用户)。可测量属性代表与连续指针传感器数据相关的值,这些值使用实数或大域内的整数表示。对于指针事件,width、height、pressure、tangentialPressure、tiltX、tiltY、twist、altitudeAngle、azimuthAngle 以及 [UIEVENTS] 鼠标事件模型属性 screenX、screenY、clientX、clientY 都是可测量属性。
相反,pointerId、pointerType、isPrimary 以及 [UIEVENTS] 鼠标事件模型属性 button、buttons、ctrlKey、shiftKey、altKey 和 metaKey 不被视为可测量属性,因为它们不涉及传感器数据。
WheelEvent 接口的输入设备上增量变化的指示。在某些设备上,这可能是滚轮的字面旋转,而在另一些设备上,它可能是沿平面的移动或在特定按钮上的压力。本节是规范性的。以下功能已过时,且仅应由需要与遗留软件兼容的用户代理实现。另请参阅 [UIEvents] 中的遗留事件初始化器。
WebIDLpartial interface MouseEvent {
};
MouseEvent 对象的属性。此方法具有与 UIEvent.initUIEvent() 相同的行为。initMouseEvent 方法已弃用,但为了向后兼容广泛部署的实现而提供支持。
initEvent() 方法。initEvent() 方法。initEvent() 方法。view。此值可能为 null。detail。screenX。screenY。clientX。clientY。ctrlKey。altKey。shiftKey。metaKey。button。relatedTarget。此值可能为 null。衷心感谢许多为本规范提出建议和方案的人,其中一些已被纳入本文件。本组主席感谢以下过去和现在的小组成员及参与者所作的贡献:Mustaq Ahmed, Arthur Barstow, Ben Boyle, Matt Brubeck, Rick Byers, Marcos Cáceres, Cathy Chan, Bo Cupp, Domenic Denicola, Ted Dinklocker, Adam Ettenberger, Robert Flack, Dave Fleck, Mike Fraser, Ella Ge, Olga Gerchikov, Scott González, Kartikaya Gupta, Dominique Hazael-Massieux, Philippe Le Hégaret, Hayato Ito, Patrick Kettner, Patrick H. Lauke, Scott Low, Sangwhan Moon, Masayuki Nakano, Olli Pettay, Addison Phillips, Alan Pyne, Antoine Quint, Jacob Rossi, Kagami Sascha Rosylight, Doug Schepers, Ming-Chou Shih, Brenton Simpson, Dave Tapuska, Liviu Tinta, Asir Vedamuthu, Lan Wei, Jeffrey Yasskin, Navid Zolghadr。
感谢过去处理鼠标和滚轮事件的人:Gary Kacmarcik, Travis Leithead 以及多年来的多位贡献者。
特别感谢那些帮助开创该模型第一版的人,特别包括:Charu Chandiram, Peter Freiling, Nathan Furtwangler, Thomas Olsen, Matt Rakow, Ramu Ramanathan, Justin Rogers, Jacob Rossi, Reed Townsend 和 Steve Wright。
本节是非规范性的。
以下是本规范各版本之间相对于 [PointerEvents3] 规范在实质性和重大编辑上的变更概要。请参阅本规范编辑草案的完整修订历史。
WebIDL[Exposed=Window]
interface MouseEvent : UIEvent {
constructor(DOMString type, optional MouseEventInit eventInitDict = {});
readonly attribute long screenX;
readonly attribute long screenY;
readonly attribute long clientX;
readonly attribute long clientY;
readonly attribute long layerX;
readonly attribute long layerY;
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;
};
dictionary PointerEventInit : MouseEventInit {
long pointerId = 0;
double width = 1;
double height = 1;
float pressure = 0;
float tangentialPressure = 0;
long tiltX;
long tiltY;
long twist = 0;
double altitudeAngle;
double azimuthAngle;
DOMString pointerType = "";
boolean isPrimary = false;
long persistentDeviceId = 0;
sequence<PointerEvent> coalescedEvents = [];
sequence<PointerEvent> predictedEvents = [];
};
[Exposed=Window]
interface PointerEvent : MouseEvent {
constructor(DOMString type, optional PointerEventInit eventInitDict = {});
readonly attribute long pointerId;
readonly attribute double width;
readonly attribute double height;
readonly attribute float pressure;
readonly attribute float tangentialPressure;
readonly attribute long tiltX;
readonly attribute long tiltY;
readonly attribute long twist;
readonly attribute double altitudeAngle;
readonly attribute double azimuthAngle;
readonly attribute DOMString pointerType;
readonly attribute boolean isPrimary;
readonly attribute long persistentDeviceId;
[SecureContext] sequence<PointerEvent> getCoalescedEvents();
sequence<PointerEvent> getPredictedEvents();
};
[Exposed=Window]
interface WheelEvent : MouseEvent {
constructor(DOMString type, optional WheelEventInit eventInitDict = {});
// 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;
};
dictionary WheelEventInit : MouseEventInit {
double deltaX = 0.0;
double deltaY = 0.0;
double deltaZ = 0.0;
unsigned long deltaMode = 0;
};
partial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
partial interface mixin GlobalEventHandlers {
attribute EventHandler onpointerover;
attribute EventHandler onpointerenter;
attribute EventHandler onpointerdown;
attribute EventHandler onpointermove;
[SecureContext] attribute EventHandler onpointerrawupdate;
attribute EventHandler onpointerup;
attribute EventHandler onpointercancel;
attribute EventHandler onpointerout;
attribute EventHandler onpointerleave;
attribute EventHandler ongotpointercapture;
attribute EventHandler onlostpointercapture;
};
partial interface Navigator {
readonly attribute long maxTouchPoints;
};
partial interface MouseEvent {
// Deprecated in this specification
undefined initMouseEvent(DOMString typeArg,
optional boolean bubblesArg = false,
optional boolean cancelableArg = false,
optional Window? viewArg = null,
optional long detailArg = 0,
optional long screenXArg = 0,
optional long screenYArg = 0,
optional long clientXArg = 0,
optional long clientYArg = 0,
optional boolean ctrlKeyArg = false,
optional boolean altKeyArg = false,
optional boolean shiftKeyArg = false,
optional boolean metaKeyArg = false,
optional short buttonArg = 0,
optional EventTarget? relatedTargetArg = null);
};引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自