Copyright © 2026 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
Pointer Events 规范定义了一个统一且与硬件无关的框架,用于处理来自 各种设备的输入,包括鼠标、触摸屏和笔/触控笔。通过提供一组统一的事件(例如 pointerdown、pointermove、pointerup),开发者无需为每种设备编写 特定逻辑,即可支持多种输入方式。
本规范还定义了鼠标事件和滚轮事件,以及一种为其他 指针设备类型触发鼠标事件的映射。
本节描述本文档在 发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准和草案 索引中找到。
本规范是对 [PointerEvents3] 规范的更新。它还 包含此前位于 [UIEVENTS] 规范中的鼠标事件和滚轮事件。
本次修订包含以下新功能:
persistentDeviceId,用于为输入设备在多次
交互之间提供稳定的标识符。touch-action 值:pan-left、
pan-right、pan-up、pan-down
本文档由 Pointer Events 工作组作为 工作草案发布,并采用 推荐标准 流程。
作为 工作草案发布并不意味着 获得 W3C 及其成员的认可。
这是一份草案文档,可能随时被其他 文档更新、替换或废弃。除将其作为正在进行的工作外, 不宜以其他方式引用本文档。
本文档由一个依照 W3C 专利 政策运作的工作组编制。 W3C 维护着一份 公开的专利 披露列表, 其中列出了与该工作组交付成果有关的披露;该页面还包含 披露专利的说明。任何实际 知悉某项专利,并认为该专利包含 必要权利要求 的个人,都必须依照 W3C 专利政策第 6 节披露该信息。
本文档受 2025年8月18日 W3C 流程文档管辖。
本节为非规范性内容。
如今,大多数 [HTML] 内容都与鼠标输入配合使用和/或针对鼠标输入进行设计。那些 以自定义方式处理输入的内容通常针对鼠标事件编写代码。然而,如今较新的计算设备 集成了其他形式的输入,包括触摸屏和笔输入。已经有人提出了分别用于 处理这些输入形式的事件类型。然而,在添加对新输入类型的支持时,这种方法通常会导致不必要的 逻辑重复和事件处理开销。当内容仅针对一种设备类型编写时,这通常 会产生兼容性问题。此外,为了与现有基于鼠标的内容兼容,大多数 用户代理都会为所有输入类型触发鼠标事件。 这使得鼠标事件究竟代表实际的鼠标设备,还是为了兼容性而由 另一种输入类型产生变得含糊,从而难以同时为两种设备类型编写代码。
为了降低针对多种输入类型编写代码的成本,同时帮助解决上述鼠标事件的 歧义问题,本规范定义了一种更加抽象的输入形式,称为指针。指针可以是由鼠标光标、笔、触摸(包括多点触摸)或其他指向 输入设备在屏幕上产生的任何接触点。无论用户拥有什么 硬件,这种模型都能让编写运行良好的网站和应用程序变得更加容易。对于需要针对特定设备进行处理的场景,本规范还 定义了用于检查产生事件的设备类型的属性。主要目标是提供 一组统一的事件和接口,使作者更容易针对跨设备指针输入进行编写,同时 仍然只在增强体验确有必要时才允许针对特定设备进行处理。
另一个关键目标是使多线程用户代理能够处理用于平移和缩放的直接操纵 操作(例如,在触摸屏上使用手指或触控笔),而无需因 脚本执行而阻塞。
用于处理通用指针输入的事件与鼠标事件非常相似:pointerdown、pointermove、pointerup、pointerover、pointerout
等。这有助于轻松地将内容
从鼠标事件迁移到指针事件。
除了面向其他形式输入的新属性(例如压力、
接触区域几何形状、倾斜度)之外,指针事件还提供鼠标事件中存在的所有常用属性(包括客户端坐标、
目标元素、按钮状态)。在适用的情况下,作者可以轻松针对指针事件编写代码,以便在不同输入
类型之间共享逻辑,并且只在为了获得最佳体验确有必要时才针对特定输入类型进行
自定义。
虽然指针事件来源于各种输入设备,但并未将其定义为由 某组其他特定于设备的事件生成。虽然出于兼容性考虑这是可行且受到鼓励的,但本规范 并不要求支持其他特定于设备的事件(例如鼠标事件或触摸事件)。用户 代理可以在不支持任何其他设备事件的情况下支持指针事件。为了与 针对鼠标特定事件编写的内容兼容,本规范确实提供了一个可选章节,用于说明如何 根据来自鼠标以外设备的指针输入生成兼容性鼠标事件。
本规范未就同时支持 触摸事件(如 [TOUCH-EVENTS] 中所定义)和指针事件的用户代理的预期行为提供任何建议。 有关这两个规范之间关系的更多信息,请参阅 触摸事件社区组。
除了标记为非规范性的章节外,本规范中的所有作者指南、图示、示例和注释 均为非规范性内容。本规范中的其他所有内容均为规范性内容。
本文档中的关键词 可以、必须、不得、可选 和 应该 应按照 BCP 14 [RFC2119] [RFC8174] 中所述的含义进行解释,但仅当这些关键词如这里所示 全部以大写形式出现时才如此。
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导致该事件的指针的唯一标识符。用户代理可以为主鼠标指针保留通用的 pointerId 值
0 或 1。pointerId 值
-1 必须予以保留,并用于表示由
指向设备以外的事物生成的事件。对于任何其他指针,用户
代理可以自由采用不同的策略和方法来分配 pointerId
值。但是,顶级
浏览上下文(如 [HTML] 中所定义)中的所有 活动指针都必须是唯一的,并且该
标识符不得受到任何其他顶级浏览
上下文的影响(即,一个顶级浏览上下文不能假定,当指针移出该浏览上下文并进入另一个
顶级浏览上下文时,该指针的 pointerId
仍将相同)。
用户代理
可以回收先前活动指针中已经停用的 pointerId 值,或者它可以始终为某个特定指向设备重用相同的 pointerId
(例如,在多用户协作应用中唯一标识来自特定用户的特定笔/触控笔
输入)。但是,在后一种情况下,为了尽量减少跨不同页面或
域进行指纹识别和跟踪的可能性,pointerId
必须仅在页面/会话的生命周期内显式关联到该特定指向
设备,并且下一次在新会话中再次使用该特定指向设备时,必须选择一个新的随机 pointerId。
pointerId 选择
算法取决于具体实现。作者不能假定这些值除了作为
指针的标识符之外还传达任何特定含义,该标识符与所有
其他活动指针的标识符均不同。例如,用户代理可以简单地按照活动指针
变为活动状态的顺序,从 0 开始为它们分配数字——
但不保证这些值单调递增。由于是否为
特定指向设备重用相同的 pointerId
由各个实现自行决定,因此强烈建议作者
不要依赖这一点,而应改用 persistentDeviceId。
width指针接触几何形状的宽度(X 轴上的大小),以 CSS 像素为单位(参见 [CSS21])。
对于给定指针,此值可以在每个事件中更新。对于通常
缺少接触几何形状的输入(例如传统鼠标),以及硬件未检测到输入实际
几何形状的情况下,用户代理必须返回默认值 1。
height指针接触几何形状的高度(Y 轴上的大小),以 CSS 像素为单位(参见 [CSS21])。
对于给定指针,此值可以在每个事件中更新。对于通常
缺少接触几何形状的输入(例如传统鼠标),以及硬件未检测到输入实际
几何形状的情况下,用户代理必须返回默认值 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
为 π/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 值 |
|---|---|
| 鼠标 | mouse |
| 笔 / 触控笔 | pen |
| 触摸接触 | touch |
如果用户代理无法检测设备类型,则该值必须为空字符串。如果用户代理支持上述列表之外的指针设备
类型,则 pointerType 的值应该带有供应商前缀,以避免不同
设备类型之间发生名称冲突。未来的规范可以为其他设备类型提供额外的
规范性值。
pointerType 的基本
演示,请参阅 示例 2。另请注意,开发者
应包含某种默认处理,以涵盖用户代理可能
实现自己的自定义 pointerType 值的情况,以及
pointerType 只是空字符串的情况。
isPrimary表示该指针是否代表此 指针类型的主指针。
persistentDeviceId指向设备的唯一标识符。如果硬件支持多个指针,
由指向设备生成的指针事件必须仅在这些指针在整个
会话期间都能够被唯一识别时,才获得
persistentDeviceId。如果指针可以被唯一识别,则分配给该指向设备的
persistentDeviceId 将在
会话剩余期间保持不变。persistentDeviceId 值 0 必须予以保留,并用于表示无法识别其生成
设备的事件。与 pointerId 类似,为了尽量减少
跨不同页面或域进行指纹识别和跟踪的可能性,
persistentDeviceId 必须仅在
页面/会话的生命周期内显式关联到该特定指向设备,并且下一次
在新会话中再次使用该特定指向设备时,必须选择一个新的随机
persistentDeviceId。
persistentDeviceId。例如,设备可能未能及时向
数字化器报告其硬件 ID,因此 pointerdown 可能没有
persistentDeviceId。在这种情况下,persistentDeviceId 最初可能
为 0,随后变为有效值。
getCoalescedEvents()返回合并事件列表的方法。
getPredictedEvents()返回预测事件列表的方法。
PointerEventInit 字典由 PointerEvent 接口的构造函数使用,用于提供
构造不受信任(合成)指针事件的机制。它继承自 MouseEventInit
字典。有关演示如何触发
不受信任指针事件的示例代码,请参阅示例。
对于 PointerEvent 的事件
构造步骤
会将 PointerEventInit 的 coalescedEvents 克隆到合并事件列表,并将
PointerEventInit 的 predictedEvents 克隆到预测事件列表。
PointerEvent 接口继承自 MouseEvent。
另请注意 CSSOM 视图模块中提出的扩展,它将
各种坐标属性从 long
更改为 double,以允许使用小数坐标。对于已经
为
PointerEvent 实现这一拟议扩展、但没有为普通
MouseEvent 实现的用户代理,当涉及
click、auxclick
和 contextmenu 事件时,还有其他要求。
在多指针(例如多点触摸)场景中,isPrimary 属性用于
在每种指针类型的活动指针集合中
标识一个主指针。
pointerType 一个)都会被视为主指针。例如,触摸接触和
鼠标光标同时移动时,会产生两个都被视为主指针的指针。
isPrimary 的值设为 false。
触发一个
指针事件,其名称为 e,意味着使用属性按照
PointerEvent 接口和
属性和默认动作中的定义设置的
PointerEvent,触发一个事件,其名称为 e。
如果事件不是 gotpointercapture、lostpointercapture、click、
auxclick 或 contextmenu 事件,则为
此 PointerEvent 运行处理待定指针捕获步骤。
按如下方式确定 事件触发的目标:
令 targetDocument 为目标的节点文档 [DOM]。
如果事件是 pointerdown、pointermove 或 pointerup,则将事件的 活动文档
对应于其 pointerId 设置为
targetDocument。
如果事件是 pointerdown,关联的
设备是直接操纵设备,并且目标是一个 Element,
那么按照隐式指针捕获中的描述,为此 pointerId 将目标元素设置为指针捕获目标。
在触发此事件之前,用户代理应该
为了确保事件顺序,将目标视为指向设备从 previousTarget 移动到其上。如果
设置了 needsOverEvent 标志,即使目标
元素相同,也需要一个 pointerover 事件。
向确定的目标触发该事件。
将确定的目标保存为给定指针的 previousTarget,
并将 needsOverEvent 标志重置为 false。
如果 previousTarget 在任何时候将不再已连接 [DOM],
则沿着向 previousTarget 分派事件时对应的事件路径,
将 previousTarget 更新为最近的仍然已连接 [DOM] 的父级,
并将 needsOverEvent 标志设置为 true。
本规范中定义的事件类型的 bubbles 和 cancelable 属性以及默认动作
如下表所示。有关每种
事件类型的详细信息,请参阅指针事件类型。
| 事件类型 | 冒泡 | 可取消 | 默认动作 |
|---|---|---|---|
pointerover
|
是 | 是 | 无 |
pointerenter |
否 | 否 | 无 |
pointerdown
|
是 | 是 | 视情况而定:当指针为主指针时,为
mousedown 事件的所有默认动作
取消此事件还会阻止随后触发兼容性鼠标事件。 |
pointermove
|
是 | 是 | 视情况而定:当指针为主指针时,为 mousemove 的所有默认动作
|
pointerrawupdate |
是 | 否 | 无 |
pointerup |
是 | 是 | 视情况而定:当指针为主指针时,为 mouseup 的所有默认动作
|
pointercancel |
是 | 否 | 无 |
pointerout
|
是 | 是 | 无 |
pointerleave |
否 | 否 | 无 |
gotpointercapture |
是 | 否 | 无 |
lostpointercapture |
是 | 否 | 无 |
视口操纵(平移和缩放)——通常是直接操纵交互的结果——
被有意设定为不是指针事件的默认动作,这意味着这些行为(例如,在触摸屏上移动手指
导致页面平移)不能通过取消
指针事件来抑制。作者必须改用 touch-action,为文档中的某个区域显式声明直接操纵行为。
移除对事件取消的这种依赖,有助于
用户代理进行性能优化。
对于 pointerenter 和 pointerleave 事件,composed
[DOM]
属性应该为
false;对于上表中的所有其他指针事件,该属性应该为 true。
对于上表中的所有指针事件,detail 属性
应该为 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(在
最初的 Pointer Events 规范中引入),以及 azimuthAngle / altitudeAngle
(采用自 触摸事件 - 第 2 级
规范)。
根据具体硬件和平台,用户代理很可能只会接收到一组
表示换能器相对于屏幕平面方向的值——要么是 tiltX /
tiltY,要么是 altitudeAngle / azimuthAngle。用户代理必须使用以下算法转换这些值。
当用户代理根据 azimuthAngle
/ altitudeAngle 计算 tiltX / tiltY 时,应该使用
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
下面是本规范中定义的事件类型。
对于主指针,这些事件(gotpointercapture 和 lostpointercapture 除外)还可能触发兼容性鼠标事件。
| 类型 | pointerover |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
|
当以下任一情况发生时,用户代理必须触发一个指针事件,其名称为 pointerover:
pointerdown 事件之前(参见 pointerdown)。| 类型 | pointerenter |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 否 |
| 可取消 | 否 |
| 组合 | 否 |
| 上下文 (可信事件) |
|
该 用户代理 必须 触发指针事件,名称为 pointerenter,触发条件为发生以下任一情况:
pointerdown 事件之前,前提是设备
不支持悬停(参见 pointerdown)。
| 类型 | pointerdown |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
该 用户代理 必须 触发指针事件,名称为 pointerdown,触发条件为指针进入 活动按钮状态。对于鼠标,这是指
设备从没有按钮被按下转换为至少有一个按钮被按下的状态。对于触摸,这是指
发生物理接触,接触对象为 数字化器。对于笔,这是指笔
在没有任何按钮被按下时与数字化器发生物理接触,或进行以下转换:
在悬停时,从没有按钮被按下到至少有一个按钮被按下。
pointerdown 和 pointerup 并非在所有相同的
情况下都像 mousedown 和 mouseup 那样触发。参见 组合按钮
以了解更多信息。对于输入 设备,若其不支持
悬停,则 用户
代理 必须 还要 触发指针
事件,名称为 pointerover,随后触发一个
指针事件,其名称为 pointerenter,然后才可
派发 pointerdown 事件。
pointerdown 事件(如果
isPrimary 属性为 true)。这会设置
该指针上的 PREVENT MOUSE EVENT 标志。不过,请注意,这不会阻止
mouseover、mouseenter、mouseout 或
mouseleave 事件的触发。
| 类型 | pointermove |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
当指针的任何属性发生变化,但该变化不会触发
pointerdown 或 pointerup 事件时,用户代理必须触发一个指针事件,其名称为 pointermove。这包括
坐标、压力、切向压力、
倾斜、旋转、接触几何形状(width 和 height)或组合按钮的任何变化。
用户代理可以延迟分派 pointermove 事件(例如,出于性能
原因)。
对于单个已分派的 pointermove 事件,合并事件信息将通过 getCoalescedEvents 方法公开。
应使用这些事件的最终坐标来查找事件目标。
| 类型 | pointerrawupdate |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 否 |
| 组合 | 是 |
| 上下文 (可信事件) |
当指针的任何属性发生变化,但该变化不会触发
pointerdown 或 pointerup 事件时,用户代理必须触发一个指针事件,
其名称为 pointerrawupdate,并且
只能在安全上下文中这样做。
有关此类属性的列表,请参阅 pointermove 事件。
与 pointermove 相比,用户代理
应该尽快分派 pointerrawupdate 事件,
并且频率应尽可能高,以 JavaScript 能够处理这些事件的速度为限。
pointerrawupdate 事件的 target
可能与
pointermove 事件不同,
因为 pointermove 事件可能
被延迟或合并,而用于查找 target 的事件最终位置
可能与其合并事件不同。
请注意,如果已经有另一个 pointerrawupdate 具有相同的
pointerId,并且尚未在
事件循环中分派,则
用户代理可以将新的 pointerrawupdate 与该事件合并,而不是
创建新的任务。
这可能导致 pointerrawupdate
包含合并事件,并且一旦该事件在
事件循环中被处理,
它们都会作为一个 pointerrawupdate 事件的合并事件立即交付。
有关更多信息,请参阅getCoalescedEvents。
就 pointerrawupdate 和 pointermove 的顺序而言,
如果用户代理从平台接收到一个同时导致 pointerrawupdate 和 pointermove 事件的更新,
那么用户代理必须在相应的 pointermove 之前分派 pointerrawupdate 事件。
除 target 外,自上一个 pointermove 事件以来所有已分派 pointerrawupdate 事件的合并事件列表连接起来后,
就其他事件属性而言,与下一个 pointermove 事件的合并事件相同。
pointerrawupdate 的属性
大多与 pointermove 相同,唯一的例外是
cancelable,对于 pointerrawupdate,其必须为 false。
用户代理应该不为 兼容性鼠标事件触发 pointerrawupdate。
pointerrawupdate 事件添加监听器可能会
对网页性能产生负面影响。
对于大多数用例,其他 pointerevent 类型应该足够。
仅当 JavaScript 需要高频事件并且能够同样快速地处理这些事件时,才应添加 pointerrawupdate
监听器。
在这些情况下,可能不需要监听其他类型的指针事件。| 类型 | pointerup |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
该 用户代理 必须 触发指针事件,名称为 pointerup,触发条件为指针离开 活动按钮状态。对于鼠标,这是指
设备从至少有一个按钮被按下转换为没有按钮被按下的状态。对于触摸,这是指
解除物理接触,接触对象为 数字化器。对于笔,这是指笔
在没有按钮被按下时解除与数字化器的物理接触,或进行以下转换:
在悬停时,从至少有一个按钮被按下到没有按钮被按下。
对于输入 设备,若其不支持
悬停,则 用户
代理 必须 还要 触发指针
事件,名称为 pointerout,随后触发一个
指针事件,其名称为 pointerleave,这些操作须晚于
派发 pointerup 事件。
所有 pointerup 事件的 pressure
值均为 0。
该 用户代理 必须 还要 隐式释放指针 捕获,如果该指针当前已被捕获。
pointerdown 和 pointerup 并非在所有相同的
情况下都像 mousedown 和 mouseup 那样触发。参见 组合按钮
以了解更多信息。| 类型 | pointercancel |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 否 |
| 组合 | 是 |
| 上下文 (可信事件) |
当用户代理
检测到需要抑制指针事件流的场景时,必须触发一个指针事件,其名称为 pointercancel。
pointercancel 事件的以下属性值必须与具有相同 pointerId
的最后一个已分派指针事件的值相匹配:width、
height、pressure、tangentialPressure、tiltX、
tiltY、twist、altitudeAngle、azimuthAngle、
pointerType、isPrimary,以及从鼠标事件继承的坐标。
pointercancel 事件中的
coalescedEvents 和 predictedEvents 列表必须为空,并且事件的 cancelable 属性
必须为 false。
| 类型 | pointerout |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
|
当以下任一情况发生时,用户代理必须触发一个指针事件,其名称为 pointerout:
| 类型 | pointerleave |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 否 |
| 可取消 | 否 |
| 组合 | 否 |
| 上下文 (可信事件) |
|
该 用户代理 必须 触发指针事件,名称为 pointerleave,触发条件为发生以下任一情况:
pointerup 事件,其对应的
设备 不支持悬停
(参见 pointerup)。| 类型 | gotpointercapture |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 否 |
| 组合 | 是 |
| 上下文 (可信事件) |
当一个元素获得指针捕获时,用户代理必须触发一个指针事件,其名称为 gotpointercapture。
此事件在正在获得指针捕获的元素上触发。该指针的后续事件将
在此元素上触发。请参阅设置指针捕获和处理待定指针捕获各节。
| 类型 | lostpointercapture |
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 否 |
| 组合 | 是 |
| 上下文 (可信事件) |
在某个指针的指针捕获被释放后,用户代理必须触发一个指针事件,其名称为 lostpointercapture。
在捕获被释放后,该事件必须先于该指针的任何后续事件触发。
此事件在被移除指针捕获的元素上触发。除 click、auxclick 和
contextmenu 事件之外,该指针的所有后续事件都遵循正常的命中测试机制
(不在本规范范围内)来确定事件目标。请参阅释放
指针捕获、隐式释放
指针捕获以及处理待定指针
捕获各节。
以下章节描述了对现有 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(),即使
该元素尚未收到 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 事件已发送,所针对的是该
指针,并且pointerup 或 pointercancel 事件(在上文
提及的 pointerdown 之后)尚未发送,所针对的是该
指针。touch-action 不会应用/层叠到嵌入的浏览上下文。
例如,即使将 touch-action 应用于 <iframe>,也不会
对用于平移和缩放的直接操纵交互行为产生任何影响,这些交互发生在
<iframe> 本身内部。
当用户与元素交互,使用的是 直接操纵 指针(例如
触摸屏上的触摸或触控笔)时,该输入的效果取决于以下属性的值:
touch-action 属性;还取决于该元素的默认直接操纵行为及其
祖先的相应行为,具体如下:
touch-action,前提是该行为
在元素的坐标空间中被允许。请注意,如果应用了 CSS 变换,
元素的坐标空间可能不同于屏幕坐标空间,并影响此处的
符合性;例如,某个元素的 X 轴(该元素旋转了 90 度,相对于
屏幕)将平行于屏幕坐标的 Y 轴。touch-action 属性,所涉及的各元素位于命中测试选中的元素与其最近的
含自身祖先之间,且该祖先是 滚动容器(其定义
见 [CSS-OVERFLOW-3])。
touch-action 属性,所涉及的各元素位于命中测试选中的元素与
document 元素之间,该元素属于 顶层
浏览上下文(其定义见 [HTML])。
touch-action 值的更改都会在该操作持续期间被忽略。举
例来说,以编程方式将某个元素的 touch-action 值从
auto 更改为 none,作为 pointerdown 处理程序脚本的一部分,不会导致
用户代理中止或抑制该输入的任何平移或缩放行为,只要
该指针仍处于活动状态。
touch-action 的各种 pan-* 值,一旦
用户代理在手势开始时已经确定是否直接处理
该手势,同一手势后续的方向变化 应该
被用户代理忽略,只要该指针仍处于活动状态。例如,如果某个元素
已设置为 touch-action: pan-y(表示仅垂直平移由
用户代理处理),且触摸手势从水平方向开始,则不应发生垂直平移,即使
用户将其手势方向改为垂直方向,而其手指仍在接触
屏幕。touch-action 的方法,
若涉及多个并发指针的值,则不在本规范的范围内。touch-action 属性涵盖与视口平移
和缩放有关的直接操纵行为。任何其他用户代理行为,例如文本选择/高亮显示,或者激活
链接和表单控件,不得受到此 CSS 属性的影响。
auto 或 none 值行为的交互或手势,
不在本规范范围内。pan-x 或 pan-y),在平移期间不能更改轴。
touch-action 值 在实现中很常见,其定义见 [COMPAT]。指定方向的平移值有助于自定义某些越界滚动行为。
例如,要实现简单的下拉刷新效果,文档的
touch-action 可以设置为 pan-x pan-down,条件是滚动位置
为 0,否则设置为 pan-x pan-y。
这允许指针事件处理程序定义向上平移/滚动的行为,条件是这些操作
从文档顶部开始。
指定方向的平移值也可用于组合一个组件,该组件实现
通过指针事件处理进行自定义平移,并位于一个原生滚动的元素内部(或者
反过来)。
例如,图片轮播组件可以使用 pan-y 来确保它接收指针事件,
针对任何水平平移操作,同时不干扰文档的垂直平移。
当轮播组件到达最右端时,可以将其 touch-action 更改为
pan-y pan-right,使后续超出其范围的滚动操作可以滚动
视口内的文档(如果可能)。
无法改变平移/滚动操作的行为,只要该操作正在
进行。
auto 时,用户
代理通常会增加 300ms 的延迟,在 click 之前,以便双击手势能够被
处理。在这些情况下,显式设置 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>
此元素上的直接操纵交互可以被用于操纵父元素。
</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 上设置指针捕获。
调用此方法时,用户代理必须运行
以下步骤:
pointerId
与任何活动指针都不匹配,则抛出一个 "NotFoundError" DOMException。pointerId 指定的活动指针。
InvalidStateError" DOMException。pointerLockElement),
则抛出一个 "InvalidStateError" DOMException。
pointerId,将待定指针捕获目标覆盖设置为调用此方法的 Element。pointerdown 监听器中。通过调用
element.releasePointerCapture(pointerId) 方法,可在元素上显式释放指针捕获。调用此方法时,用户代理必须运行以下步骤:
pointerId
与任何活动指针都不匹配,并且这些步骤
不是由于隐式释放指针
捕获而调用的,则抛出一个
"NotFoundError" DOMException。pointerId 的
Element,hasPointerCapture 为 false,则终止这些
步骤。
pointerId,如果设置了待定指针捕获目标
覆盖,则将其清除。输入若实现 直接操纵 交互以进行平移和缩放
(例如触摸屏上的触摸或触控笔),应该 表现得完全如同 setPointerCapture 被调用于
目标元素,调用时机恰在调用任何 pointerdown 监听器之前。该 hasPointerCapture API 可用于(举
例来说,在 pointerdown 监听器中)判断这是否已
发生。如果 releasePointerCapture 未在
下一个指针事件触发前针对该指针调用,则一个 gotpointercapture 事件将被派发到
目标(照常),表明捕获处于活动状态。
紧接在触发 pointerup 或 pointercancel 事件之后,
该 用户代理 必须 清除 待处理的指针捕获目标
覆盖值
,其对应的 pointerId 属于 pointerup 或 pointercancel 事件,该事件刚刚派发,
然后运行 处理待处理的指针捕获 步骤以触发
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>
/* 禁用用户代理固有的直接操纵行为(例如平移或缩放),
以便 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>
所有这些已分派事件的顺序必须与原始事件的实际顺序
相匹配。
例如,如果一个 pointerdown 事件导致
合并的 pointermove 事件被分派,则用户代理必须首先
分派一个 pointermove
事件,其中包含某个 pointerId 的所有这些合并事件,然后
再分派 pointerdown 事件。
下面是实际事件随 timeStamp 值递增而发生,
以及
用户代理所分派事件的一个示例:
| 实际事件 | 已分派事件 |
|---|---|
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),包含一个
合并事件 |
指针(pointerId=1)
坐标变化 |
pointerrawupdate(pointerId=1),包含一个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),包含一个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),包含一个
合并事件 |
指针(pointerId=1)
坐标变化 |
pointerrawupdate(pointerId=1),包含一个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),包含一个
合并事件 |
指针(pointerId=1)按钮
按下 |
pointermove
(pointerId=1),包含两个
合并事件pointermove
(pointerId=2),包含四个
合并事件pointerdown
(pointerId=1),包含零个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),包含一个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2),包含一个
合并事件 |
指针(pointerId=1)按钮
释放 |
pointermove
(pointerId=2),包含两个
合并事件pointerup(pointerId=1),包含零个
合并事件 |
某些用户代理具有内置算法,在一系列已确认的指针移动之后,
可以预测(基于当前手势之前的事件以及移动的速度/轨迹)
未来指针移动的位置可能在哪里。应用程序可以通过
getPredictedEvents 方法使用这些信息,
推测性地“提前绘制”到预测位置,
以降低感知延迟,然后在接收到实际点后丢弃这些预测点。
pointermove 事件中的合并坐标,并显示用户
代理预测的未来点(灰色圆圈)。PointerEvent 具有一个关联的预测
事件列表(包含零个或多个
PointerEvent 的列表)。对于可信的 pointermove 事件,它是
用户代理预测将在未来跟随该事件发生的 PointerEvent 序列。
对于所有其他可信事件类型,它是一个空列表。
不可信事件的预测事件列表会初始化
为传给
构造函数的值。
列表中的事件数量以及它们距离当前时间戳有多远,由 用户代理及其使用的预测算法决定。
可信事件的预测事件列表中的事件将具有:
timeStamp 值
[DOM]——所有预测事件的
timeStamp 都
大于或等于调用
getPredictedEvents 方法的
已分派指针事件的 timeStamp。预测事件列表
必须按 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 时,对于
合并事件列表和预测事件列表中的每个事件,用户代理应该运行以下步骤:
pointerId、
pointerType、
isPrimary 和 isTrusted 设置为与
“父”指针事件的相应属性相匹配。
cancelable 和 bubbles 设置为 false(因为
这些事件永远不会
被单独分派)。PointerEvent 值。当可信的 PointerEvent 的 target 被更改时,对于
合并事件列表和预测事件列表中的每个事件,用户代理
应该:
如今绝大多数现有 Web 内容都只针对鼠标事件编写代码。下面描述了一种算法,说明用户 代理可以如何将通用指针输入映射到鼠标事件,以与 此类内容兼容。
与鼠标事件的兼容性映射是本规范的一项可选功能。鼓励用户代理支持此功能,以便与现有旧版 内容实现最佳兼容性。
总体而言,兼容性鼠标事件旨在 "交错" 于其各自对应的 指针事件之间。然而,这一特定顺序并非强制,用户代理若实现 兼容性鼠标事件,则 可以 决定延迟或分组派发 鼠标事件,只要它们的相对顺序保持一致。
特别是在触摸屏输入的情况下,用户代理 可以 应用
额外的手势识别启发式方法(除非作者显式加以抑制,所用方式是 )。在一段序列中,
其中的事件位于一个 touch-actionpointerdown 事件与一个 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)应该 模拟 单个
传统鼠标输入的移动。这意味着每个事件目标的进入/离开状态都是有效的。用户代理
应该 保证这一点,方法是维护 传统鼠标指针的有效位置,在文档中的维护方式如下。
就在触发一个 pointerdown、pointerup 或 pointermove 事件,或一个 pointerleave 事件(目标为 window)之前,
用户代理 应该 执行以下步骤:
pointerdown、pointerup 或 pointermove 事件,该事件正在被派发。对于 pointerleave 事件,将 T 设为未设置状态。mouseover、mouseout、mouseenter 和
mouseleave 事件,按照鼠标事件的规定处理鼠标从当前 传统鼠标指针的有效
位置 到 T 的移动。将未设置的值(无论是当前的 传统鼠标指针的有效
位置 还是 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 事件,或一个 pointerleave 事件(目标为 window),
则派发兼容性鼠标过渡事件,具体见 跟踪
传统鼠标指针的有效位置。pointerdown 且该事件的 已取消标志 已设置,则设置
PREVENT MOUSE EVENT 标志(对应此 pointerType)。
PREVENT MOUSE EVENT 标志 未 设置于此
pointerType,且已派发的指针事件为:
pointerdown,则触发一个
mousedown 事件。
pointermove,则触发一个
mousemove 事件。
pointerup,则触发一个
mouseup 事件。
pointercancel,
则触发一个 mouseup 事件,目标为 window。pointerup 或 pointercancel,则清除
PREVENT MOUSE EVENT 标志(对应此 pointerType)。
某些设备(例如大多数触摸屏)在不处于活动状态时,不支持在某个坐标(或一组坐标)上 悬停。大量现有针对鼠标事件编写的内容都假定这些事件由鼠标 产生,因此通常认为以下特性成立:
mousemove 事件。
这要求用户代理为这些类型的输入设备提供不同的映射。每当 用户代理要为不支持悬停的设备分派指针事件时,它应该运行以下步骤:
isPrimary 属性为 false
则派发该指针事件并终止这些步骤。pointerover 且 pointerdown 事件尚未派发
(针对此指针),则触发一个 mousemove 事件(为了兼容传统的
鼠标专用代码)。pointerdown、pointerup 或 pointermove 事件,或一个 pointerleave 事件(目标为 window),
则派发兼容性鼠标过渡事件,具体见 跟踪
传统鼠标指针的有效位置。pointerdown 且该事件的 已取消标志 已设置,则设置
PREVENT MOUSE EVENT 标志(对应此 pointerType)。
PREVENT MOUSE EVENT 标志 未 设置于此
pointerType,且已派发的指针事件为:
pointerdown,则触发一个
mousedown 事件。
pointermove,则触发一个
mousemove 事件。
pointerup,则触发一个
mouseup 事件。
pointercancel,
则触发一个 mouseup 事件,目标为 window。pointerup 或 pointercancel,则清除
PREVENT MOUSE EVENT 标志(对应此 pointerType)。
如果用户代理同时支持触摸事件(定义见 [TOUCH-EVENTS]) 和指针事件,则 用户 代理 不得 同时 生成兼容性鼠标事件(如 本节所述)以及 回退 鼠标事件,后者概述于 [TOUCH-EVENTS]。
激活元素(click)所用的主指针若 不支持悬停(例如,
触摸屏上的单根手指),通常会产生以下事件序列:
mousemovepointeroverpointerentermouseovermouseenterpointerdownmousedownpointermove 和
mousemove 事件,具体取决于指针的移动
pointerupmouseuppointeroutpointerleavemouseoutmouseleaveclick但是,如果 pointerdown 事件的 已取消标志 在
此次交互期间被设置,则事件序列如下:
mousemovepointeroverpointerentermouseovermouseenterpointerdownpointermove 事件,
具体取决于指针的移动pointeruppointeroutpointerleavemouseoutmouseleaveclick鼠标事件模块源自 [HTML401] 的 onclick、
ondblclick、onmousedown、onmouseup、onmouseover、
onmousemove 和 onmouseout 属性。此事件模块专门设计
用于指点输入设备,例如鼠标或轨迹球。
在 DOM 第 2 级中引入,在本规范中修改。
该 MouseEvent 接口提供特定的上下文
信息,这些信息与鼠标事件相关联。
在元素嵌套的情况下,鼠标事件始终以嵌套最深的元素为目标。
目标元素的祖先可以利用事件冒泡获得鼠标事件的通知, 这些事件发生在其后代元素内。
要创建一个 MouseEvent 接口的实例,请使用 MouseEvent 构造函数,并传入一个可选的 MouseEventInit 字典。
在初始化 MouseEvent 对象时,若使用
initMouseEvent,实现可以使用客户区坐标 clientX 和 clientY 来计算其他坐标
(例如 DOM 第 0 级实现所暴露的目标坐标或其他专有属性,
如 pageX)。
WebIDLdictionary MouseEventInit : EventModifierInit {
long screenX = 0;
long screenY = 0;
long clientX = 0;
long clientY = 0;
short button = 0;
unsigned short buttons = 0;
};
[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事件发生位置的水平坐标,相对于原点(屏幕 坐标系)。
此 未初始化值
对于该
属性 必须 为 0。
screenY事件发生位置的垂直坐标,相对于原点(屏幕 坐标系)。
此 未初始化值
对于该
属性 必须 为 0。
clientX事件发生位置的水平坐标,相对于关联视口,该视口关联于 该事件。
此 未初始化值
对于该
属性 必须 为 0。
clientY事件发生位置的垂直坐标,相对于关联视口,该视口关联于此 事件。
此 未初始化值
对于该
属性 必须 为 0。
layerX
水平偏移量,以最近的满足以下条件的 祖先 元素为参照:该元素是一个 层叠上下文、已 定位,或在以下过程的 定位阶段被绘制:绘制层叠 上下文。
此 未初始化值
对于该
属性 必须 为 0。
layerY
垂直偏移量,以最近的满足以下条件的 祖先 元素为参照:该元素是一个 层叠上下文、已 定位,或在以下过程的 定位阶段被绘制:绘制层叠 上下文。
此 未初始化值
对于该
属性 必须 为 0。
ctrlKey参见 KeyboardEvent 的 ctrlKey
属性。
此 未初始化值
对于该
属性 必须 为 false。
shiftKey参见 KeyboardEvent 的 shiftKey
属性。
此 未初始化值
对于该
属性 必须 为 false。
altKey
参见 KeyboardEvent 的 altKey
属性。
此 未初始化值
对于该
属性 必须 为 false。
metaKey参见 KeyboardEvent 的 metaKey
属性。
此 未初始化值
对于该
属性 必须 为 false。
button
在按下或释放鼠标按钮所引发的鼠标事件期间,button 必须
用于指示指点设备的哪个按钮改变了状态。
取值对于 button 属性而言 必须 如下:
0 必须 表示设备的主按钮(在
一般情况下,为左键或单按钮设备上唯一的按钮,用于激活
用户界面控件或选择文本),或表示未初始化值。1 必须 表示辅助按钮(通常为
中键,常与鼠标滚轮结合)。2 必须 表示次要按钮(通常为
右键,常用于显示上下文菜单)。3 必须 表示 X1(后退)按钮。4 必须 表示 X2(前进)按钮。某些指点设备提供或模拟更多按钮状态,而大于
2 或小于 0 的值 可以 用于表示
此类按钮。
取值对于 button 而言,不会
因并非由鼠标按钮按下/释放所引发的事件而更新。在这些
情形中,请注意不要将值 0 解释为左键,而
应将其解释为默认值。
此 未初始化值
对于该
属性 必须 为 0。
buttons在任何鼠标事件期间,buttons 必须
用于指示哪些鼠标按钮的组合
当前正被按下,以位掩码表示。
该 buttons 属性是一个位字段。
如果值为 1 的掩码应用于位字段的值时结果为真,则主
鼠标按钮已按下。如果值为 2 的掩码应用于位
字段的值时结果为真,则鼠标右键已按下。如果值为 4 的掩码应用于
位字段的值时结果为真,则辅助按钮/中键已按下。
尽管名称相似,但以下两个属性的值,即 buttons 属性和
button 属性的值,有很大
差异。以下属性的值,即 button 的值,
假定在以下情况下有效:mousedown / mouseup 事件处理器运行期间,而 buttons 属性反映了
鼠标按钮的状态,适用于任何受信任的 MouseEvent 对象(在其正在
派发时),因为它可以表示 "当前没有活动按钮" 状态(0)。
取值对于 buttons 属性而言 必须 如下:
0 必须 表示当前没有活动按钮。1 必须 表示设备的主按钮(在
一般情况下,为左键或单按钮设备上唯一的按钮,用于激活
用户界面控件或选择文本)。2 必须 表示次要按钮(通常为
右键,常用于显示上下文菜单),如果存在。4 必须 表示辅助按钮(通常为
中键,常与鼠标滚轮结合)。某些指点设备提供或模拟更多按钮。为了表示此类按钮,其值 必须 随每个后续按钮依次加倍(按二进制序列
8、16、32、... )。
由于任意一组按钮值的和都是唯一的数值,内容作者可以
使用按位运算确定当前按下了多少个按钮以及具体是哪些
按钮,这适用于设备上任意数量的鼠标按钮。例如,
值 3 表示左键和右键当前均被按下,
而值 5 表示左键和中键当前均
被按下。
此 未初始化值
对于该
属性 必须 为 0。
relatedTarget用于标识一个次要的 EventTarget,与 UI
事件相关,具体取决于事件类型。
此 未初始化值
对于该
属性 必须 为 null。
此 relatedTarget 应该
初始化为鼠标指针刚刚离开其边界的元素(在 mouseover 或 mouseenter 事件的情况下),或另一个元素,其边界
正被鼠标指针进入(在 mouseout 或 mouseleave 或 focusout 事件的情况下)。对于其他事件,此
值无需赋值(默认为 null)。
getModifierState(keyArg)使用键值查询修饰键的状态。
如果它是修饰键且该修饰键已激活,则返回 true,
否则返回 false。
DOMString keyArg
KeyboardEvent 的 getModifierState()
方法中对此参数的描述。生成鼠标事件时,实现必须维护当前点击 计数。该值必须是一个非负 整数,表示在特定时间内连续点击指向设备按钮的次数。 计数重置前的延迟取决于环境配置。
本节中的算法假定原生平台操作系统将提供以下内容:
对于这些事件,操作系统将能够提供以下信息:
本节需要修订。
一般而言,当某个构造函数属于 Event 接口,或属于某个接口,
该接口继承自 Event 接口,且该构造函数被调用时,
步骤(描述于 [DOM])应该被遵循。然而,MouseEvent 接口提供额外的
字典成员,用于初始化内部状态,该状态属于 Event 对象的修饰
键:具体而言,就是通过以下方法查询的内部状态:getModifierState()
方法。本节补充 [DOM] 中的步骤,以初始化一个新的 MouseEvent 对象,并为其设置这些可选的修饰键
状态。
为构造一个 MouseEvent,或从这些对象派生的对象,
使用下面的算法时,所有 MouseEvent 以及派生
对象都具有 内部修饰键状态,可以通过以下名称设置和读取:
修饰键名称,这些名称描述于 修饰键表,位于 [UIEvents-Key]。
以下步骤补充了事件构造算法,该算法定义于 [DOM]:
Event 是一个 MouseEvent 对象或一个派生对象,
派生自该对象,且一个 EventModifierInit
参数已提供给构造函数,则执行以下子步骤:
EventModifierInit
参数,如果字典成员以字符串 "modifier" 开头,则
令 修饰键名称 为该字典
成员的名称(去掉前缀 "modifier"),并设置 Event 对象的 内部修饰键
状态,该状态匹配 修饰键名称,将其设为对应的
值。
本节需要修订。
用户代理必须维护以下由整个用户代理共享的值。
一个用于跟踪鼠标 按钮当前状态的鼠标按钮位掩码。
用户代理必须维护以下由 Window 共享的值。
一个上一个
鼠标元素值(初始为 undefined),用于跟踪最后一个我们向其发送
MouseEvent 的 Element。
一个上一个
鼠标 DOM 路径值(初始为空),其中包含最近一次发送鼠标
事件时上一个鼠标元素的祖先 Element 的快照。
本节需要修订。
MouseEvent 具有以下内部标志,用于
跟踪各种修饰键的状态:
shift 标志、
control
标志、
alt 标志、
altgraph
标志,
以及 meta 标志。
如果鼠标事件发生时按下了相应的修饰键,则设置这些标志。
本节需要修订。
elementFromPoint()
(位于 pos 的最前端 DOM 元素)
为了考虑 惰性或已禁用
元素,应调用 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
待办。
type 是 [
mousedown, mouseup ] 之一,则
button
本节需要修订。
可以从 0x08 开始添加其他按钮。
この節は改訂する必要があります。
mousedown と mouseup の間に他のマウスイベントが発生することがあります。
本节需要修订。
对于会生成点击事件的 mouseup,平台应在处理原生鼠标释放后立即调用此算法。
本节需要修订。
EventTarget
screenX
不是整数值,则将其舍入。screenY
不是整数值,则将其舍入。有关浏览器使用 PointerEvents 和舍入坐标的信息,请参阅 pointerevents/100 。
任何“默认操作”都会在分派期间通过触发目标的 激活 行为 算法来处理。因此,无需在此处处理。 但是,需要验证现有规范是否处理了 disabled/css-pointer-events/inert/...
要处理 HTMLelement.click(),请调用此算法,并将 native =
null,将 target = HTMLelement。
要处理由键盘发起的点击,请调用此算法,并将 native = null 且将 target = 当前获得焦点的元素。
本节需要修订。
对于会生成双击事件的鼠标点击,应在处理原生鼠标点击后立即 调用此算法。
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。
检查影子 DOM 元素的兼容性。Chrome/Linux 会在该 元素和影子根上触发此事件。
本规范中定义的某些鼠标事件彼此之间必须按照既定顺序 发生。下面显示了当指向设备的光标移动到某个元素上时必须发生的 事件序列:
| # | 事件类型 | 元素 | 注释 |
|---|---|---|---|
| 1 | mousemove |
||
| 指向设备移入元素 A... | |||
| 2 | mouseover |
A | |
| 3 | mouseenter |
A | |
| 4 | mousemove |
A | 多个 mousemove 事件 |
| 指向设备移出元素 A... | |||
| 5 | mouseout |
A | |
| 6 | mouseleave |
A |
当指向设备移入元素 A,然后移入嵌套元素 B 再移出时,必须发生以下事件序列:
| 事件类型 | 元素 | 注释 | |
|---|---|---|---|
| 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 的元素,然后再次 移出时,必须发生以下事件序列:
| 事件类型 | 元素 | 注释 | |
|---|---|---|---|
| 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 事件之间,在仍然触发 click 或 dblclick
事件的情况下,允许的延迟时间、程度、距离以及 mousemove 事件数量将取决于具体实现、设备和平台。
这种容差可以帮助存在身体障碍(例如手部不稳)的用户与指向设备进行交互。
每个实现都会确定适当的滞后
容差,但通常,当相关 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
|
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
当用户按下并释放非主指针按钮,或者以模拟此类动作的方式
激活指针时,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) {
// 这将阻止默认行为,例如
// 中键点击链接时打开新标签页。
e.preventDefault();
// 执行其他操作来处理中键点击,例如以适合
// 应用的方式处理在新标签页中打开链接或非链接按钮。
// 其他应在点击动作时执行的操作,例如关闭标签栏中的标签页,
// 也可以在此处完成。
}
});
对于右键,auxclick 事件会在
任何 contextmenu 事件之后分派。请注意,某些用户
代理会在显示上下文菜单期间吞掉所有输入
事件,因此在此类场景中,应用程序可能无法获得 auxclick。
有关更多说明,请参阅示例 10。
myDiv.addEventListener("contextmenu", function(e) {
// 此调用确保不会显示上下文菜单,
// 从而不会干扰页面接收事件。
e.preventDefault();
});
myDiv.addEventListener("auxclick", function(e) {
if (e.button === 2) {
// 执行其他操作来处理右键点击,例如在应用中打开
// 自定义上下文菜单。
}
});
| 类型 | click
|
|---|---|
| 接口 | PointerEvent
|
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
当用户按下并释放主指针按钮,或者以模拟此类动作的方式
激活指针时,click 事件类型必须
分派到指针所指示的最顶层
事件目标上。鼠标按钮的触发
方式取决于指针设备和
环境配置,例如,它可以取决于屏幕
位置或指向设备按钮按下与释放之间的延迟。
click 事件应仅针对主
指针按钮触发(即,当 button 值为 0,
buttons 值为 1 时)。
次要按钮
(例如标准鼠标的中键或右键)不得触发
click 事件。有关与
非主按钮关联的相应事件,请参阅 auxclick。
click 事件可以由同一元素上的 mousedown 和
mouseup 事件先行发生,而忽略
其他节点类型之间的变化(例如文本节点)。根据
环境配置,如果指向设备按钮按下与
释放之间发生一种或多种 mouseover、
mousemove 和 mouseout 事件类型,则可以分派 click 事件。click 事件之后还可以
跟随 dblclick 事件。
如果用户在一个设置了较大
line-height 样式的 <p> 元素的文本节点子节点上按下鼠标,
然后轻微移动鼠标,使其不再位于包含文本的区域上方,
但仍位于该 <p> 元素的包含
块内(即指针位于同一文本块的
行之间,但严格来说并不在文本节点上方),随后释放鼠标,
则这很可能仍会触发 click 事件(如果它位于 click 的正常时间
滞后范围内),因为
用户始终处于同一元素的范围内。请注意,用户代理生成的
鼠标事件不会分派到文本节点。
除了与指针设备相关联之外,
click 事件类型还必须作为元素
激活的一部分进行分派。
为获得最大的可访问性,鼓励内容作者在为自定义
控件定义激活行为时使用
click 事件类型,而不是 mousedown 或 mouseup 等更依赖具体设备的指向设备事件类型。
尽管 click 事件类型起源于指针
设备(例如鼠标),后续实现增强已将其扩展到这种关联之外,
因而可以将其视为一种用于元素激活的
与设备无关的事件类型。
click 事件类型的默认动作
会根据事件的目标以及
button 或 buttons 属性的值而有所不同。click 事件类型的典型
默认动作如下:
| 类型 | dblclick |
|---|---|
| 接口 | MouseEvent |
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
当指向设备的主按钮
在某个元素上被点击两次时,用户代理必须分派此事件。双击的
定义取决于环境
配置,但 mousedown、mouseup 和 dblclick 之间的事件目标必须相同。如果点击
和双击同时发生,则此事件
类型必须在事件类型 click 之后分派,否则在事件类型
mouseup 之后分派。
与 click 事件一样,dblclick
事件应
仅针对主指针按钮触发。次要按钮不得
触发 dblclick 事件。
click 事件类型一样,dblclick
事件类型的默认动作会根据事件的目标以及 button
或 buttons 属性的值而有所不同。dblclick 事件类型的典型
默认动作与
click 事件类型的默认动作相同。
| 类型 | mousedown
|
|---|---|
| 接口 | MouseEvent |
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
当指向设备 按钮在某个元素上被按下时,用户代理必须分派此事件。
| 类型 | mouseenter
|
|---|---|
| 接口 | MouseEvent |
| 冒泡 | 否 |
| 可取消 | 否 |
| 组合 | 否 |
| 上下文 (可信事件) |
|
当指向设备
移动到某个元素或其后代
元素之一的边界上时,用户代理必须分派此事件。当该
元素或其后代之一移动到主
指向设备下方时,用户代理
也必须分派此事件。此事件类型与 mouseover 类似,但
区别在于它不会冒泡,并且当指针设备从一个元素移动到其某个
后代元素的边界上时,不得分派此事件。
此事件类型与 CSS
:hover 伪类之间存在相似之处 [CSS2]。
另请参阅 mouseleave 事件类型。
| 类型 | mouseleave
|
|---|---|
| 接口 | MouseEvent |
| 冒泡 | 否 |
| 可取消 | 否 |
| 组合 | 否 |
| 上下文 (可信事件) |
|
当指向设备
移出某个元素及其所有
后代元素的边界时,用户
代理必须分派此事件。当
该元素或其后代之一移动到不再位于
主指向设备下方时,用户
代理也必须分派此事件。此事件类型与 mouseout
类似,
但区别在于它不会冒泡,并且在指向设备离开
该元素及其所有子元素的边界之前,不得
分派此事件。
此事件类型与 CSS
:hover 伪类之间存在相似之处 [CSS2]。
另请参阅 mouseenter 事件类型。
| 类型 | mousemove
|
|---|---|
| 接口 | MouseEvent |
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
当指向设备
位于某个元素上方并发生移动时,用户代理必须分派此事件。指向设备移动时事件的
频率取决于具体实现、设备和
平台,但对于持续的指针设备移动,应该触发多个连续的 mousemove 事件,
而不是针对每次鼠标移动仅触发
单个事件。鼓励实现确定最佳频率,
以在响应性与性能之间取得平衡。
在某些实现环境中,例如浏览器,
如果用户开始了
拖动操作(例如按下鼠标按钮)并且指向
设备已经离开用户代理的边界,mousemove 事件仍可以继续触发。
此事件以前在 DOM 第 2 级 事件中被规定为不可取消,但后来进行了更改,以反映 用户代理之间现有的互操作性。
| 类型 | mouseout
|
|---|---|
| 接口 | MouseEvent |
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
|
当指向设备
移出某个元素的边界,或者该元素
移动到不再位于主指向设备下方时,用户代理必须分派此事件。
此事件类型与 mouseleave 类似,但区别在于
它会冒泡,并且当指针设备
从一个元素移动到其某个后代元素的边界上时,必须分派此事件。
另请参阅 mouseover 事件类型。
| 类型 | mouseover
|
|---|---|
| 接口 | MouseEvent |
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
|
当指向设备
移动到某个元素的边界上,或者该元素
移动到主指向设备下方时,用户代理必须分派此事件。
此事件类型与 mouseenter 类似,但区别在于
它会冒泡,并且当指针设备移动到
某个元素的边界上,而该元素的祖先元素是同一个事件监听器实例的目标时,必须分派此事件。
另请参阅 mouseout 事件类型。
| 类型 | mouseup
|
|---|---|
| 接口 | MouseEvent |
| 冒泡 | 是 |
| 可取消 | 是 |
| 组合 | 是 |
| 上下文 (可信事件) |
当指向设备 按钮在某个元素上被释放时,用户代理必须分派此事件。
在某些实现环境中,例如浏览器,即使
指向设备已经离开用户代理的边界,也可以分派
mouseup 事件,例如,如果用户在
按住鼠标按钮的情况下开始了拖动操作。
滚轮是可以在一个或多个空间维度上旋转的设备,并且可以与 指针设备关联。坐标系取决于环境配置。
用户的环境可以配置为将垂直滚动 与沿 y 轴的旋转关联,将水平滚动与沿 x 轴的旋转关联,并将缩放与沿 z 轴的旋转关联。
WheelEvent
对象的 deltaX、deltaY 和 deltaZ 属性表示
沿各自轴的测量值,单位为像素、行或
页面。报告的测量值是在特定于环境的
算法将滚轮设备的实际旋转/移动转换为
相应值和单位之后提供的。
用户的环境设置可以自定义,以不同方式解释滚轮设备的实际旋转/移动。
常见的有刻度
鼠标滚轮移动一次可以产生 162 像素的测量值
(162 只是一个示例值,实际值可能取决于用户代理当前的屏幕
尺寸)。
但用户可以更改其默认环境设置以加快鼠标滚轮速度,
从而增大这个数值。
此外,某些鼠标滚轮软件可以支持加速(滚轮
旋转/移动得越快,每次测量的增量就越大),甚至支持亚像素旋转
测量。
因此,作者不能假定某个用户代理中的给定旋转量会
在所有用户代理中产生相同的增量值。
deltaX、deltaY 和 deltaZ 属性值的符号(正或负)
在实际滚轮设备沿相同方向旋转/移动期间,多次分派
wheel 事件时必须保持一致。
如果用户代理将滚动作为
wheel 事件的默认动作,则
增量的符号应该由右手坐标系确定,其中正 X、
Y 和 Z 轴分别指向文档的最右边缘、最下边缘以及最远
深度(远离用户)。
各个用户代理可以(取决于其环境和硬件配置) 对滚轮上的同一物理用户交互作出不同解释。 例如,在触控板边缘从上到下的垂直滑动可以被 解释为旨在向下滚动 页面或向上平移页面的滚轮动作(即分别产生正值或负值的 deltaY)。
当触发第一个滚轮事件时,用户代理必须创建一个滚轮事件事务, 以便在特定于实现的一段时间内,所有后续滚轮事件都可以以同一元素为目标。 滚轮事件事务是与单个用户手势关联的一系列 滚轮事件。滚轮事件事务必须 具有一个关联的事件目标,该目标是在组中第一个滚轮事件 发生时的最顶层事件目标。
如果以某个可滚动元素为目标的一系列滚轮事件开始于某个子元素上方, 则同一用户手势的后续事件可能发生在该子元素上。
WheelEvent 接口提供与 wheel 事件关联的特定上下文
信息。
要创建 WheelEvent 接口的实例,请使用 WheelEvent 构造函数,并传入可选的 WheelEventInit 字典。
WebIDLdictionary WheelEventInit : MouseEventInit {
double deltaX = 0.0;
double deltaY = 0.0;
double deltaZ = 0.0;
unsigned long deltaMode = 0;
boolean momentum = false;
};
[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_PAGEdeltaX
wheel
事件默认动作的用户代理中,当事件未被取消时,该值必须是沿
x 轴要滚动的测量值(以像素、行或页面为单位)。
否则,这是滚轮设备绕 x 轴移动的
特定于实现的测量值(以像素、行或页面为单位)。
此属性的未初始化值必须为
0.0。
deltaY
wheel
事件默认动作的用户代理中,当事件未被取消时,该值必须是沿
y 轴要滚动的测量值(以像素、行或页面为单位)。
否则,这是滚轮设备绕 y 轴移动的
特定于实现的测量值(以像素、行或页面为单位)。
此属性的未初始化值必须为
0.0。
deltaZ
在将滚动作为 wheel
事件默认动作的用户代理中,当事件未被取消时,该值必须是沿
z 轴要滚动的测量值(以像素、行或页面为单位)。
否则,这是滚轮设备绕 z 轴移动的
特定于实现的测量值(以像素、行或页面为单位)。
此属性的未初始化值必须为
0.0。
初始化 deltaZ 属性,该属性属于 WheelEvent
对象。此属性(以及
deltaX 和 deltaY 属性)的相对正值
由右手坐标系给出,其中 X、Y 和 Z
轴分别指向文档的最右边缘、最下边缘
和最远深度(远离用户)。
负的相对值则位于各自相反的方向。
deltaModedeltaMode 属性包含
增量值测量单位的指示。默认值为
DOM_DELTA_PIXEL(像素)。
此属性必须设置为 DOM_DELTA 常量之一,以 表示增量值的测量单位。 精确测量方式取决于设备、操作系统 和应用程序配置。
此属性的未初始化值必须为
0。
momentum如果此事件由平台合成,用于在
用户结束物理滚动交互后模拟滚动惯性(例如
快速滑动后从触控板抬起手指),则此属性必须为 true,
否则为
false。
此属性的未初始化值必须为
false。
| 类型 | wheel |
|---|---|
| 接口 | WheelEvent |
| 冒泡 | 是 |
| 可取消 | 视情况而定 |
| 组合 | 是 |
| 上下文 (可信事件) |
|
当鼠标滚轮绕任意轴旋转,或者等效输入设备
(例如轨迹球、某些平板设备或触控板等)
模拟此类动作时,用户代理必须分派此事件。根据平台和输入设备不同,
对角线方向的滚轮增量可以作为一个
在多个轴上具有非零值的 wheel 事件传递,也可以针对每个非零轴作为单独的
wheel 事件传递。
wheel 事件类型的典型默认
动作是按指定
量滚动(或在某些情况下缩放)文档。如果取消此事件,实现不得
滚动或缩放文档(也不得执行与此事件
类型关联的任何其他特定于实现的默认动作)。
在滚轮事件上调用 preventDefault 可以阻止
或以其他方式中断滚动。为了获得最大的滚动性能,
用户代理可以不等待处理与滚动相关的每个滚轮事件
来查看它是否会被取消。在这种情况下,用户
代理应生成 cancelable 属性为 false 的
wheel 事件,表示
不能使用 preventDefault 来阻止或中断
滚动。否则,cancelable 将为 true。
特别是,当用户代理
观察到
该事件不存在非被动监听器时,应只生成不可取消的
wheel 事件。
本节为非规范性内容。
以下是一些基本示例,用于演示作者可以如何使用本规范中的某些 API。 本文档的相关章节还提供了更多、更具体的示例。
/* 绑定到指针事件或传统的触摸/鼠标事件 */
if (window.PointerEvent) {
// 如果支持指针事件,则只监听指针事件
target.addEventListener("pointerdown", function(e) {
// 如有必要,根据 e.pointerType 应用不同逻辑
// 以处理不同的触摸/笔/鼠标行为
...
});
...
} else {
// 传统的触摸/鼠标事件处理程序
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 为空(无法检测)
或为用户代理特定的自定义类型 */
}
}
<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>
本附录讨论指针事件实现的安全和隐私注意事项。 讨论仅限于直接由本规范中定义的事件 模型、API 和事件的实现所引起的安全和隐私问题。
本规范中定义的许多事件类型都是为响应用户动作而分派的。这使 恶意事件监听器能够访问用户通常认为属于机密的信息,例如 用户在与页面交互时鼠标/触控笔/手指的精确路径/移动。
指针事件还包含其他信息(如果用户设备支持),例如笔输入 握持时的角度或倾斜度、接触面的几何形状,以及施加在 触控笔或触摸屏上的压力。有关角度、倾斜度、几何形状和压力的信息都与 用户设备上的传感器直接相关,这意味着本规范允许源访问这些传感器。
这些传感器数据,以及确定所使用输入机制类型(鼠标、触摸、笔)的能力, 都可能用于推断用户的特征,或用户设备和环境的特征。这些推断出的 特征以及任何设备/环境信息本身都可能是敏感的——例如,它们可能 允许恶意网站进一步推断用户是否正在使用辅助技术。这些信息还 可能被用于构建用户画像和/或尝试对特定用户进行“指纹识别”和跟踪。
作为缓解措施,用户代理可以考虑提供让用户禁用对特定 传感器数据(例如角度、倾斜度、压力)访问的能力,和/或仅在用户明确选择加入后 才提供这些数据。
本规范定义了作者访问“预测事件”的方法。本规范本身 并未定义用户代理应使用的预测算法。规范 作者设想,这些算法仅依赖与用户当前执行手势相关的先前指针事件。 用户代理有责任确保其预测算法的具体实现 不依赖任何额外数据——例如用户跨不同网站的完整交互历史—— 因为这些数据可能泄露用户的敏感信息,或被用于对其进行“指纹识别” 和跟踪。
除这些注意事项外,工作组认为本规范:
本节为非规范性内容。
buttons 属性值非零时的状态。对于鼠标,这是
设备至少有一个按钮被按下的状态。对于触摸,这是与数字化器存在物理接触的状态。
对于笔,这是笔与数字化器存在物理接触,或者在悬停时至少有一个按钮被按下的状态。pointerId 标识)
仍有可能在文档中产生其他事件,则该指针仍被视为活动状态。示例:
WheelEvent 接口的输入设备
(例如鼠标滚轮或触控板)的物理移动而滚动或缩放
页面时的估计滚动量(以像素、行或页面为单位)。增量值(例如 deltaX、deltaY 或 deltaZ 属性)应在当前 deltaMode 属性的上下文中解释。滚轮
(或其他设备)的物理移动与增量为正还是为负之间的关系
取决于环境和设备。但是,如果用户代理将滚动作为默认动作,则增量的符号
由右手坐标系给出,其中正 X、Y 和 Z 轴分别指向文档的
最右边缘、最下边缘和最远深度(远离用户)。可测量属性表示与连续指针传感器数据相关的值,这些值使用
实数或来自大范围域的
整数表示。对于指针事件,width、height、
pressure、
tangentialPressure、tiltX、tiltY、twist、
altitudeAngle、azimuthAngle,以及鼠标事件模型属性
screenX、screenY、clientX、clientY 都是
可测量属性。
相比之下,pointerId、pointerType、
isPrimary,以及
鼠标事件模型属性 button、buttons、ctrlKey、
shiftKey、altKey 和 metaKey 不被视为可测量
属性,
因为它们与传感器数据无关。
WheelEvent 接口表示输入设备上的增量变化。
在某些设备上,这可以是滚轮的字面旋转,而在另一些设备上,它可以是沿平面的移动,或者对特定按钮施加压力。
命中测试机制用于 确定目标。有关命中测试和堆叠顺序的具体细节,请参阅宿主语言。
本节为规范性内容。 以下功能已经过时,仅应由需要 与旧式软件兼容的用户代理实现。 另请参阅 [UIEvents] 中的旧式事件初始化器。
WebIDLpartial interface MouseEvent {
};
initMouseEvent(typeArg)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] 规范。 请参阅本规范编辑者 草案的完整修订历史。
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();
};
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;
};
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;
};
[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 WheelEventInit : MouseEventInit {
double deltaX = 0.0;
double deltaY = 0.0;
double deltaZ = 0.0;
unsigned long deltaMode = 0;
boolean momentum = false;
};
[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;
};
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: