Copyright © 2026 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
Pointer Events 规范定义了一种统一的、与硬件无关的框架,用于处理来自 各种设备的输入,包括鼠标、触摸屏以及笔/触控笔。通过提供一组单一的事件(例如 pointerdown、pointermove、pointerup),它允许开发者支持多样化的输入方式,而无需为每种设备编写 特定于设备的逻辑。
本规范还定义了 Mouse 和 Wheel Events,以及为其他 指针设备类型触发 Mouse Events 的映射。
本节描述了本文档在其 发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准和草案 索引中找到。
本规范是对 [PointerEvents3] 规范的更新。它还 包括以前位于 [UIEVENTS] 规范中的 Mouse 和 Wheel Events。
本修订版包括新特性:
persistentDeviceId,用于为输入设备在多次
交互中提供稳定标识符。touch-action 值:pan-left、
pan-right、pan-up、pan-down
本文档由 Pointer Events 工作组作为 工作草案发布,并使用 推荐标准 轨道。
作为 工作草案发布并不表示 W3C 及其成员认可该文档。
这是一个草案文档,可能随时被其他 文档更新、取代或废弃。除作为进行中的工作之外, 引用本文档是不合适的。
本文档由一个按照 W3C 专利 政策运行的组制作。 W3C 维护了一份 任何专利 披露的公开列表, 这些披露与该组的交付物有关;该页面还包括 专利披露说明。实际知晓某项专利的个人,如果该个人认为该专利包含 必要权利要求, 则必须按照 W3C 专利政策第 6 节 披露相关信息。
本文档受 2025 年 8 月 18 日 W3C 流程文档管辖。
本节为非规范性内容。
如今,大多数 [HTML] 内容都与鼠标输入一起使用,和/或为鼠标输入而设计。那些 以自定义方式处理输入的内容通常会针对 [UIEVENTS] Mouse Events 编写代码。然而,如今较新的计算设备 还包含其他形式的输入,包括触摸屏和笔输入。已经有人提出用于分别处理这些输入形式的事件类型。 然而,在为新的输入类型添加支持时,这种方式通常会导致不必要的逻辑重复和事件处理开销。 当内容只考虑一种设备类型来编写时,这通常会产生兼容性问题。 此外,为了与现有的基于鼠标的内容兼容,大多数 用户代理 会为所有输入类型触发 Mouse Events。 这使得无法明确判断某个 Mouse Event 是表示实际的鼠标设备,还是为了兼容性而由 另一种输入类型产生的,从而使得同时针对两种设备类型编写代码变得困难。
为了降低针对多种输入类型编写代码的成本,并帮助解决上文所述 Mouse Events 的歧义问题, 本规范定义了一种更抽象的输入形式,称为 指针。指针可以是 由鼠标光标、笔、触摸(包括多点触控)或其他指点输入设备在屏幕上形成的任何 接触点。无论用户拥有何种硬件,此模型都能更容易地编写表现良好的站点和应用。 对于需要特定于设备的处理的场景,本规范还定义了用于检查产生该事件的设备类型的属性。 主要目标是提供一组单一的事件和接口,使跨设备指针输入的创作更加容易,同时 仍然只在为了增强体验而有必要时,允许特定于设备的处理。
另一个关键目标是使多线程用户代理能够处理用于平移和缩放的 直接操纵 动作(例如,在触摸屏上使用手指或触控笔),而无需阻塞脚本执行。
虽然本规范为各种指针输入定义了统一的事件模型,但此模型 不覆盖其他形式的输入,例如键盘或类似键盘的接口(例如, 在仅触摸屏设备上运行的屏幕阅读器或类似辅助技术,它允许 用户在可聚焦控件和元素之间按顺序导航)。虽然用户代理可能会选择 也响应这些接口来生成指针事件,但本规范并不覆盖此场景。
首先,鼓励作者通过响应诸如 focus、blur 和
click 等高级事件,为所有形式的输入提供等效功能。
然而,在使用低级事件(例如 Pointer Events)时,鼓励作者
确保支持所有类型的输入。对于键盘和类似键盘的接口,
这可能需要额外添加显式的键盘事件处理。更多
细节请参见 Keyboard Accessible [WCAG22]。
用于处理通用指针输入的事件看起来非常像鼠标事件:pointerdown、pointermove、pointerup、pointerover、pointerout,等等。这有助于将内容轻松
从 Mouse Events 迁移到 Pointer Events。
Pointer Events 提供 Mouse Events 中存在的所有常见属性(包括客户端坐标、
目标元素、按钮状态),此外还提供用于其他输入形式的新属性,例如压力、
接触几何形状、倾斜。作者可以很容易地针对 Pointer Events 编写代码,在有意义的地方
在不同输入类型之间共享逻辑,并且只在必要时为特定输入类型进行定制,
以获得最佳体验。
虽然 Pointer Events 来源于各种输入设备,但它们并未被定义为 由其他某组特定于设备的事件生成。虽然为了兼容性可以并且鼓励这样做,但本规范 不要求支持其他特定于设备的事件(例如鼠标事件或触摸事件)。用户代理 可以支持指针事件,而不支持任何其他设备事件。为了与 针对特定于鼠标的事件编写的内容兼容,本规范确实提供了一个可选章节,描述如何 根据来自鼠标以外设备的指针输入生成 兼容性鼠标事件。
本规范不提供关于同时支持 Touch Events(如 [TOUCH-EVENTS] 中定义)和 Pointer Events 的用户代理预期行为的任何建议。 有关这两个规范之间关系的更多信息,请参见 Touch Events Community Group。
除标记为非规范性的章节外,本规范中的所有创作指南、图表、示例和注释 均为非规范性内容。除此之外,本规范中的所有内容均为规范性内容。
本文档中的关键词 MAY、MUST、MUST NOT、OPTIONAL 和 SHOULD 应按 BCP 14 [RFC2119] [RFC8174] 中所述进行解释,但仅限于它们如本文所示以全 大写形式出现时。
本节为非规范性内容。
以下是一些基本示例,用于演示本规范中的某些 API 可如何由 作者使用。此外,本文档的相关章节中还提供了更具体的示例。
/* 绑定到 Pointer Events 或传统 touch/mouse */
if (window.PointerEvent) {
// 如果支持 Pointer Events,则只监听 pointer 事件
target.addEventListener("pointerdown", function(e) {
// 如有必要,基于 e.pointerType 应用单独的逻辑
// 用于不同的 touch/pen/mouse 行为
...
});
...
} else {
// 传统 touch/mouse 事件处理器
target.addEventListener('touchstart', function(e) {
// 阻止兼容性鼠标事件和 click
e.preventDefault();
...
});
...
target.addEventListener('mousedown', ...);
...
}
// 用于键盘处理的其他事件监听器
...
window.addEventListener("pointerdown", detectInputType);
function detectInputType(event) {
switch(event.pointerType) {
case "mouse":
/* 检测到鼠标输入 */
break;
case "pen":
/* 检测到笔/触控笔输入 */
break;
case "touch":
/* 检测到触摸输入 */
break;
default:
/* pointerType 为空(无法检测)
或 UA 特定的自定义类型 */
}
}
<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;
// 检查是否存在唯一 Id。
if (uniqueId == 0) {
return;
}
// 检查是否已为该设备分配颜色。
if (map.has(uniqueId)) {
return;
}
// 为该设备分配颜色。
let newColor = getNewColor();
map.set(uniqueId, newColor);
return newColor;
}
function getNewColor() {
/* 返回某个颜色值 */
}
</script>
鼠标事件模块源自 [HTML401] 的 onclick、
ondblclick、onmousedown、onmouseup、onmouseover、
onmousemove 和 onmouseout 属性。此事件模块专门设计为
与指点输入设备一起使用,例如鼠标或轨迹球。
在 DOM Level 2 中引入,在本规范中修改。
MouseEvent 接口提供与 Mouse 事件关联的特定上下文
信息。
在嵌套元素的情况下,鼠标事件始终以最深层嵌套元素为目标。
目标元素的祖先可以使用事件冒泡,来获得在其后代元素中发生的鼠标事件 通知。
要创建 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事件发生处相对于屏幕坐标系原点的水平坐标。
此属性的 未初始化值
MUST 为 0。
screenY事件发生处相对于屏幕坐标系原点的垂直坐标。
此属性的 未初始化值
MUST 为 0。
clientX事件发生处相对于与该事件关联的视口的水平坐标。
此属性的 未初始化值
MUST 为 0。
clientY事件发生处相对于与该事件关联的视口的垂直坐标。
此属性的 未初始化值
MUST 为 0。
layerX相对于最近的 祖先元素的水平偏移量,该元素是 层叠上下文、是 定位的,或者在 绘制层叠上下文时于定位阶段进行绘制。
此属性的 未初始化值
MUST 为 0。
layerY相对于最近的 祖先元素的垂直偏移量,该元素是 层叠上下文、是 定位的,或者在 绘制层叠上下文时于定位阶段进行绘制。
此属性的 未初始化值
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(前进)按钮。
某些指点设备提供或模拟更多按钮状态,且高于
2 或低于 0 的值 MAY 用于
表示这些按钮。
对于非由鼠标按钮按下/释放引起的事件,button
的值不会更新。
在这些场景中,请注意不要将值 0 解释为左键,而应解释为
默认值。
此属性的 未初始化值
MUST 为 0。
buttons
在任何鼠标事件期间,buttons MUST 用于指示当前正在按下的鼠标按钮组合,
并表示为位掩码。
尽管名称相似,buttons 属性和 button 属性的值非常
不同。button 的值
被假定在 mousedown / mouseup 事件处理器期间有效,而 buttons 属性反映
任何受信任的 MouseEvent 对象(在其被
分派期间)的鼠标按钮状态,因为它可以表示“当前没有按钮处于活动状态”的状态 (0)。
buttons 属性的值 MUST 如下:
0 MUST 表示当前没有按钮处于活动状态。
1 MUST 表示设备的主按钮
(通常为左键,或单按钮设备上的唯一按钮,用于
激活用户界面控件或选择文本)。
2 MUST 表示次按钮(通常为
右键,常用于显示上下文菜单),如果存在。
4 MUST 表示辅助按钮(通常为
中键,常与鼠标滚轮结合)。
某些指点设备提供或模拟更多按钮。为了表示这些按钮,该值
MUST 对每个后续按钮加倍(二进制序列
8、16、32、...)。
因为任意一组按钮值的总和都是唯一数字,内容作者可以使用
按位运算来确定当前正在按下多少个按钮以及它们是哪些
按钮,适用于设备上任意数量的鼠标按钮。例如,
值 3 表示左键和右键当前都被
按下,而值 5 表示左键和中键当前都被
按下。
此属性的 未初始化值
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
将 screenX 属性初始化为 MouseEvent 对象所需的
鼠标指针在用户屏幕上的水平相对位置。
将事件对象初始化为给定鼠标位置不得将用户的鼠标 指针移动到初始化位置。
screenY
将 screenY 属性初始化为 MouseEvent 对象所需的
鼠标指针在用户屏幕上的垂直相对位置。
将事件对象初始化为给定鼠标位置不得将用户的鼠标 指针移动到初始化位置。
clientX
将 clientX 属性初始化为 MouseEvent 对象所需的
鼠标指针相对于用户浏览器客户端窗口的水平
位置。
将事件对象初始化为给定鼠标位置不得将用户的鼠标 指针移动到初始化位置。
clientY
将 clientY 属性初始化为 MouseEvent 对象所需的
鼠标指针相对于用户浏览器客户端窗口的垂直
位置。
将事件对象初始化为给定鼠标位置不得将用户的鼠标 指针移动到初始化位置。
button
将 button 属性初始化为 MouseEvent 对象中表示
鼠标按钮所需状态的数字。
值 0 用于表示主鼠标按钮,1 用于表示 辅助/中间鼠标按钮,2 用于表示右鼠标按钮。大于 2 的数字 也是可能的,但本文档未指定。
buttons
将 buttons 属性初始化为 MouseEvent 对象中表示
鼠标按钮中被认为处于活动状态的一个或多个按钮的数字。
buttons 属性是
位字段。如果掩码值 1 应用于该位字段的值时为 true,则
主鼠标按钮处于按下状态。如果掩码值 2 应用于该位字段的值
时为 true,则右鼠标按钮处于按下状态。如果掩码值 4 应用于
该位字段的值时为 true,则辅助/中间按钮处于按下状态。
在 JavaScript 中,要将 buttons
属性初始化为仿佛右键 (2) 和中键 (4) 被同时按下,
buttons 值可以指定为:
{ buttons: 2 | 4 }
或:
{ buttons: 6 }
relatedTarget
relatedTarget 应初始化为
鼠标指针刚刚离开其边界的元素(对于 mouseover 或 mouseenter 事件),或初始化为
鼠标指针正在进入其边界的元素(对于 mouseout、mouseleave 或 focusout 事件)。对于其他事件,
无需指定此值(并将默认为 null)。
实现 MUST 在 生成鼠标事件时维护 当前点击计数。这 MUST 是一个非负整数,表示在特定时间内 指点设备按钮连续点击的次数。计数重置前的延迟 由环境配置决定。
本节中的算法假定原生平台 OS 将提供以下内容:
对于这些事件,OS 将能够提供以下信息:
本节需要修订。
通常,当调用 Event 接口的构造器,或调用继承自
Event 接口的接口构造器时,应遵循
[DOM] 中描述的步骤。然而,MouseEvent 接口提供额外的
字典成员,用于初始化 Event 对象的键
修饰键内部状态:具体来说,即使用 getModifierState()
方法查询的内部状态。本节补充 [DOM] 中用于用这些可选修饰键
状态初始化新的 MouseEvent 对象的步骤。
为了构造 MouseEvent,或使用以下算法从这些对象
派生出的对象,所有 MouseEvent 及其派生
对象都具有 内部键修饰键状态,可以使用
[UIEvents-Key] 中
Modifier Keys 表描述的
键修饰键名称来设置和检索。
以下步骤补充 [DOM] 中定义的构造事件算法:
Event 是 MouseEvent 对象,或是从其派生的对象,
并且构造器被提供了 EventModifierInit
参数,则运行以下子步骤:
EventModifierInit
参数,如果字典成员以字符串 "modifier" 开头,则
令 键修饰键名称为该字典
成员名去掉前缀 "modifier" 后的名称,并将 Event 对象的、与该
键修饰键名称匹配的 内部键
修饰键状态设置为对应
值。
本节需要修订。
UA 必须维护以下在整个用户代理中共享的值。
一个用于跟踪鼠标按钮当前状态的 鼠标按钮位掩码。
UA 必须维护以下在 Window 中共享的值。
一个 最后
鼠标元素值(初始为 undefined),用于跟踪我们最后发送
MouseEvent 的 Element。
一个 最后
鼠标 DOM 路径值(初始为空),包含最近一次鼠标
事件被发送时 最后鼠标元素的祖先 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 设置为事件发生位置
相对于 视口原点的 x 坐标
clientY 设置为事件发生位置
相对于 视口原点的 y 坐标
button 设置为 0
buttons 设置为 鼠标按钮位掩码
我们应为 PointerLock 提供钩子,而不是在这里硬编码。
本节需要修订。
MouseEvent
shiftKey 设置为 true,否则设置为 falsectrlKey 设置为 true,否则设置为 falsealtKey 设置为 true,否则
设置为 false
metaKey 设置为 true,否则设置为 false本节需要修订。
MouseEvent 类型的 DOMString
EventTarget
MouseEvent 创建事件的结果
本节需要修订。
MouseEvent 类型的 DOMString
EventTarget
MouseEvent 创建事件的结果
本节需要修订。
MouseEvent
TODO。
type 是 [
mousedown, mouseup ] 之一,则
button
设置为
使用 mbutton 计算 MouseEvent button
属性的结果
本节需要修订。
其他按钮可以从 0x08 开始添加。
本节需要修订。
其他鼠标事件可以发生在 mousedown 和 mouseup 之间。
本节需要修订。
对于会生成点击的 mouseup,平台应在 处理原生 mouse up 之后立即调用此算法。
本节需要修订。
EventTarget
screenX
不是整数值,则将其舍入。screenY
不是整数值,则将其舍入。有关浏览器使用 PointerEvents 和舍入坐标的信息,请参见 pointerevents/100。
任何“默认动作”都在分派期间通过触发目标的 激活 行为 算法来处理。因此这里无需处理。 但是,需要验证现有规范是否处理了 disabled/css-pointer-events/inert/...
要处理 HTMLelement.click(),请使用 native =
null 且 target = HTMLelement 调用此算法。
要处理由键盘发起的点击,请使用 native = null 且 target = 当前聚焦元素调用此算法。
本节需要修订。
对于会生成双击的鼠标点击,这应在 handle native mouse click 之后立即调用。
screenX 不是整数值,则
将其舍入。screenY 不是整数值,则
将其舍入。本节需要修订。
此算法对 PointerEvents 的分派作出假设,因为它们 目前尚未被明确指定。一旦 pointerevents/285 得到解决,这里可能需要更新。
TODO:从 native 设置 mouseout 属性。+CSSOM 属性。
验证被取消时的行为(看起来没有影响)。
处理 element 已被删除的情况。 还要处理它已被移动的情况:DOM 变更是否应该触发 mouseleave 事件?我们现在是否应该发送它?是否应该丢弃它? 需要验证当前浏览器的行为。
Event.composed
= false
检查兼容性:event.composed 的值。规范称为 false。Chrome/Linux = true。Firefox/Linux = false。
TODO:从 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 的三个元素 在网页上都具有相同的尺寸和绝对位置。元素 C 是 B 的子元素,而 B 在 DOM 中是 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
|
OPTIONAL,多个事件,一些限制 |
| 3 | mouseup
|
|
| 4 | click
|
|
| 5 | mousemove
|
OPTIONAL,多个事件,一些限制 |
| 6 | mousedown
|
|
| 7 | mousemove
|
OPTIONAL,多个事件,一些限制 |
| 8 | mouseup
|
|
| 9 | click
|
|
| 10 | dblclick
|
在 mousedown 和 mouseup 事件之间,仍会触发 click 或 dblclick
事件时所允许的 mousemove 事件的滞后时间、程度、距离和数量,
将是实现、设备和平台特定的。这种容差可以帮助身体残障用户,例如手部不稳的用户,
在这些用户与指点设备交互时使用。
每个实现都会确定适当的 迟滞
容差,但通常在关联的 mousedown
和
mouseup 事件的事件目标是同一元素,且中间没有
mouseout 或
mouseleave 事件介入时,SHOULD 触发
click 和 dblclick
事件;并且当
关联的 mousedown 和 mouseup 事件目标
不同时,SHOULD 在最近的公共包含性
祖先上触发 click 和
dblclick 事件。
如果 mousedown 事件以 HTML 文档的 body
元素为目标,而对应的 mouseup 事件以
文档元素为目标,
则 click 事件将被分派
到 文档
元素,因为它是最近的公共包含性
祖先。
如果 目标(例如 目标元素)在鼠标事件序列期间被从 DOM 中移除,则该序列的剩余事件 MUST NOT 在该元素上触发。
如果目标元素由于
mousedown 事件而被从 DOM 中移除,则不会为该元素
分派
mouseup、click 或 dblclick 的事件,也不会分派任何默认
激活事件。然而,在初始目标元素被移除后,暴露给鼠标的元素仍会收到
mouseup 事件。
类似地,如果目标元素在 mouseup 事件的分派期间
被从 DOM 中移除,则
click 和后续事件将不会被分派。
| 类型 | auxclick
|
|---|---|
| 接口 | PointerEvent
|
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| Composed | 是 |
| 默认动作 | 可变 |
| 上下文 (受信任事件) |
|
当用户按下并释放非主指针按钮,或以模拟此类动作的方式
激活指针时,auxclick 事件类型 MUST
被分派到指针所指示的 最上层
事件目标上。鼠标按钮的致动
方法取决于指针设备和
环境配置,例如,它 MAY 取决于屏幕
位置,或指点设备按钮按下与释放之间的延迟。
auxclick 事件应仅为
非主指针
按钮触发(即,当 button 值不是 0,
buttons 值大于
1 时)。主按钮
(例如标准鼠标上的左键)MUST NOT 触发
auxclick 事件。有关与主按钮
相关联的对应事件,请参见 click。
auxclick 事件 MAY 之前可有同一元素上的
mousedown 和
mouseup 事件,忽略
其他节点类型(例如文本节点)之间的变化。取决于
环境配置,如果在指点设备按钮按下与
释放之间发生了一个或多个 mouseover、
mousemove 和 mouseout 事件类型,则 auxclick 事件 MAY 被分派。
auxclick 事件类型的
默认动作
会根据该事件的 目标以及
button 或 buttons 属性的值而变化。auxclick 事件类型的典型
默认动作如下:
myLink.addEventListener("auxclick", function(e) {
if (e.button === 1) {
// 这会阻止默认行为,例如
// 在链接上点击中键时打开新标签页。
e.preventDefault();
// 执行其他操作来处理中键点击,例如以适合该应用的方式
// 负责在新标签页中打开链接或非链接按钮。
// 其他动作,例如关闭标签条中的标签页,
// 这些应在点击动作中完成的动作,也可以在这里完成。
}
});
对于右键,auxclick 事件会在
任何 contextmenu 事件之后分派。注意,一些用户
代理会在上下文菜单显示期间吞掉所有输入
事件,因此在这些场景中 auxclick 可能无法供应用使用。
更多说明请参见 示例 7。
myDiv.addEventListener("contextmenu", function(e) {
// 此调用确保不显示上下文菜单,
// 以免干扰页面接收事件。
e.preventDefault();
});
myDiv.addEventListener("auxclick", function(e) {
if (e.button === 2) {
// 执行其他操作来处理右键点击,例如打开
// 应用内的自定义上下文菜单。
}
});
| 类型 | click
|
|---|---|
| 接口 | PointerEvent
|
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| Composed | 是 |
| 默认动作 | 可变 |
| 上下文 (受信任事件) |
|
当用户按下并释放主指针按钮,或以模拟此类动作的方式
激活指针时,click 事件类型 MUST 被
分派到指针所指示的 最上层
事件目标上。鼠标按钮的致动
方法取决于指针设备和
环境配置,例如,它 MAY 取决于屏幕
位置,或指点设备按钮按下与释放之间的延迟。
click 事件应仅为主
指针
按钮触发(即,当 button 值为 0,
buttons 值为 1 时)。
次按钮
(例如标准鼠标上的中键或右键)MUST NOT 触发
click 事件。有关与非主按钮
相关联的对应事件,请参见 auxclick。
click 事件 MAY 之前可有同一元素上的
mousedown 和
mouseup 事件,忽略
其他节点类型(例如文本节点)之间的变化。取决于
环境配置,如果在指点设备按钮按下与
释放之间发生了一个或多个 mouseover、
mousemove 和 mouseout 事件类型,则 click 事件 MAY 被分派。click 事件 MAY
之后还可跟随 dblclick 事件。
如果用户在一个
<p> 元素的文本节点子节点上按下鼠标,该元素被设置了较大的
line-height,然后稍微移动鼠标,使其不再位于包含文本的区域上,
但仍在该 <p> 元素的包含
块内(即指针位于同一文本块的行与行之间,而不是
正好在文本节点上),随后释放鼠标,那么这很可能仍会触发
click 事件(如果它处于 click 的正常时间
迟滞范围内),因为
用户一直停留在同一元素的范围内。注意,用户代理生成的
鼠标事件不会分派到文本节点上。
除了与指针设备相关联外,
click 事件类型 MUST 作为元素
激活的一部分被分派。
为了获得最大的无障碍性,鼓励内容作者在为自定义
控件定义激活行为时使用
click 事件类型,而不是
mousedown 或 mouseup 等更特定于设备的
其他指点设备事件类型。
尽管 click 事件类型源于指针
设备(例如鼠标),但后续的实现增强已将其扩展到该关联之外,
因而它可被视为用于元素激活的
与设备无关的事件类型。
click 事件类型的
默认动作
会根据该事件的 目标以及
button 或 buttons 属性的值而变化。click 事件类型的典型
默认动作如下:
| 类型 | dblclick |
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| Composed | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
当指点设备的主按钮在某元素上被点击两次时,用户代理 MUST 分派此事件。
双击的定义取决于环境
配置,但事件目标在
mousedown、mouseup 和 dblclick 之间
MUST 相同。如果 click
和 double click 同时发生,则此事件
类型 MUST 在事件类型 click 之后分派;否则在事件类型
mouseup 之后分派。
与 click 事件一样,dblclick
事件应
仅为主指针按钮触发。次按钮 MUST NOT
触发 dblclick 事件。
click 事件类型一样,
dblclick 事件类型的 默认动作
会根据该事件的 目标以及
button
或 buttons 属性的值而变化。
dblclick 事件类型的典型
默认动作与
click 事件类型相匹配。
| 类型 | mousedown
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| Composed | 是 |
| 默认动作 | 可变:开始拖放操作;开始文本选择;开始滚动/平移 交互(如果支持,与鼠标中键结合使用) |
| 上下文 (受信任事件) |
|
| 类型 | mouseenter
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 否 |
| 受信任目标 | Element |
| 可取消 | 否 |
| Composed | 否 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mouseover,
但
不同之处在于它不冒泡,并且当指针设备从某元素移动到
其某个后代元素的边界上时,MUST NOT 分派它。
此事件类型与 CSS
:hover 伪类 [CSS2]
存在相似之处。
另请参见 mouseleave 事件类型。
| 类型 | mouseleave
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 否 |
| 受信任目标 | Element |
| 可取消 | 否 |
| Composed | 否 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mouseout,
但不同之处在于它不冒泡,并且只有在指点设备已经离开该
元素的边界以及其所有子元素的边界之后,MUST NOT 才能
分派它。
此事件类型与 CSS
:hover 伪类 [CSS2]
存在相似之处。
另请参见 mouseenter 事件类型。
| 类型 | mousemove
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| Composed | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mousemove
事件,
而不是为每次鼠标移动实例触发单个事件。鼓励实现
确定最佳频率,以在响应性与性能之间取得平衡。
在某些实现环境中,例如浏览器中,如果用户开始了
拖动操作(例如按下鼠标按钮),并且指点
设备已离开用户代理的边界,mousemove 事件仍可继续触发。
此事件以前在 DOM Level 2 Events 中被指定为不可取消,但后来更改为反映 用户代理之间现有的互操作性。
| 类型 | mouseout
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| Composed | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mouseleave,但不同之处在于
它会冒泡,并且当指针设备从某元素移动到其某个后代元素的边界上时,
MUST 分派它。
另请参见 mouseover 事件类型。
| 类型 | mouseover
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| Composed | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mouseenter,但不同之处在于
它会冒泡,并且当指针设备移动到某元素的边界上,而该元素的祖先元素是同一
事件监听器实例的
目标时,MUST 分派它。
另请参见 mouseout 事件类型。
| 类型 | mouseup
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| 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导致该事件的指针的唯一标识符。用户代理 MAY
为主鼠标指针保留一个通用的 pointerId
值
0 或 1。pointerId 值
-1 MUST 保留并用于指示
由指点设备之外的其他内容生成的事件。对于任何其他指针,用户
代理可以自由实现不同的策略和方法来分配 pointerId
值。然而,顶级
浏览上下文(如 [HTML] 所定义)中的所有
活动指针都必须是唯一的,并且该
标识符 MUST NOT 受任何其他顶级浏览
上下文影响(即,一个顶级浏览上下文不能假定当指针移出该浏览上下文并进入另一个
顶级浏览上下文时,指针的 pointerId
会保持相同)。
用户代理
MAY 回收先前活动指针中已经退役的 pointerId 值,或者它
MAY 始终为特定指点设备重用相同的 pointerId
(例如,为了在多用户协作应用中唯一标识来自特定用户的特定笔/触控笔
输入)。然而,在后一种情况下,为了尽量减少跨不同页面或
域进行指纹识别和跟踪的可能性,pointerId
MUST 只在页面 / 会话的生命周期内明确地与该特定指点
设备相关联,并且在下一次该特定指点设备在新会话中再次使用时,
MUST 选择一个新的随机化 pointerId。
pointerId 选择
算法是特定于实现的。作者不能假定这些值传达任何特定含义,除
了它是指针的标识符,并且与所有其他活动指针唯一不同。例如,用户代理
可以简单地从 0 开始,按照指针变为活动的顺序,为任何活动
指针分配一个数字——但这些值不保证单调递增。由于是否为特定
指点设备重用相同的 pointerId 由各个实现自行决定,
因此强烈建议作者不要依赖它,而应改用 persistentDeviceId。
width指针的接触几何形状的宽度(X 轴上的大小),
以 CSS 像素为单位(见 [CSS21])。
对于给定指针,此值 MAY 在每个事件上更新。对于
通常缺少接触几何形状的输入(例如传统鼠标),以及输入的实际几何形状未被硬件检测到的情况,
用户代理 MUST 返回默认值 1。
height指针的接触几何形状的高度(Y 轴上的大小),
以 CSS 像素为单位(见 [CSS21])。
对于给定指针,此值 MAY 在每个事件上更新。对于
通常缺少接触几何形状的输入(例如传统鼠标),以及输入的实际几何形状未被硬件检测到的情况,
用户代理 MUST 返回默认值 1。
pressure范围为 [0,1] 的指针输入归一化压力,其中
0 和 1 分别表示硬件能够检测到的最小和最大压力。
对于不支持压力的硬件和平台,该值在活动按钮状态下 MUST 为 0.5,否则为 0。
tangentialPressure指针输入的归一化切向压力(也称为笔杆压力),通常由额外控制装置
(例如喷枪触控笔上的指轮)设置,范围为 [-1,1],其中
0 为该控制装置的中性位置。请注意,某些硬件可能只支持
[0,1] 范围内的正值。对于不支持切向压力的硬件和平台,该值
MUST 为 0。
tiltXY-Z 平面与同时包含换能器(例如笔/触控笔)轴和 Y 轴的平面之间的
平面角(以度为单位,范围为 [-90,90])。正的
tiltX 指向右侧,即 X 值增大的方向。
tiltX 可以与 tiltY 一起用于表示换能器相对于数字化仪
法线的倾斜。对于不报告倾斜或角度的硬件和平台,该值
MUST 为 0。
tiltX。
tiltYX-Z 平面与同时包含换能器(例如笔/触控笔)轴和 X 轴的平面之间的
平面角(以度为单位,范围为 [-90,90])。正的
tiltY 指向用户,即 Y 值增大的方向。
tiltY 可以与 tiltX 一起用于表示换能器相对于数字化仪
法线的倾斜。对于不报告倾斜或角度的硬件和平台,该值
MUST 为 0。
tiltY。
twist换能器(例如笔/触控笔)围绕其自身主轴的顺时针旋转角度
(以度为单位,范围为 [0,359])。对于不报告
twist 的硬件和平台,该值 MUST 为 0。
altitudeAngle换能器(例如笔/触控笔)的高度角(以弧度为单位),范围为
[0,π/2] —— 其中 0 表示平行于表面(X-Y 平面),
π/2 表示垂直于表面。对于不报告倾斜或角度的硬件和平台,
该值 MUST 为 π/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),该值 MUST 为 0。
对于不报告倾斜或角度的硬件和平台,该值 MUST 为
0。
azimuthAngle
为 π/6(“4 点钟”)的示例。pointerType指示导致该事件的设备类型(例如 mouse、pen、touch)。如果用户
代理要为鼠标、笔/触控笔或触摸输入设备触发指针事件,
则 pointerType 的值 MUST 符合下表:
| 指针设备类型 | pointerType 值 |
|---|---|
| 鼠标 | mouse |
| 笔 / 触控笔 | pen |
| 触摸接触点 | touch |
如果用户代理无法检测到设备类型,则该值 MUST 为空字符串。如果用户代理支持上文未列出的指针设备
类型,则 pointerType 的值 SHOULD 带有厂商前缀,以避免不同类型设备的名称冲突。
未来规范 MAY 为其他设备类型提供额外的规范性
值。
pointerType 如何使用的基本演示,请参见
示例 2。另请注意,开发者
应包含某种形式的默认处理,以覆盖用户代理可能已经实现了自己的自定义
pointerType 值的情况,以及
pointerType 只是空字符串的情况。
isPrimary指示该指针是否表示此指针类型的主指针。
persistentDeviceId指点设备的唯一标识符。如果硬件支持多个指针,则只有当这些指针在
会话期间可被唯一标识时,从指点设备生成的指针事件 MUST
才能获得
persistentDeviceId。如果指针可被唯一标识,则分配给该指点设备的
persistentDeviceId 将在该会话剩余期间保持不变。
persistentDeviceId 值 0 MUST
保留并用于指示生成设备无法被标识的事件。
与 pointerId 一样,为了尽量减少
跨不同页面或域进行指纹识别和跟踪的可能性,
persistentDeviceId MUST 只在页面 / 会话的生命周期内
明确地与该特定指点设备相关联,并且下一次该特定指点设备在新会话中再次使用时,
MUST 选择一个新的随机化
persistentDeviceId。
persistentDeviceId。例如,设备可能没有及时
向数字化仪报告其硬件 ID,导致 pointerdown 没有
persistentDeviceId。在这种情况下,persistentDeviceId 可能
最初为 0,随后变为有效值。
getCoalescedEvents()返回合并事件列表的方法。
getPredictedEvents()返回预测事件列表的方法。
PointerEventInit 字典由 PointerEvent 接口的构造器使用,用于
提供一种构造不受信任(合成)指针事件的机制。它继承自
[UIEVENTS] 中定义的
MouseEventInit 字典。有关演示如何触发不受信任指针
事件的示例代码,请参见示例。
PointerEvent 的事件
构造步骤
会将 PointerEventInit 的 coalescedEvents 克隆到合并事件列表,并将
PointerEventInit 的 predictedEvents 克隆到预测事件列表。
PointerEvent 接口继承自 MouseEvent,后者定义于 UI
Events。
另请注意 CSSOM View Module 中提出的扩展,它会将
各种坐标属性从 long
改为 double,以允许小数坐标。对于已经为
PointerEvent 实现了此提议扩展,但
没有为普通
MouseEvent 实现该扩展的用户代理,在
click、
auxclick 和 contextmenu 事件方面还有额外
要求。
在多指针(例如多点触控)场景中,isPrimary 属性用于
在每种指针类型的活动指针集合中
标识一个主控指针。
pointerType 一个)会被视为主指针。例如,一个触摸接触点和
一个鼠标光标同时移动时,会产生两个都被视为主指针的指针。
isPrimary 值为 false 的指针事件。
触发
指针事件,其名称为 e,是指使用 触发一个事件,其名称为 e,
并使用 PointerEvent,其属性按
PointerEvent 接口和
属性和默认动作中的定义进行设置。
如果事件不是 gotpointercapture、lostpointercapture、click、
auxclick 或 contextmenu 事件,则为
此 PointerEvent 运行处理待处理的指针捕获步骤。
按如下方式确定 目标,事件会在该目标上触发:
令 targetDocument 为 target 的节点文档 [DOM]。
如果事件是 pointerdown、pointermove 或 pointerup,则将该事件的 活动文档
设置为 targetDocument,该活动文档对应事件的 pointerId。
如果事件是 pointerdown,关联
设备是直接操纵设备,且目标是一个 Element,
则按照隐式指针捕获中所述,为此 pointerId 将设置指针捕获到目标元素。
在触发此事件之前,用户代理 SHOULD
为了确保事件顺序,将目标视为指点设备已经从
previousTarget 移动到其上 [UIEVENTS]。如果
needsOverEvent 标志被设置,则即使目标
元素相同,也需要一个 pointerover 事件。
向确定的目标触发该事件。
将确定的目标保存为给定指针的 previousTarget,
并将 needsOverEvent 标志重置为 false。
如果 previousTarget 在任何时候不再已连接 [DOM],
则按照与向 previousTarget 分派事件对应的事件路径,
将 previousTarget 更新为最近的仍然已连接 [DOM] 的父节点,
并将 needsOverEvent 标志设置为 true。
本规范中定义的事件类型的 bubbles 和 cancelable 属性以及默认动作
显示在下表中。每个事件类型的细节在Pointer Event 类型中提供。
| 事件类型 | 冒泡 | 可取消 | 默认动作 |
|---|---|---|---|
pointerover
|
是 | 是 | 无 |
pointerenter |
否 | 否 | 无 |
pointerdown
|
是 | 是 | 可变:当指针为主指针时,mousedown 事件的所有默认动作
取消此事件还会阻止后续兼容性鼠标事件的触发。 |
pointermove
|
是 | 是 | 可变:当指针为主指针时,mousemove 的所有默认动作
|
pointerrawupdate |
是 | 否 | 无 |
pointerup |
是 | 是 | 可变:当指针为主指针时,mouseup 的所有默认动作
|
pointercancel |
是 | 否 | 无 |
pointerout
|
是 | 是 | 无 |
pointerleave |
否 | 否 | 无 |
gotpointercapture |
是 | 否 | 无 |
lostpointercapture |
是 | 否 | 无 |
视口操纵(平移和缩放)——通常是直接操纵交互的结果——
有意不作为指针事件的默认动作,这意味着这些行为(例如由于在触摸屏上移动手指而
平移页面)不能通过取消指针事件来抑制。作者必须改用 touch-action 为
文档的某一区域显式声明直接操纵行为。
移除对事件取消的这种依赖,有助于用户代理进行性能优化。
对于 pointerenter 和 pointerleave 事件,composed
[DOM] 属性 SHOULD 为
false;对于上表中的所有其他指针事件,该属性 SHOULD 为 true。
对于上表中的所有指针事件,detail [UIEVENTS] 属性 SHOULD 为 0。
fromElement 和
toElement 以支持旧内容。我们鼓励这些用户
代理将 PointerEvents 中这些(继承的)属性的值设置为
null,以便将作者过渡到使用标准化的替代项
(target 和 relatedTarget)。
与 MouseEvent relatedTarget 类似,
relatedTarget 应初始化为指针刚离开其边界的元素(在 pointerover 或
pointerenter 事件的情况下),或初始化为指针正在进入其边界的元素(在
pointerout 或 pointerleave 的情况下)。对于其他指针事件,
此值将默认为 null。请注意,当某个元素接收指针捕获时,该指针随后的所有事件都被视为位于捕获
元素的边界内。
对于 gotpointercapture
和 lostpointercapture 事件,除上表中定义的属性外,
所有属性都应与导致用户代理运行处理待处理的指针捕获步骤并触发
gotpointercapture
和 lostpointercapture 事件的 Pointer Event
相同。
用户代理 MUST 在隐式释放指针
捕获时,以及在触发不是 gotpointercapture 或 lostpointercapture 的 Pointer Events
时,运行以下步骤。
lostpointercapture 的指针事件。
gotpointercapture 的指针事件。
如click、
auxclick 和 contextmenu 事件章节所定义,即使在
lostpointercapture 事件已经
被分派之后,
对应的 click、auxclick 或 contextmenu
事件(如果有)仍会被分派到捕获目标。
当用户代理检测到
网页不太可能继续接收具有特定 pointerId 的指针事件时,
MUST 抑制指针事件流。以下任何场景
都满足此条件(MAY 还有其他场景):
touch-action CSS
属性的章节。
pointercancel
事件。pointerout 事件。
pointerleave 事件。
相对于屏幕表面移动,或其任一属性发生某些变化的指点设备,会触发
Pointer Event 类型中定义的各种事件。
对于静止的指点设备(既未相对于屏幕表面移动,也未经历任何属性变化),
如果布局变化影响了该指针的命中测试目标,
则用户代理 MUST
在布局变化后触发某些边界事件,详见 pointerover、pointerenter、pointerout 和 pointerleave。出于性能原因(例如为了避免
过多的命中测试,或避免边界事件监听器导致过多的布局变化),用户代理 MAY
延迟触发这些边界事件。
pointermove 事件。Pointer Events 包含两组互补的属性,用于表示换能器相对于 X-Y 平面的方向:
tiltX / tiltY(在原始 Pointer Events 规范中引入),以及
azimuthAngle / altitudeAngle
(采自 Touch Events - Level 2
规范)。
取决于具体硬件和平台,用户代理很可能只会接收到一组表示换能器相对于屏幕平面方向的
值——要么是 tiltX /
tiltY,要么是 altitudeAngle / azimuthAngle。用户代理 MUST 使用以下算法来转换这些值。
当用户代理根据 azimuthAngle
/ altitudeAngle 计算 tiltX / tiltY 时,它 SHOULD 使用
Math.round [ECMASCRIPT] 规则对最终整数值进行舍入。
/* 在 tiltX/tiltY 和 altitudeAngle/azimuthAngle 之间转换 */
function spherical2tilt(altitudeAngle, azimuthAngle) {
const radToDeg = 180/Math.PI;
let tiltXrad = 0;
let tiltYrad = 0;
if (altitudeAngle == 0) {
// 笔位于 X-Y 平面内
if (azimuthAngle == 0 || azimuthAngle == 2*Math.PI) {
// 笔在正 X 轴上
tiltXrad = Math.PI/2;
}
if (azimuthAngle == Math.PI/2) {
// 笔在正 Y 轴上
tiltYrad = Math.PI/2;
}
if (azimuthAngle == Math.PI) {
// 笔在负 X 轴上
tiltXrad = -Math.PI/2;
}
if (azimuthAngle == 3*Math.PI/2) {
// 笔在负 Y 轴上
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;
// 计算方位角
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) {
// 没有足够信息来计算方位角
azimuthAngle = 0;
} else {
// 非边界情况:tiltX 和 tiltY 都不等于 0 或 +-90
const tanX = Math.tan(tiltXrad);
const tanY = Math.tan(tiltYrad);
azimuthAngle = Math.atan2(tanY, tanX);
if (azimuthAngle < 0) {
azimuthAngle += 2*Math.PI;
}
}
// 计算高度角
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 {
// 非边界情况:tiltX 和 tiltY 都不等于 0 或 +-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 复制到 event
MouseEventTODO。
targetMouseEventTODO。
targetMouseEventTODO。
targetMouseEventTODO。
targetMouseEvent
这可以发送 pointermove 和 pointerrawupdate 吗?还是我们需要 2 个方法?
要正确定义 pointermove 事件如何被合并,需要什么?
TODO。
targetMouseEvent
与 mousedown 事件不同,当按下多个按钮时,pointerdown
事件不会嵌套。
传入 MouseEvent,
以便将字段复制到 PointerEvent 中。
TODO。
targetMouseEvent
targetMouseEvent
与 mouseup 事件不同,当按下多个按钮时,pointerup 事件不会嵌套。
传入 MouseEvent,以便将字段
复制到 PointerEvent 中。
TODO。
target以下是本规范中定义的事件类型。
在主指针的情况下,这些事件(gotpointercapture 和 lostpointercapture 除外)也可能触发兼容性鼠标事件。
当以下任一情况发生时,用户代理 MUST 触发一个指针事件,其名称为 pointerover:
pointerdown 事件之前
(参见 pointerdown)。当以下任一情况发生时,用户代理 MUST 触发一个指针事件,其名称为 pointerenter:
pointerdown 事件之前
(参见 pointerdown)。当指针进入活动按钮状态时,用户代理 MUST 触发一个指针事件,其名称为 pointerdown。对于鼠标,这是指
设备从没有按下任何按钮转换为至少按下一个按钮时。对于触摸,这是指
与数字化仪发生物理接触时。对于笔,这是指笔
在没有按下任何按钮的情况下与数字化仪发生物理接触,或者在悬停时从
没有按下任何按钮转换为至少按下一个按钮时。
对于不支持
悬停的输入设备,用户
代理 MUST 还在分派 pointerdown 事件之前,触发一个指针
事件,其名称为 pointerover,随后触发一个
名为 pointerenter 的
指针事件。
pointerdown 事件(如果
isPrimary 属性为 true)来阻止某些兼容性鼠标事件的触发。这会在该指针上设置
PREVENT MOUSE EVENT 标志。不过请注意,这不会阻止
mouseover、mouseenter、mouseout 或
mouseleave 事件触发。
当指针更改了不会触发
pointerdown 或 pointerup 事件的任何属性时,用户代理 MUST 触发一个指针事件,其名称为 pointermove。这包括
坐标、压力、切向压力、倾斜、twist、接触几何形状(width 和 height)或组合按钮的任何变化。
用户代理 MAY 延迟分派 pointermove 事件(例如,出于性能原因)。
合并事件信息将通过单个已分派的 pointermove 事件上的getCoalescedEvents 方法暴露。
应使用此类事件的最终坐标来查找事件的目标。
当指针更改了不会触发
pointerdown 或 pointerup 事件的任何属性时,用户代理 MUST 触发一个指针事件,
其名称为 pointerrawupdate,并且
只在安全上下文中
这样做。此类属性的列表请参见 pointermove 事件。
与 pointermove 相比,用户代理
SHOULD 尽可能快地,并以 JavaScript 能够处理这些事件的频率,
分派 pointerrawupdate 事件。
pointerrawupdate 事件的
target 可能不同于 pointermove 事件,
原因是 pointermove 事件可能
被延迟或合并,并且用于查找 target 的事件最终位置
可能不同于其合并事件。
注意,如果已经存在另一个具有相同 pointerId 且尚未在事件循环中
被分派的 pointerrawupdate,
则用户代理 MAY 将新的 pointerrawupdate 与该事件合并,而不是
创建新的任务。
这可能导致 pointerrawupdate
具有合并事件,并且一旦该事件在事件循环中被处理,
它们都会作为一个 pointerrawupdate 事件的合并事件被交付。
更多信息请参见getCoalescedEvents。
就 pointerrawupdate 和 pointermove 的顺序而言,
如果用户代理从平台接收到会导致 pointerrawupdate 和 pointermove 事件的更新,
则用户代理 MUST 在对应的 pointermove 之前分派
pointerrawupdate 事件。
除了 target 之外,自上一个 pointermove 事件以来,
所有已分派的 pointerrawupdate
事件的合并事件列表连接起来,
就其他事件属性而言,与下一个 pointermove 事件的合并事件相同。
pointerrawupdate 的属性
大多与 pointermove 相同,例外是
cancelable,对于 pointerrawupdate,它 MUST 为 false。
用户代理 SHOULD 不为 pointerrawupdate 触发兼容性鼠标事件。
pointerrawupdate
事件添加监听器可能会
对网页性能产生负面影响,具体取决于用户代理的实现。
对于大多数用例,其他 pointerevent 类型应当足够。
只有当 JavaScript 需要高频事件并且能够同样快速地处理它们时,才应添加
pointerrawupdate
监听器。
在这些情况下,可能无需监听其他类型的指针事件。
当指针离开活动按钮状态时,用户代理 MUST 触发一个指针事件,其名称为 pointerup。对于鼠标,这是指
设备从至少按下一个按钮转换为没有按下任何按钮时。对于触摸,这是指
从数字化仪移除物理接触时。对于笔,这是指笔
在没有按下任何按钮的情况下从与数字化仪的物理接触中移开,或者在悬停时从
至少按下一个按钮转换为没有按下任何按钮时。
对于不支持
悬停的输入设备,用户
代理 MUST 还在分派 pointerup
事件之后,触发一个指针
事件,其名称为 pointerout,随后触发一个
名为 pointerleave 的
指针事件。
所有 pointerup 事件的 pressure
值均为 0。
如果指针当前已被捕获,用户代理 MUST 还隐式释放指针 捕获。
当检测到要抑制指针事件流的场景时,用户代理 MUST 触发一个指针事件,其名称为 pointercancel。
pointercancel 事件的以下属性的值 MUST 与具有相同 pointerId
的最后一个已分派指针事件的值相匹配:
width、height、pressure、tangentialPressure、tiltX、
tiltY、twist、altitudeAngle、azimuthAngle、
pointerType、isPrimary,以及从 [UIEVENTS] 继承的坐标。pointercancel 事件中的
coalescedEvents 和
predictedEvents 列表 MUST 为空,并且该事件的 cancelable 属性
MUST 为 false。
当以下任一情况发生时,用户代理 MUST 触发一个指针事件,其名称为 pointerout:
当以下任一情况发生时,用户代理 MUST 触发一个指针事件,其名称为 pointerleave:
pointerup 事件之后
(参见 pointerup)。
当某元素接收指针捕获时,用户代理 MUST 触发一个指针事件,其名称为 gotpointercapture。
此事件会在正在接收指针捕获的元素上触发。该指针的后续事件将在此元素上触发。请参见设置指针捕获和处理待处理的指针捕获章节。
在某指针的指针捕获被释放之后,用户代理 MUST 触发一个指针事件,其名称为 lostpointercapture。
此事件 MUST 在捕获被释放后该指针的任何后续事件之前触发。
此事件会在其指针捕获被移除的元素上触发。该指针的所有后续事件,除click、
auxclick 和 contextmenu 事件外,都遵循正常的命中测试
机制(不在本规范范围内)来确定事件目标。请参见释放指针捕获、隐式释放指针
捕获和处理待处理的指针
捕获章节。
用户的环境可能被配置为将垂直滚动 与沿 y 轴的旋转关联,将水平滚动与沿 x 轴的旋转关联,将缩放与沿 z 轴的旋转关联。
WheelEvent 对象的 deltaX、deltaY 和 deltaZ 属性表示
沿其各自轴的测量值,单位为像素、行或
页。报告的测量值是在环境特定
算法将滚轮设备的实际旋转/移动转换为
适当值和单位之后提供的。
用户的环境设置可以被自定义,以不同方式解释滚轮设备的实际旋转/移动。
常见的有齿
鼠标滚轮的一次移动可以产生 162 像素的测量值
(162 只是一个示例值,实际值可能取决于用户代理的当前屏幕
尺寸)。
但用户可以更改其默认环境设置来加快鼠标滚轮,
从而增大这个数字。
此外,某些鼠标滚轮软件可以支持加速度(滚轮
旋转/移动得越快,每次测量的 delta 越大)甚至亚像素旋转
测量。
因此,作者不能假定在一个用户代理中给定的旋转量会在所有用户代理中
产生相同的 delta
值。
wheel 事件之间保持一致。
如果用户代理将滚动作为
wheel 事件的默认动作,则 delta 的符号
SHOULD 由右手坐标系给出,其中正 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;
readonly attribute boolean momentum;
};
DOM_DELTA_PIXELDOM_DELTA_LINEDOM_DELTA_PAGEdeltaXwheel
事件的默认动作为滚动的用户代理中,如果事件未被取消,
该值 MUST 为要沿 x 轴滚动的测量值
(以像素、行或页为单位)。否则,这是滚轮设备围绕
x 轴移动的实现特定测量值(以像素、行或页为单位)。
此属性的未初始化值
MUST 为
0.0。
deltaYwheel
事件的默认动作为滚动的用户代理中,如果事件未被取消,
该值 MUST 为要沿 y 轴滚动的测量值
(以像素、行或页为单位)。否则,这是滚轮设备围绕
y 轴移动的实现特定测量值(以像素、行或页为单位)。
此属性的未初始化值
MUST 为
0.0。
deltaZwheel
事件的默认动作为滚动的用户代理中,如果事件未被取消,
该值 MUST 为要沿 z 轴滚动的测量值
(以像素、行或页为单位)。否则,这是滚轮设备围绕
z 轴移动的实现特定测量值(以像素、行或页为单位)。
此属性的未初始化值
MUST 为
0.0。
deltaModedeltaMode 属性包含对
delta
值测量单位的指示。默认值是
DOM_DELTA_PIXEL(像素)。
此属性 MUST 设置为 DOM_DELTA 常量之一,以指示
delta
值的测量单位。
精确测量是特定于设备、操作系统和应用配置的。
此属性的未初始化值
MUST 为
0。
momentumtrue,
否则为 false。
此属性的未初始化值
MUST 为
false。
WebIDLdictionary WheelEventInit : MouseEventInit {
double deltaX = 0.0;
double deltaY = 0.0;
double deltaZ = 0.0;
unsigned long deltaMode = 0;
boolean momentum = false;
};
当我们已经在上面定义了相应的 属性时,下面的定义似乎是冗余的。请参见 pointerevents/646。
deltaXdeltaZ 属性。deltaYdeltaZ 属性。deltaZdeltaZ 属性,该属性属于 WheelEvent
对象。此属性(以及
deltaX 和 deltaY 属性)的相对正值
由右手坐标系给出,其中 X、Y 和 Z 轴分别指向文档的
最右边缘、最下边缘和最远深度(远离用户)。
负的相对值则位于各自相反方向。
deltaMode
deltaMode 属性初始化到
WheelEvent 对象上,初始化为枚举值 0、
1 或 2,如果滚轮的旋转会导致滚动,则它们分别表示已滚动的像素量
(DOM_DELTA_PIXEL)、已滚动的行数
(DOM_DELTA_LINE)或已滚动的页数
(DOM_DELTA_PAGE)。
momentummomentum 属性。
| 类型 | wheel |
|---|---|
| 接口 | WheelEvent |
| 同步 / 异步 | 异步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 可变 |
| Composed | 是 |
| 默认动作 | 滚动(或缩放)文档 |
| 上下文 (受信任事件) |
|
wheel 事件交付,或者作为每个非零轴的单独
wheel 事件交付。
wheel 事件类型的典型默认动作是
按所指示的量滚动(或在某些情况下缩放)文档。如果此事件被取消,
实现 MUST NOT 滚动或缩放文档
(或执行与此事件类型关联的任何其他
实现特定默认动作)。
在 wheel 事件上调用 preventDefault 可以阻止
或以其他方式中断滚动。为了获得最大的滚动性能,用户代理
可以不等待与滚动相关联的每个 wheel 事件被处理,
以查看它是否会被取消。在这种情况下,用户代理应生成
cancelable 属性为 false 的 wheel 事件,
表明 preventDefault 不能用于阻止或中断
滚动。否则 cancelable 将为 true。
特别是,当用户代理观察到
该事件没有非被动监听器时,
应只生成不可取消的 wheel 事件。
以下章节描述对现有 Element 接口的扩展,以
便于设置和释放指针捕获。
WebIDLpartial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
setPointerCapture()为由参数 pointerId 标识的指针,向调用此方法的元素设置指针捕获。对于该指针的后续事件,捕获目标将
替代正常的命中测试结果,就像指针始终位于捕获目标之上一样,
并且这些事件 MUST 始终以此元素为目标,直到捕获被
释放。为了使此方法有效,指针 MUST 处于其活动按钮状态,否则它会静默失败。当提供的方法参数与任何
活动指针都不匹配时,抛出一个 "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 属性确定直接
操纵交互(尽管属性名称如此,但并不限于触摸)是否 MAY 触发用户代理的平移和缩放行为。参见
touch-action 值章节。
在开始平移或缩放之前,若以下所有条件均为 true,用户代理 MUST 抑制指针事件流:
pointerdown 事件,并且pointerup 或 pointercancel 事件(跟随上述
pointerdown)。
touch-action 不会应用/级联到嵌入的浏览上下文。
例如,即使将 touch-action 应用于 <iframe>,
也不会对 <iframe> 本身内部用于平移和缩放的直接操纵交互行为
产生任何影响。
当用户使用直接操纵指针(例如
触摸屏上的触摸或触控笔)与元素交互时,该输入的效果由
touch-action 属性的值,以及该元素及其祖先的默认直接操纵行为决定,如下:
touch-action。注意,如果应用了 CSS 变换,
元素的坐标空间可能不同于屏幕坐标,从而影响此处的一致性;例如,
相对于屏幕旋转 90 度的元素的 X 轴将平行于屏幕坐标的 Y 轴。
touch-action 属性,则支持该交互(如
[CSS-OVERFLOW-3] 中所定义)。
document 元素之间每个元素的
touch-action 属性,则支持该交互(如
[HTML] 中所定义)。
touch-action 值的任何更改
都将被忽略。例如,作为 pointerdown 处理器脚本的一部分,
以编程方式将某元素的 touch-action 值从
auto 改为 none,不会导致用户代理中止或抑制该输入的任何
平移或缩放行为,只要该指针仍处于活动状态。
pan-* 的 touch-action 值,一旦用户代理
在手势开始时确定是否直接处理某个手势,同一手势方向的后续变化 SHOULD
在该指针处于活动状态期间被用户代理忽略。例如,如果某元素被设置为
touch-action: pan-y(意味着只有垂直平移由用户代理处理),而触摸手势
以水平方向开始,则如果用户在其手指仍接触屏幕时将手势方向改为垂直,
也不应发生垂直平移。
touch-action 值的方法不在本规范范围内。touch-action 属性覆盖与视口平移
和缩放相关的直接操纵行为。任何额外的用户代理行为,例如文本选择/高亮,
或激活链接和表单控件,MUST NOT 受此 CSS 属性影响。
auto 或 none 值行为的交互或手势,
不在本规范范围内。pan-x 或 pan-y),在平移过程中不能改变轴。touch-action 值定义于 [COMPAT]。特定方向的 pan 值可用于自定义某些过度滚动行为。
例如,为实现简单的下拉刷新效果,当滚动位置为
0 时,文档的 touch-action 可以设置为
pan-x pan-down,否则设置为 pan-x pan-y。
这允许指针事件处理器定义从文档顶部开始的向上平移/滚动行为。
特定方向的 pan 值也可用于组合一个组件:该组件在原生滚动的元素内使用
指针事件处理来实现自定义平移(反之亦然)。
例如,图像轮播可以使用 pan-y 来确保它接收任何水平平移操作的指针事件,
且不会干扰文档的垂直平移。当轮播到达其最右端时,
它可以将其 touch-action 改为 pan-y pan-right,
以便超出其范围的后续滚动操作可以在可能的情况下滚动视口内的文档。
无法在平移/滚动操作正在进行时更改该操作的行为。
auto 时,用户
代理通常会在 click 之前添加 300ms 延迟,以便处理双击手势。
在这些情况下,显式设置 touch-action: none 或
touch-action: manipulation 将移除此延迟。请注意,确定轻触或双击手势的方法
不在本规范范围内。
<div style="touch-action: none;">
此元素接收所有否则会导致平移或缩放的直接操纵交互的指针事件。
</div>
<div style="touch-action: pan-x;">
当未在水平方向平移时,此元素接收指针事件。
</div>
<div style="overflow: auto;">
<div style="touch-action: none;">
此元素接收所有否则会导致平移或缩放的直接操纵交互的指针事件。
</div>
<div>
此元素上的直接操纵交互 MAY 被消耗用于操纵父元素。
</div>
</div>
<div style="overflow: auto;">
<div style="touch-action: pan-y;">
<div style="touch-action: pan-x;">
此元素接收所有直接操纵交互的指针事件,因为
它仅允许水平平移,而中间祖先
(位于它和可滚动元素之间)仅允许垂直平移。
因此,用户代理不会处理任何用于平移/缩放的直接操纵行为。
</div>
</div>
</div>
<div style="overflow: auto;">
<div style="touch-action: pan-y pan-left;">
<div style="touch-action: pan-x;">
当未向左平移时,此元素接收指针事件。
</div>
</div>
</div>
本节是非规范性的。
指针捕获允许将特定指针的事件(包括任何兼容性鼠标事件)重新定向到某个特定元素,
而不是指针位置的正常命中测试结果。
这在自定义滑块控件等场景中很有用(例如类似于 [HTML]
<input type="range"> 控件)。指针捕获可以设置在滑块拇指
元素上,从而允许用户来回滑动该控件,即使指针滑出了
拇指。
pointerdown 后,可以使用指针捕获
允许用户滑动拇指,即使指针偏离了它。
通过调用 element.setPointerCapture(pointerId) 方法,在 element
(类型为 Element)上设置指针捕获。
当调用此方法时,用户代理 MUST 运行
以下步骤:
pointerId
与任何活动指针都不匹配,则抛出一个 "NotFoundError" DOMException。pointerId 所指定的活动指针。
InvalidStateError" DOMException。pointerLockElement)时调用的,
则抛出一个 "InvalidStateError" DOMException。
pointerId,将待处理的指针捕获目标覆盖设置为调用此方法的
Element。
pointerdown 监听器中尝试释放隐式指针捕获失败的情况,也是如此。通过显式调用 element.releasePointerCapture(pointerId) 方法,
在元素上释放指针捕获。当调用此方法时,用户代理 MUST 运行以下步骤:
pointerId
与任何活动指针都不匹配,并且这些步骤
并非由于隐式释放指针
捕获而被调用,则抛出一个
"NotFoundError" DOMException。pointerId 的
Element,hasPointerCapture 为 false,
则终止这些步骤。
pointerId,清除待处理的指针捕获目标
覆盖,如果已设置。实现用于平移和缩放的直接操纵交互的输入
(例如触摸屏上的触摸或触控笔)SHOULD 表现得就像在调用任何
pointerdown 监听器之前,
已在目标元素上调用了 setPointerCapture 一样。可以使用
hasPointerCapture API(例如在
pointerdown 监听器中)来确定这是否
已经发生。如果在下一个指针事件触发之前没有为该指针调用
releasePointerCapture,
则会向目标分派一个 gotpointercapture
事件(正常情况下),
指示捕获处于活动状态。
在触发 pointerup 或 pointercancel 事件后立即,
用户代理 MUST 清除刚刚分派的 pointerup 或 pointercancel 事件的
pointerId 的待处理的指针捕获目标
覆盖,
然后运行处理待处理的指针捕获步骤,以在必要时触发
lostpointercapture。
运行处理待处理的指针捕获步骤后,
如果指针支持悬停,用户代理 MUST 还
发送必要的对应边界事件,以反映在没有捕获时指针的当前位置。
当指针捕获目标覆盖不再 已连接时 [DOM], 指针捕获目标覆盖 SHOULD 被设置为 document。
当待处理的指针捕获目标 覆盖不再已连接时 [DOM], 待处理的指针捕获目标 覆盖节点 SHOULD 被清除。
lostpointercapture
事件。
当指针锁定 [PointerLock] 成功应用到某元素上时,如果任何元素已被设置为捕获
或待捕获,用户代理 MUST 运行这些步骤,就像已经调用了
releasePointerCapture 方法一样。
出于性能原因,用户代理可以选择不在指针的可测量属性
(例如坐标、压力、切向压力、倾斜、twist 或接触几何形状)
每次更新时都发送一个 pointermove
事件。相反,它们可以将多个变化合并(组合/融合)到
单个 pointermove 或 pointerrawupdate 事件中。虽然
这种方法有助于减少用户代理 MUST
执行的事件处理量,
但在跟踪指针位置时自然会降低粒度和保真度,
尤其是在快速且大幅移动时。使用
getCoalescedEvents 方法,
应用可以访问原始的、未合并的位置变化。这些
允许对指针移动数据进行更精确的处理。例如,在绘图
应用中,未合并事件可用于绘制更平滑的曲线,使其
更接近指针的实际移动。
pointermove 事件中的合并
坐标(灰色点)时,曲线明显
有棱角且锯齿状;使用 getCoalescedEvents()
提供的更细粒度点(红色圆圈)绘制同一条线,会得到对指针移动的更平滑近似。PointerEvent 具有关联的合并
事件列表(一个由零个或多个 PointerEvent 组成的列表)。
对于受信任的 pointermove 和
pointerrawupdate 事件,该列表是
被合并到此事件中的所有 PointerEvent 的序列。
“父”受信任 pointermove 和
pointerrawupdate 事件表示这些合并事件的
累积,
但可以有额外处理(例如与显示刷新率对齐)。
因此,这些事件的合并事件列表始终至少包含一个事件。
对于所有其他受信任事件类型,它是空列表。不受信任事件的
合并事件列表会初始化为传递给构造器的值。
受信任事件的合并事件列表中的事件将具有:
timeStamp 值
[DOM]——所有合并事件的
timeStamp 都小于或等于
调用
getPredictedEvents 方法的
已分派指针事件的
timeStamp。合并事件列表
MUST 按 timeStamp 时间顺序排序,因此第一个
事件将具有最小的 timeStamp。
pointerId、pointerType
和 isPrimary。<style>
/* 禁用用户代理固有的直接操纵行为(例如平移或缩放),
使 canvas 元素上的所有事件都改为交给应用。 */
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); // 绘制所有原始/未合并点
}
} else {
paint(e); // 绘制最终的合并点
}
});
function paint(event) {
if (event.buttons>0) {
context.fillRect(event.clientX, event.clientY, 5, 5);
}
}
</script>
所有这些已分派事件的顺序 MUST 与
原始事件的实际顺序匹配。
例如,如果 pointerdown 事件导致
合并的 pointermove 事件分派,则用户代理 MUST 先
分派一个 pointermove
事件,其中包含该 pointerId 的所有这些合并事件,
随后再分派 pointerdown 事件。
以下示例展示了随着 timeStamp
值递增而实际发生的事件
以及用户代理分派的事件:
| 实际事件 | 已分派事件 |
|---|---|
pointer(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),带一个
合并事件 |
pointer(pointerId=1)
坐标变化 |
pointerrawupdate(pointerId=1),带一个
合并事件 |
pointer(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),带一个
合并事件 |
pointer(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),带一个
合并事件 |
pointer(pointerId=1)
坐标变化 |
pointerrawupdate(pointerId=1),带一个
合并事件 |
pointer(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),带一个
合并事件 |
pointer(pointerId=1)按钮
按下 |
pointermove
(pointerId=1),带两个
合并事件pointermove
(pointerId=2),带四个
合并事件pointerdown
(pointerId=1),带零个
合并事件 |
pointer(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),带一个
合并事件 |
pointer(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),带一个
合并事件 |
pointer(pointerId=1)按钮
释放 |
pointermove
(pointerId=2),带两个
合并事件pointerup(pointerId=1),带零个
合并事件 |
某些用户代理内置了算法,这些算法在一系列已确认的指针移动之后,
可以(基于当前手势的前置事件以及移动的速度/轨迹)
预测未来指针移动的位置可能在哪里。应用可以通过
getPredictedEvents 方法使用此信息,
推测性地“提前绘制”到预测位置,
以降低感知延迟,然后在接收到实际点后丢弃这些预测点。
pointermove 事件的合并坐标,
显示用户代理预测的未来点(灰色圆圈)。PointerEvent 具有关联的预测
事件列表(一个由零个或多个
PointerEvent 组成的列表)。对于受信任的 pointermove 事件,它是用户代理预测将在未来跟随该事件的
PointerEvent 的序列。
对于所有其他受信任事件类型,它是空列表。
不受信任事件的预测事件列表会初始化
为传递给构造器的值。
列表中事件的数量以及它们距当前时间戳的距离由 用户代理及其使用的预测算法决定。
受信任事件的预测事件列表中的事件将具有:
timeStamp 值
[DOM]——所有预测事件的
timeStamp 都大于或等于
调用
getPredictedEvents 方法的
已分派指针事件的
timeStamp。预测事件列表
MUST 按 timeStamp 时间顺序排序,因此第一个
事件将具有最小的 timeStamp。
pointerId、pointerType
和 isPrimary。请注意,作者只应在下一个指针事件被 分派之前,将预测事件视为有效预测。取决于用户代理预测事件到未来的距离, 常规指针事件可能会早于一个或多个预测事件的时间戳被分派。
let predicted_points = [];
window.addEventListener("pointermove", function(event) {
// 清除先前绘制的预测点。
for (let e of predicted_points.reverse()) {
clearPoint(e.pageX, e.pageY);
}
// 绘制自上次接收事件以来实际发生的移动。
for (let e of event.getCoalescedEvents()) {
drawPoint(e.pageX, e.pageY);
}
// 绘制当前预测点,以减少对延迟的感知。
predicted_points = event.getPredictedEvents();
for (let e of predicted_points) {
drawPoint(e.pageX, e.pageY);
}
});
当创建受信任的 PointerEvent 时,用户代理 SHOULD 对合并事件列表和预测事件列表中的每个事件运行以下步骤:
pointerId、
pointerType、
isPrimary 和 isTrusted 设置为与
“父”指针事件的相应属性匹配。
cancelable 和 bubbles 设置为 false(因为
这些事件永远不会
被单独分派)。PointerEvent 值。当受信任的 PointerEvent 的 target 被更改时,用户代理
SHOULD 对合并事件列表和预测事件列表中的每个事件:
如今存在的绝大多数 Web 内容只针对 Mouse Events 编码。下面描述一种算法,说明用户 代理 MAY 如何将通用指针输入映射到鼠标事件,以便与 这些内容兼容。
与鼠标事件的兼容性映射是本规范的一个 OPTIONAL 特性。 鼓励用户代理支持此特性,以便与现有旧式内容获得最佳兼容性。
从高层来看,兼容性鼠标事件旨在与其各自的指针事件“交错”。 然而,此特定顺序不是强制性的,实现兼容性鼠标事件的用户代理 MAY 决定延迟或分组分派鼠标事件,只要它们的相对顺序保持一致。
特别是在触摸屏输入的情况下,用户代理 MAY 应用
额外的手势识别启发式规则(除非作者通过 显式抑制)。
在 touch-actionpointerdown 事件和 pointerup 事件之间的一系列事件期间,手势识别可能必须
等到 pointerup 事件才能检测或
忽略某个手势。因此,如果用户代理确定某次交互并非旨在作为特定手势,
则整个序列的兼容性鼠标事件可能会在最后一个 pointerup 事件之后
一起分派。用户代理手势识别的这些具体细节并未在本规范中定义,并且它们可能因实现而异。
无论是否支持兼容性鼠标事件,用户代理 MUST
始终支持 click、auxclick 和 contextmenu 事件,因为
这些事件属于 PointerEvent 类型,因此不是兼容性鼠标事件。在指针事件期间调用
preventDefault MUST NOT 影响
click、auxclick 或 contextmenu 是否触发。
其中一些高层事件(例如 contextmenu、focus、blur)与指针
事件的相对顺序未定义,并且会因用户代理而异。例如,在某些用户代理中
contextmenu 通常会跟随 pointerup,而在其他用户代理中它通常会先于
pointerup 或 pointercancel,并且在某些情况下可能
会在没有任何对应指针事件的情况下触发(例如,由键盘交互导致)。
此外,用户代理可以应用自己的启发式规则来确定是否应触发
click、auxclick 或 contextmenu 事件。某些
用户代理可能选择在存在相同类型的其他(非主)指针,或不同类型的其他主指针时
不触发这些事件。用户代理可能会判定某个特定动作不是一次“干净的”轻触、点击或长按
(例如,如果触摸屏上手指的交互在手指接触屏幕期间包含过多移动),
并决定不触发 click、auxclick 或
contextmenu 事件。用户代理行为的这些方面未在本规范中定义,
并且它们可能因实现而异。
除非另有说明,任何映射鼠标事件的目标 SHOULD 与相应指针事件的
目标相同,除非该目标不再参与其 ownerDocument 的树。在这种情况下,
鼠标事件应在原始目标的最近祖先节点上触发(以其从树中移除时为准),该祖先节点仍参与其
ownerDocument 的树,这意味着会为鼠标事件构建一条新的事件路径
(基于新的目标节点)。
作者可以通过取消 pointerdown 事件来阻止某些兼容性鼠标事件的产生。
只有当指针处于按下状态时,才能阻止鼠标事件。悬停指针(例如未按下任何按钮的鼠标) 不能阻止其鼠标事件。
mouseover、mouseout、mouseenter 和 mouseleave
事件永远不会被阻止(即使指针处于按下状态)。
当指针事件 EventListener 被设置为
passive
时,不能阻止兼容性鼠标事件 [DOM]。
虽然只有主指针可以产生兼容性鼠标事件,但多个主指针可以同时处于活动状态,每个都会产生自己的兼容性鼠标事件。
为了与依赖 MouseEvents 的脚本兼容,鼠标过渡事件(mouseover、mouseout、
mouseenter 和 mouseleave)SHOULD 模拟
单个旧式鼠标输入的移动。这意味着每个事件目标的进入/退出状态都是有效的,
符合 [UIEVENTS]。用户代理 SHOULD 通过按如下方式维护文档中的旧式鼠标指针的有效位置来保证这一点。
在触发 pointerdown、pointerup 或 pointermove 事件,或者在 window 上触发
pointerleave 事件之前,
用户代理 SHOULD 运行以下步骤:
pointerdown、pointerup 或 pointermove 事件的目标。对于 pointerleave 事件,取消设置 T。mouseover、mouseout、mouseenter 和
mouseleave 事件,表示鼠标从当前旧式鼠标指针的有效
位置移动到 T。将当前旧式鼠标指针的有效
位置或 T 的未设置值视为窗口外的鼠标位置。
旧式
鼠标指针的有效位置模拟了这样一个事实:我们并不总是能够从指针过渡事件
(pointerover、pointerout、pointerenter
和 pointerleave)直接映射到对应的旧式鼠标过渡事件
(mouseover、
mouseout、mouseenter 和 mouseleave)。下面的
动画展示了这样一种情况:用户代理需要分派比指针过渡事件更多的旧式鼠标过渡事件,
才能使用单个旧式鼠标输入协调两个主指针。
在此动画中,请注意鼠标点击和触摸轻触之间的时间段。Button 1
没有收到
pointerout 事件(因为“真实”鼠标指针在
此时间段内没有离开按钮矩形),但当旧式
鼠标指针的有效位置在触摸轻触时移动到 Button 2 时,Button 1 会收到
mouseout 事件。类似地,在触摸轻触和鼠标离开 Button 1 之前的这段时间内,
Button 1 也因相同原因没有收到
pointerover 事件,但当旧式鼠标指针的有效位置
移回 Button 1 内部时,Button 1 会收到 mouseover 事件。
每当用户代理要为支持悬停的设备分派指针事件时,它 SHOULD 运行以下步骤:
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 事件。
这要求用户代理为这些类型的输入设备提供不同的映射。每当用户代理要为不支持悬停的设备分派指针事件时,它 SHOULD 运行以下步骤:
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] 中定义) 和 Pointer Events,则用户 代理 MUST NOT 同时生成本节所述的兼容性鼠标事件,以及 [TOUCH-EVENTS] 中概述的回退 鼠标事件。
使用不支持悬停的主指针(例如
触摸屏上的单个手指)激活某个元素(click)通常会产生以下事件序列:
mousemovepointeroverpointerentermouseovermouseenterpointerdownmousedownpointermove 和
mousemove 事件,取决于指针的移动
pointerupmouseuppointeroutpointerleavemouseoutmouseleaveclick但是,如果在此交互期间设置了 pointerdown 事件的已取消标志,
则事件序列将为:
mousemovepointeroverpointerentermouseovermouseenterpointerdownpointermove 事件,
取决于指针的移动pointeruppointeroutpointerleavemouseoutmouseleaveclick本附录讨论 Pointer Events 实现的安全和隐私考量。讨论仅限于直接源自实现本规范中定义的事件 模型、API 和事件的安全和隐私问题。
本规范中定义的许多事件类型会响应用户动作而分派。这使得 恶意事件监听器能够访问用户通常会认为机密的信息,例如 用户在与页面交互时鼠标/触控笔/手指的精确路径/移动。
指针事件包含额外信息(在用户设备支持的情况下),例如笔输入握持的角度或 倾斜、接触面的几何形状,以及施加在触控笔或触摸屏上的压力。 关于角度、倾斜、几何形状和压力的信息与用户设备上的传感器直接相关, 这意味着本规范允许 origin 访问这些传感器。
此传感器数据,以及确定所使用输入机制(鼠标、触摸、笔)类型的能力, 可用于推断用户、或用户设备和环境的特征。这些推断出的 特征以及任何设备/环境信息本身可能是敏感的——例如,它们可能 允许恶意站点进一步推断用户是否正在使用辅助技术。此信息还可能 被用于建立用户画像和/或尝试对特定用户进行“指纹识别”和跟踪。
作为缓解措施,用户代理可以考虑提供让用户禁用对特定 传感器数据(例如角度、倾斜、压力)的访问的能力,和/或仅在用户显式选择加入后 才使其可用。
本规范定义了作者可以访问“预测事件”的方法。本规范本身不定义 用户代理应为其预测使用的算法。规范作者设想这些算法只依赖于与用户正在执行的 当前手势相关的前置指针事件。用户代理有责任确保其预测算法的具体实现 不依赖任何额外数据——例如用户跨不同站点的完整交互历史——这些数据可能泄露用户的敏感信息, 或被用于“指纹识别”和跟踪他们。
除这些考量外,工作组认为本规范:
本节是非规范性的。
buttons 属性具有非零值时的状态。对于鼠标,这是指
设备至少有一个按钮被按下。对于触摸,这是指与数字化仪存在物理接触。对于笔,这是指
笔与数字化仪存在物理接触,或者在悬停时至少有一个按钮被按下。pointerId 标识)
仍可能在文档内产生额外事件,则该指针仍被视为活动。示例:
WheelEvent 接口的输入设备(例如鼠标滚轮或触控板)的物理移动
而滚动或缩放页面的估计滚动量(以像素、行或页为单位)。delta 的值(例如 deltaX、deltaY 或 deltaZ 属性)将在当前
deltaMode 属性的上下文中解释。滚轮
(或其他设备)的物理移动与delta 是正还是负之间的关系
取决于环境和设备。但是,如果用户代理将滚动作为默认动作,则 delta 的符号
由右手坐标系给出,其中正 X、Y 和 Z 轴分别指向
文档的最右边缘、最下边缘和最远深度(远离用户)。
可测量属性表示与连续指针传感器数据相关的值,这些数据使用实数或
来自大范围域的整数表示。对于指针事件,width、height、
pressure、
tangentialPressure、tiltX、tiltY、twist、
altitudeAngle、azimuthAngle,以及 [UIEVENTS] Mouse
Event 模型属性
screenX、screenY、clientX、clientY 都是
可测量属性。
相反,pointerId、pointerType、
isPrimary,以及
[UIEVENTS] Mouse Event 模型属性 button、
buttons、ctrlKey、
shiftKey、altKey 和 metaKey 不被视为可测量
属性,
因为它们与传感器数据无关。
WheelEvent 接口的输入设备上增量变化的指示。在某些设备上,这 MAY 是滚轮的字面旋转,而在其他设备上,它 MAY 是沿平面的移动,或对特定按钮的按压。命中测试设施用于 确定目标。关于命中测试和堆叠顺序的具体细节,请参考宿主语言。
本节是规范性的。 以下特性已过时,并且只应由需要 与旧式软件兼容的用户代理实现。 另请参见 [UIEvents] 中的旧式事件初始化器。
WebIDLpartial interface MouseEvent {
};
MouseEvent 对象的属性。此
方法的行为与 UIEvent.initUIEvent() 相同。
initMouseEvent 方法已弃用,但为与广泛部署的
实现向后兼容而受到支持。
initEvent()
方法。
initEvent()
方法。
initEvent()
方法。
view。此
值 MAY 为 null。
detail。
screenX。
screenY。
clientX。
clientY。
ctrlKey。
altKey。
shiftKey。
metaKey。
button。
relatedTarget。此值
MAY
为 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;
readonly attribute boolean momentum;
};
dictionary WheelEventInit : MouseEventInit {
double deltaX = 0.0;
double deltaY = 0.0;
double deltaZ = 0.0;
unsigned long deltaMode = 0;
boolean momentum = false;
};
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);
};
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: