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] 内容被用于或设计用于鼠标输入。那些以自定义方式处理输入的内容,通常会针对 [UIEVENTS] 鼠标事件进行编码。然而,现代计算设备正逐步引入其他输入方式,包括触摸屏和笔输入。针对这些不同输入形式已提出专门的事件类型来分别处理,但这种做法在新增某类输入支持时,常常导致逻辑和事件处理的重复,带来不必要的开销。此种方式还会造成内容仅考虑某一种设备类型时的兼容性问题。此外,为了与基于鼠标的现有内容兼容,大多数用户代理会为所有输入类型触发鼠标事件。这就会让鼠标事件是否真正代表鼠标设备变得模糊不清,抑或只是为兼容性由其他输入类型生成的,使得同时针对多种设备编码变得困难。
为减少多输入类型编码的成本,同时缓解上述鼠标事件的歧义问题,本文规范定义了一种更抽象的输入方式,称为指针(pointer)。指针可以是屏幕上由鼠标光标、笔、触摸(包括多点触控)或其他指向性输入设备所产生的任意接触点。这一模型让站点和应用能够更容易地兼容用户设备的各种硬件。对于需要进行设备专属处理的场景,本规范也定义了用于检测产生事件的设备类型的属性。主要目标是提供一套统一的事件及接口,让跨设备指针输入的开发更加便利,同时仅在需要时提供设备特有的增强体验。
另一个关键目标在于使多线程用户代理能处理直接操作的平移和缩放(例如,用户用手指或手写笔在触摸屏上操作),且不会因脚本执行而阻塞界面。
用于处理通用指针输入的事件,与鼠标事件非常相似:pointerdown、pointermove、pointerup、
pointerover、
pointerout 等。这极大方便了从鼠标事件到指针事件的内容迁移。
Pointer Events 除了包含 Mouse Events
的全部常用属性(如客户端坐标、目标元素、按钮状态)外,还新增了针对不同输入方式的属性,例如压力、接触几何、倾斜角等。这样,作者便可根据需要,灵活地在逻辑复用和设备专项体验间做取舍。
指针事件可能来源于多种输入设备,但其并未被定义为从其它特定设备事件转换生成。尽管可以为兼容性目的这样做,并很鼓励这么做,但此规范并不要求必须实现其它设备相关事件(如鼠标事件或触摸事件)。用户代理可以仅实现指针事件而不实现其它设备事件。为兼容只处理鼠标事件的内容,本规范也提供了可选章节,描述如何根据鼠标之外设备的指针输入生成兼容鼠标事件。
本规范未对同时支持 [TOUCH-EVENTS] Touch Events 和 Pointer Events 的用户代理的期望行为提出建议。两者之间关系的详细信息见 Touch Events 社区组。
除标记为非规范性的章节外,本规范中的所有编写指南、图示、示例与注释均为非规范性内容。本规范中其余内容均为规范性内容。
本文档中的关键字 MAY、MUST、MUST NOT、OPTIONAL 与 SHOULD 的解释应遵循 BCP 14 [RFC2119] [RFC8174] 中所述,仅当这些词以全大写形式出现时(如这里所示)才适用。
本节为非规范性内容。
以下是一些基础示例,用于演示作者可能如何使用本规范中的部分 API。此外,在本文档相关章节还提供了更具体的示例。
/* Bind to either Pointer Events or traditional touch/mouse */
if (window.PointerEvent) {
// if Pointer Events are supported, only listen to pointer events
target.addEventListener("pointerdown", function(e) {
// if necessary, apply separate logic based on e.pointerType
// for different touch/pen/mouse behavior
...
});
...
} else {
// traditional touch/mouse event handlers
target.addEventListener('touchstart', function(e) {
// prevent compatibility mouse events and click
e.preventDefault();
...
});
...
target.addEventListener('mousedown', ...);
...
}
// additional event listeners for keyboard handling
...
window.addEventListener("pointerdown", detectInputType);
function detectInputType(event) {
switch(event.pointerType) {
case "mouse":
/* mouse input detected */
break;
case "pen":
/* pen/stylus input detected */
break;
case "touch":
/* touch input detected */
break;
default:
/* pointerType is empty (could not be detected)
or UA-specific custom type */
}
}
<div style="position:absolute; top:0px; left:0px; width:100px;height:100px;"></div>
<script>
window.addEventListener("pointerdown", checkPointerSize);
function checkPointerSize(event) {
event.target.style.width = event.width + "px";
event.target.style.height = event.height + "px";
}
</script>
const event1 = new PointerEvent("pointerover",
{ bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500
});
eventTarget.dispatchEvent(event1);
let pointerEventInitDict =
{
bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500,
};
const p1 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.clientX += 10;
const p2 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.coalescedEvents = [p1, p2];
const event2 = new PointerEvent("pointermove", pointerEventInitDict);
eventTarget.dispatchEvent(event2);
<div style="position:absolute; top:0px; left:0px; width:100px;height:100px;"></div>
<script>
window.addEventListener("pointerdown", assignPenColor);
window.addEventListener("pointermove", assignPenColor);
const colorMap = new Map();
function assignPenColor(event) {
const uniqueId = event.persistentDeviceId;
// Check if a unique Id exists.
if (uniqueId == 0) {
return;
}
// Check if a color has been assigned to the device.
if (map.has(uniqueId)) {
return;
}
// Assign a color to the device.
let newColor = getNewColor();
map.set(uniqueId, newColor);
return newColor;
}
function getNewColor() {
/* return some color value */
}
</script>
鼠标事件模块起源于 [HTML401] 的 onclick、
ondblclick、onmousedown、onmouseup、onmouseover、
onmousemove 与 onmouseout 属性。该事件模块专门为指向性输入设备(如鼠标或轨迹球)而设计。
在 DOM Level 2 中引入,并在本规范中进行了修改。
MouseEvent 接口提供与鼠标事件相关的特定上下文信息。
在嵌套元素的情况下,鼠标事件始终以最深层嵌套的元素为目标。
目标元素的祖先元素可以使用事件冒泡来获取其后代元素内发生的鼠标事件通知。
要创建 MouseEvent 接口的实例,请使用 MouseEvent 构造函数,并传入一个可选的 MouseEventInit 字典。
在使用 initMouseEvent 初始化 MouseEvent 对象时,实现可以使用客户端坐标 clientX 与 clientY 来计算其它坐标(例如 DOM Level 0
实现所暴露的目标坐标,或其它专有属性,如 pageX)。
WebIDL[Exposed=Window]
interface MouseEvent : UIEvent {
constructor(DOMString type, optional MouseEventInit eventInitDict = {});
readonly attribute long screenX;
readonly attribute long screenY;
readonly attribute long clientX;
readonly attribute long clientY;
readonly attribute long layerX;
readonly attribute long layerY;
readonly attribute boolean ctrlKey;
readonly attribute boolean shiftKey;
readonly attribute boolean altKey;
readonly attribute boolean metaKey;
readonly attribute short button;
readonly attribute unsigned short buttons;
boolean getModifierState(DOMString keyArg);
};
screenX事件发生时相对于屏幕坐标系原点的水平坐标。
该属性的未初始化值 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 的值来表示这些按钮。
对于非由鼠标按钮按下/释放导致的事件,button
的值不会更新。在这些场景中,应注意不要将 0 解释为左键,而应将其视为默认值。
该属性的未初始化值 MUST 为 0。
buttons
在任何鼠标事件期间,buttons MUST 用于指示当前被按下的鼠标按钮组合,并以位掩码(bitmask)表示。
尽管名称相似,buttons 属性与 button 属性的取值差异很大。button 的值被假定在 mousedown / mouseup 事件处理程序中有效;而 buttons 属性反映任意受信任的 MouseEvent
对象(在其被派发期间)中鼠标按钮的状态,因为它可以表示“当前没有任何按钮处于激活状态”的状态(0)。
buttons 属性的取值 MUST 如下:
0 MUST 表示当前没有按钮处于激活状态。1 MUST
表示设备的主按钮(通常为左键,或单按钮设备上的唯一按钮,用于激活用户界面控件或选择文本)。2 MUST 表示次按钮(通常为右键,常用于显示上下文菜单),如果存在。4 MUST 表示辅助按钮(通常为中键,常与鼠标滚轮组合)。
某些指向设备提供或模拟更多按钮。为表示这些按钮,每增加一个后续按钮,其值 MUST 都必须加倍(按二进制序列
8、16、32、...)。
由于任意一组按钮值之和都是唯一的数字,内容作者可以使用按位运算来确定当前按下了多少个按钮以及分别是哪些按钮,且可适用于设备上任意数量的鼠标按钮。例如,值
3 表示左键与右键当前都被按下;值 5 表示左键与中键当前都被按下。
该属性的未初始化值 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
属性初始化为所需的、鼠标指针在用户屏幕上的水平相对位置。
将事件对象初始化为给定的鼠标位置,不得将用户的鼠标指针移动到所初始化的位置。
screenY
将 screenY
属性初始化为所需的、鼠标指针在用户屏幕上的垂直相对位置。
将事件对象初始化为给定的鼠标位置,不得将用户的鼠标指针移动到所初始化的位置。
clientX
将 clientX
属性初始化为所需的、鼠标指针相对于用户浏览器客户端窗口的水平位置。
将事件对象初始化为给定的鼠标位置,不得将用户的鼠标指针移动到所初始化的位置。
clientY
将 clientY
属性初始化为所需的、鼠标指针相对于用户浏览器客户端窗口的垂直位置。
将事件对象初始化为给定的鼠标位置,不得将用户的鼠标指针移动到所初始化的位置。
button
将 button 属性初始化为一个数字,用于表示鼠标按钮的期望状态。
值 0 用于表示主鼠标按钮,值 1 用于表示辅助/中键,值 2 用于表示右键。大于 2 的数字也可能出现,但本文档未对此进行规定。
buttons
将 buttons
属性初始化为一个数字,用于表示鼠标按钮中需要被视为激活的一个或多个按钮。
buttons
属性是一个位字段(bit-field)。若对位字段值应用掩码 1 后结果为真,则主鼠标按钮处于按下状态;若应用掩码 2 后结果为真,则右键处于按下状态;若应用掩码 4
后结果为真,则辅助/中键处于按下状态。
在 JavaScript 中,要将 buttons
属性初始化为如同右键(2)与中键(4)同时被按下,可将 buttons 的值赋为以下任一形式:
{ buttons: 2 | 4 }
或:
{ buttons: 6 }
relatedTarget
relatedTarget
应初始化为鼠标指针刚刚离开的元素边界(对于 mouseover 或 mouseenter 事件),或鼠标指针正在进入其边界的元素(对于 mouseout 或 mouseleave 或 focusout 事件)。对于其它事件,该值无需赋值(默认为
null)。
实现 MUST 在生成鼠标事件时维护 当前点击计数。该计数 MUST 是一个非负整数,用于表示在特定时间内指向设备按钮的连续点击次数。计数在何时重置的延迟取决于环境配置。
本节中的算法假设原生平台操作系统将提供以下内容:
对于这些事件,操作系统将能够提供以下信息:
本节需要修订。
一般而言,当调用 Event 接口的构造函数,或调用继承自 Event 接口的接口构造函数时,应遵循 [DOM]
中描述的步骤。然而,MouseEvent 接口还提供了额外的字典成员,用于初始化 Event 对象的按键修饰符的内部状态:具体来说,即通过 getModifierState()
方法查询的内部状态。本节补充了 [DOM] 中初始化新的 MouseEvent 对象的步骤,以包含这些可选的修饰键状态。
为了构造 MouseEvent,或使用下述算法从这些对象派生的对象,所有 MouseEvent 及其派生对象都具有 内部按键修饰符状态,其可使用 [UIEvents-Key]
中 修饰键表 所描述的 修饰键名称 来进行设置与读取。
以下步骤补充了 [DOM] 中定义的用于构造事件的算法:
Event 是一个 MouseEvent 对象或其派生对象,并且构造函数提供了一个 EventModifierInit
参数,则运行以下子步骤:
EventModifierInit
参数,如果该字典成员以字符串 "modifier" 开头,则令 按键修饰键名称 为该字典成员去除前缀 "modifier" 后的名称,并将 Event 对象中与该 按键修饰键名称 匹配的 内部按键修饰键状态
设置为相应的值。
本节需要修订。
用户代理必须维护以下在整个用户代理范围内共享的值。
一个用于跟踪鼠标按钮当前状态的 鼠标按钮位掩码。
用户代理必须维护以下在该窗口范围内共享的值。
一个 上一个鼠标元素 值(初始为 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 之间可能发生其他鼠标事件。
本节需要修订。
本节需要修订。
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。
检查 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 是 A 的子元素(在 DOM 中):
当指向设备从元素叠层之外移动到标记为 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 事件的滞后时间、程度、距离以及数量,将取决于具体实现、设备与平台。
这种容差可以帮助存在身体障碍(例如手部不稳)的用户在使用指向设备交互时更容易操作。
每种实现将确定合适的 滞后
容差,但总体上 SHOULD 在相关 mousedown
与
mouseup 事件的目标为同一元素,且期间没有插入 mouseout 或
mouseleave 事件时触发 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 |
| 可取消 | 是 |
| 可组合 | 是 |
| 默认动作 | 视情况而定 |
| 上下文 (受信任事件) |
|
当用户按下并释放非主指针按钮,或以其他方式激活指针以模拟此动作时,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) {
// This would prevent the default behavior which is for example
// opening a new tab when middle clicking on a link.
e.preventDefault();
// Do something else to handle middle button click like taking
// care of opening link or non-link buttons in new tabs in a way
// that fits the app. Other actions like closing a tab in a tab-strip
// which should be done on the click action can be done here too.
}
});
在右键的情况下,auxclick 事件会在
任意 contextmenu
事件之后被派发。注意,某些用户代理会在上下文菜单显示期间吞掉所有输入
事件,因此在此类场景下应用可能无法获得 auxclick。
更多说明见 Example 7。
myDiv.addEventListener("contextmenu", function(e) {
// This call makes sure no context menu is shown
// to interfere with page receiving the events.
e.preventDefault();
});
myDiv.addEventListener("auxclick", function(e) {
if (e.button === 2) {
// Do something else to handle right button click like opening a
// customized context menu inside the app.
}
});
| 类型 | click
|
|---|---|
| 接口 | PointerEvent
|
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| 可组合 | 是 |
| 默认动作 | 视情况而定 |
| 上下文 (受信任事件) |
|
当用户按下并释放主指针按钮,或以其他方式激活指针以模拟此动作时,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> 元素的一个文本节点子节点上按下鼠标(该 <p> 元素被设置了很大的
line-height),然后稍微移动鼠标,使其不再位于包含文本的区域上方,但仍处于该 <p>
元素的包含块之内(即指针位于同一文本块的两行之间,但本身并未悬停在文本节点之上),随后释放鼠标,则这很可能仍会触发一个
click 事件(如果它落在 click 的正常时间性滞后范围内),因为用户仍在同一元素的范围内。注意,由用户代理生成的鼠标事件不会派发到文本节点上。
除了与指针设备关联之外,
click 事件类型 MUST
也必须作为元素激活的一部分被派发。
为获得最佳可访问性,建议内容作者在为自定义控件定义激活行为时使用
click 事件类型,而不是诸如
mousedown 或 mouseup 等更具设备特性的指向设备事件类型。
虽然 click
事件类型起源于指针设备(例如鼠标),但后续的实现增强已将其扩展到超出这种关联的范围,它可以被视为用于元素激活的、与设备无关的事件类型。
click 事件类型的 默认动作
会根据事件的 目标 以及
button 或 buttons 属性的值而变化。click 事件类型的典型默认动作如下:
| 类型 | dblclick |
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| 可组合 | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
当用户在某个元素上方用指向设备的主按钮点击两次时,用户代理 MUST
派发此事件。双击的定义取决于环境配置,但要求在
mousedown、mouseup 与 dblclick 之间,事件目标 MUST 相同。
如果点击与双击同时发生,则此事件类型 MUST 在 click
事件类型之后派发;否则在 mouseup 事件类型之后派发。
与 click 事件一样,dblclick
事件应仅对主指针按钮触发。次要按钮 MUST NOT
触发 dblclick 事件。
click 事件类型一样,默认动作在
dblclick 事件类型中会根据事件的 目标 以及 button
或 buttons 属性的值而变化。dblclick 事件类型的典型默认动作与
click 事件类型的典型默认动作相同。
| 类型 | mousedown
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| 可组合 | 是 |
| 默认动作 | 视情况而定:开始拖放操作;开始文本选择;开始滚动/平移交互 (如果支持,则与鼠标中键结合) |
| 上下文 (受信任事件) |
|
| 类型 | mouseenter
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 否 |
| 受信任目标 | Element |
| 可取消 | 否 |
| 可组合 | 否 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mouseover 类似,
但不同之处在于它不冒泡,且当指针设备从某元素移动到其某个后代元素的边界上时,MUST NOT 派发该事件。
此事件类型与 CSS 的
:hover 伪类 [CSS2]
之间存在相似之处。另请参见 mouseleave 事件类型。
| 类型 | mouseleave
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 否 |
| 受信任目标 | Element |
| 可取消 | 否 |
| 可组合 | 否 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mouseout 类似,
但不同之处在于它不冒泡,并且在指向设备离开该元素的边界以及其所有子元素的边界之前,MUST NOT 派发该事件。
此事件类型与 CSS 的
:hover 伪类 [CSS2]
之间存在相似之处。另请参见 mouseenter 事件类型。
| 类型 | mousemove
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| 可组合 | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mousemove
事件,而不是对每次鼠标移动仅触发单个事件。鼓励实现确定最佳的频率,以在响应性与性能之间取得平衡。
在某些实现环境(如浏览器)中,如果用户开始了拖动操作(例如按下鼠标按钮)且指向设备已离开用户代理的边界,mousemove 事件仍可能继续触发。
此事件曾在 DOM Level 2 Events 中被规定为不可取消,但后来进行了更改,以反映用户代理之间现有的互操作性。
| 类型 | mouseout
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| 可组合 | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mouseleave
类似,但不同之处在于它会冒泡,并且当指针设备从某元素移动到其某个后代元素的边界上时,它 MUST 被派发。
另请参见 mouseover 事件类型。
| 类型 | mouseover
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| 可组合 | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
mouseenter
类似,但不同之处在于它会冒泡,并且当指针设备移动到某个元素的边界上,且该元素的祖先元素是同一 目标 上相同 事件监听器 实例的目标时,它 MUST 被派发。
另请参见 mouseout 事件类型。
| 类型 | mouseup
|
|---|---|
| 接口 | MouseEvent |
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信任目标 | Element |
| 可取消 | 是 |
| 可组合 | 是 |
| 默认动作 | 无 |
| 上下文 (受信任事件) |
|
在某些实现环境(如浏览器)中,即使指向设备已离开用户代理的边界,仍可能派发
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 值增大的方向(在 X-Y 平面上俯视时指向“3
点钟”方向),并且数值在顺时针方向逐步增大(π/2 为“6 点钟”、π 为“9 点钟”、3π/2 为“12
点钟”)。当换能器完全垂直于表面(altitudeAngle 为 π/2)时,该值 MUST 为 0。对于不报告倾斜或角度的硬件与平台,该值 MUST 为 0。
azimuthAngle 为 π/6(“4 点钟”方向)。pointerType指示导致该事件的设备类型(如 mouse、pen、touch)。如果用户代理要为鼠标、笔/触控笔或触摸输入设备触发一个指针事件,则 pointerType 的值 MUST 符合下表:
| 指针设备类型 | pointerType 值 |
|---|---|
| Mouse | mouse |
| Pen / stylus | pen |
| Touch contact | touch |
如果用户代理无法检测设备类型,则该值 MUST
为空字符串。如果用户代理支持上述列表之外的指针设备类型,为避免不同设备类型名称冲突,pointerType 的值 SHOULD 使用厂商前缀。未来规范 MAY 为其他设备类型提供额外的规范化取值。
pointerType 的基本用法作了演示。另请注意,开发者应包含某种形式的默认处理,以涵盖用户代理可能实现了自定义
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 触发一个指针事件”是指:使用 PointerEvent 来触发名为
e 的事件,其属性按 PointerEvent 接口以及 属性与默认动作中的定义进行设置。
如果该事件不是 gotpointercapture、lostpointercapture、click、
auxclick 或 contextmenu 事件,则对该 PointerEvent 运行处理待定指针捕获步骤。
确定目标(即事件将触发于其上的目标)如下:
令 targetDocument 为目标的节点文档 [DOM]。
如果事件为 pointerdown、pointermove 或 pointerup,则将该事件的 活动文档
(对应该事件的 pointerId)设置为
targetDocument。
如果事件为 pointerdown,关联设备为直接操控设备,并且目标为 Element,
则按隐式指针捕获中的描述,为该 pointerId设置指针捕获到目标元素。
在触发该事件之前,为了确保事件顺序 [UIEVENTS],用户代理 SHOULD
将目标视为指向设备已从 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] 属性 SHOULD 为
false;对上表中所有其他指针事件,该属性 SHOULD 为 true。
对上表中所有指针事件,其 detail [UIEVENTS] 属性 SHOULD 为 0。
fromElement 与
toElement 以支持遗留内容。我们鼓励这些用户代理将 PointerEvent 中这些(继承的)属性值设置为
null,以促使作者迁移到使用标准替代项(target 与 relatedTarget)。
与 MouseEvent 的 relatedTarget
类似,relatedTarget 应初始化为指针刚刚离开的元素边界对应的元素(对于 pointerover 或
pointerenter 事件),或指针正在进入其边界的元素(对于 pointerout 或 pointerleave)。对其他指针事件,该值默认为
null。注意,当某元素获得指针捕获时,该指针的后续所有事件都被认为发生在捕获元素边界之内。
对于 gotpointercapture
与 lostpointercapture
事件,除上表中定义的那些属性之外,其余所有属性都应与触发用户代理运行处理待定指针捕获步骤并触发 gotpointercapture
与 lostpointercapture 事件的那个 Pointer
Event 相同。
用户代理 MUST 在隐式释放指针捕获以及触发非 gotpointercapture
或 lostpointercapture 的指针事件时,运行以下步骤。
lostpointercapture 的指针事件。
gotpointercapture 的指针事件。
如click、
auxclick 与 contextmenu 事件一节所定义,即使 lostpointercapture
事件已经派发,若存在相应的 click、auxclick 或 contextmenu
事件,它仍会派发到捕获目标。
用户代理 MUST 在检测到网页不太可能继续接收具有特定 pointerId 的指针事件时,抑制指针事件流。以下任一场景满足该条件(也 MAY 存在其他场景):
touch-action CSS
属性一节。
用户代理 MAY 抑制指针事件流的其他场景包括:
检测这些场景的方法超出本规范范围。
pointercancel
事件。pointerout 事件。
pointerleave 事件。
相对于屏幕表面移动的指向设备,或其任一属性发生变化的指向设备,会按 指针事件类型中定义触发各类事件。对于静止的指向设备(既未相对屏幕表面移动,也未发生任何属性变化),若布局变化影响了该指针的
命中测试目标,则 用户代理 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] 规则对最终整数值进行舍入。
/* Converting between tiltX/tiltY and altitudeAngle/azimuthAngle */
function spherical2tilt(altitudeAngle, azimuthAngle) {
const radToDeg = 180/Math.PI;
let tiltXrad = 0;
let tiltYrad = 0;
if (altitudeAngle == 0) {
// the pen is in the X-Y plane
if (azimuthAngle == 0 || azimuthAngle == 2*Math.PI) {
// pen is on positive X axis
tiltXrad = Math.PI/2;
}
if (azimuthAngle == Math.PI/2) {
// pen is on positive Y axis
tiltYrad = Math.PI/2;
}
if (azimuthAngle == Math.PI) {
// pen is on negative X axis
tiltXrad = -Math.PI/2;
}
if (azimuthAngle == 3*Math.PI/2) {
// pen is on negative Y axis
tiltYrad = -Math.PI/2;
}
if (azimuthAngle>0 && azimuthAngle<Math.PI/2) {
tiltXrad = Math.PI/2;
tiltYrad = Math.PI/2;
}
if (azimuthAngle>Math.PI/2 && azimuthAngle<Math.PI) {
tiltXrad = -Math.PI/2;
tiltYrad = Math.PI/2;
}
if (azimuthAngle>Math.PI && azimuthAngle<3*Math.PI/2) {
tiltXrad = -Math.PI/2;
tiltYrad = -Math.PI/2;
}
if (azimuthAngle>3*Math.PI/2 && azimuthAngle<2*Math.PI) {
tiltXrad = Math.PI/2;
tiltYrad = -Math.PI/2;
}
}
if (altitudeAngle != 0) {
const tanAlt = Math.tan(altitudeAngle);
tiltXrad = Math.atan(Math.cos(azimuthAngle) / tanAlt);
tiltYrad = Math.atan(Math.sin(azimuthAngle) / tanAlt);
}
return {"tiltX":tiltXrad*radToDeg, "tiltY":tiltYrad*radToDeg};
}
function tilt2spherical(tiltX, tiltY) {
const tiltXrad = tiltX * Math.PI/180;
const tiltYrad = tiltY * Math.PI/180;
// calculate azimuth angle
let azimuthAngle = 0;
if (tiltX == 0) {
if (tiltY > 0) {
azimuthAngle = Math.PI/2;
}
else if (tiltY < 0) {
azimuthAngle = 3*Math.PI/2;
}
} else if (tiltY == 0) {
if (tiltX < 0) {
azimuthAngle = Math.PI;
}
} else if (Math.abs(tiltX) == 90 || Math.abs(tiltY) == 90) {
// not enough information to calculate azimuth
azimuthAngle = 0;
} else {
// Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
const tanX = Math.tan(tiltXrad);
const tanY = Math.tan(tiltYrad);
azimuthAngle = Math.atan2(tanY, tanX);
if (azimuthAngle < 0) {
azimuthAngle += 2*Math.PI;
}
}
// calculate altitude angle
let altitudeAngle = 0;
if (Math.abs(tiltX) == 90 || Math.abs(tiltY) == 90) {
altitudeAngle = 0
} else if (tiltX == 0) {
altitudeAngle = Math.PI/2 - Math.abs(tiltYrad);
} else if (tiltY == 0) {
altitudeAngle = Math.PI/2 - Math.abs(tiltXrad);
} else {
// Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
altitudeAngle = Math.atan(1.0/Math.sqrt(Math.pow(Math.tan(tiltXrad),2) + Math.pow(Math.tan(tiltYrad),2)));
}
return {"altitudeAngle":altitudeAngle, "azimuthAngle":azimuthAngle};
}
PointerEvent要使用 event、eventType、eventTarget、bubbles 与 cancelable 来 初始化一个 PointerEvent,请运行以下步骤:
PointerEvent 值。PointerEvent
要使用 eventType、eventTarget、bubbles 与 cancelable
来 创建一个
PointerEvent,请运行以下步骤:
PointerEvent
创建一个事件的结果
DOMStringMouseEventPointerEvent
创建一个事件的结果
targetMouseEvent 的属性从
mouseevent 复制到 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
事件的触发。
用户代理 MUST 当指针发生任何不会触发
pointerdown 或 pointerup 事件的属性变化时,触发一个指针事件,其名称为 pointermove。这包括坐标、压力、切向压力、倾斜、旋转、接触几何(width
与 height)或 组合按键 的任何变化。
用户代理 MAY 延迟派发 pointermove 事件(例如出于性能原因)。
合并事件信息将通过getCoalescedEvents
方法暴露给单个已派发的 pointermove 事件。
这类事件的最终坐标应当用于查找该事件的目标。
用户代理 MUST 触发一个指针事件,其名称为 pointerrawupdate,并且仅能在安全上下文中这样做;当指针发生任何不会触发
pointerdown 或 pointerup 事件的属性变化时触发。此类属性列表参见 pointermove 事件。
与 pointermove 不同,用户代理
SHOULD 尽快并尽可能频繁地派发 pointerrawupdate 事件,频率以 JavaScript
能处理这些事件为限。
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;
};
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。
WebIDLdictionary WheelEventInit : MouseEventInit {
double deltaX = 0.0;
double deltaY = 0.0;
double deltaZ = 0.0;
unsigned long deltaMode = 0;
};
deltaXdeltaZ 属性。deltaYdeltaZ 属性。deltaZdeltaZ 属性于该 WheelEvent
对象上。该属性的相对正值(以及
deltaX 与 deltaY 属性)由右手坐标系给出,其中 X、Y 与 Z
轴的正方向分别指向文档的最右边缘、最下边缘与最远深度(远离用户)。
相对负值则分别指向相反方向。
deltaMode
deltaMode 属性初始化为枚举值 0、
1 或 2,这些值
分别表示滚动的像素量
(DOM_DELTA_PIXEL)、滚动的行数
(DOM_DELTA_LINE)或滚动的页数
(DOM_DELTA_PAGE),如果该滚轮的旋转本会导致滚动。
| Type | wheel |
|---|---|
| Interface | WheelEvent |
| Sync / Async | 异步 |
| Bubbles | 是 |
| Trusted Targets | Element |
| Cancelable | 视情况而定 |
| Composed | 是 |
| Default action | 滚动(或缩放)文档 |
| Context (trusted events) |
|
wheel 事件(具有多个非零轴)交付,或以每个非零轴各自一个的独立
wheel 事件交付。
wheel 事件类型的典型默认动作是
按所指示的量滚动(或在某些情况下缩放)文档。
如果该事件被取消,实现 MUST NOT
滚动或缩放文档(或执行与该事件类型相关联的任何其他
实现特定的默认动作)。
在滚轮事件上调用 preventDefault 可以阻止
或以其他方式中断滚动。为获得最佳滚动性能,用户代理可能不会等待与滚动相关联的每个滚轮事件
都被处理后再判断其是否会被取消。
在这种情况下,用户代理应生成
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()
之后,即使该元素尚未收到 gotpointercapture 事件,该方法也会立即返回
true。因此,它对在 隐式指针捕获(从 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 属性看似只指触摸输入,
但它实际上适用于所有允许为平移与缩放进行直接操控的指针输入形式。| Name: | touch-action |
|---|---|
| Value: | auto | none | [ [ pan-x | pan-left |
pan-right ] || [ pan-y | pan-up |
pan-down ] ] | manipulation
|
| Initial: | auto |
| Applies to: | 除以下之外的所有元素:非替换的内联元素、表格行、行组、表格列 与列组 |
| Inherited: | 否 |
| Percentages: | N/A |
| Media: | visual |
| Computed value: | 与指定值相同 |
| Canonical order: | 按语法 |
| Animation type: | 不可动画 |
touch-action CSS 属性用于确定直接
操控交互(尽管属性名如此,它并不局限于触摸)是否 MAY 触发用户代理的平移与缩放行为。参见
touch-action 值章节。
在开始平移或缩放之前,用户代理 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 属性都符合,则该缩放交互是受支持的。
touch-action 值的任何更改都将被忽略。
例如,在 pointerdown 处理脚本中将某元素的
touch-action 值从
auto 改为 none,
并不会导致用户代理在该指针处于活动状态的期间中止或抑制该输入的任何平移或缩放行为。
touch-action 的 pan-* 值,
一旦用户代理在手势开始时已确定是否直接处理该手势,则同一手势方向的后续变化 SHOULD
在该指针处于活动状态期间被用户代理忽略。
例如,如果某元素被设置为 touch-action: pan-y(意味着仅由用户代理处理垂直平移),
且某触摸手势最初是水平开始的,那么如果用户在手指仍接触屏幕时将手势方向改为垂直,也不应发生任何垂直平移。touch-action 值的方法不在本规范范围内。touch-action 属性涵盖与视口平移与缩放相关的直接操控行为。
任何额外的用户代理行为,例如文本选择/高亮,或激活链接与表单控件,MUST NOT 受到该 CSS 属性的影响。
auto 或 none 值对应行为的方法,均不在本规范范围内。pan-x 或 pan-y)时,在平移期间不能更改轴向。touch-action 值定义于 [COMPAT]。方向特定的 pan 值可用于自定义某些回弹滚动(overscroll)行为。
例如,为实现简单的下拉刷新效果,当滚动位置为 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"> 控件)。可以在滑块的滑块柄(thumb)
元素上设置指针捕获,使用户即使指针滑出滑块柄
之外也能来回滑动该控件。
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 事件
在捕获节点被移除之后的下一次 处理待定指针捕获期间
在 document 上触发。
当某个元素成功应用了指针锁定 [PointerLock] 时,如果任何元素被设置为已捕获或待捕获,
用户代理 MUST 执行步骤,仿佛已调用了 releasePointerCapture 方法。
出于性能原因,用户代理可能选择不在每次指针的某个可测量属性
(例如坐标、压力、切向压力、倾斜、旋转或接触几何)
更新时都发送一个 pointermove
事件。相反,它们可能将多次变化合并(combine/merge)为
单个 pointermove 或 pointerrawupdate 事件。虽然
这种方式有助于减少 用户代理 MUST
执行的事件处理量,
但它自然会降低跟踪指针位置时的粒度与保真度,
特别是在快速且幅度很大的移动情况下。通过使用
getCoalescedEvents 方法,
应用可以访问原始的、未被合并的位置变化。这些
使得对指针移动数据的处理更精确。例如在绘图
应用中,未合并事件可用于绘制更平滑的曲线,
更接近指针的实际移动。
pointermove 事件中的合并
坐标(灰点)时,曲线明显更
棱角分明且锯齿状;使用 getCoalescedEvents()
提供的更细粒度点(红圈)绘制的同一条线,会得到对指针移动更平滑的近似。PointerEvent 具有一个关联的 合并事件列表(一个包含零个或多个
PointerEvent 的列表)。对于可信(trusted)的 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 值递增)
以及用户代理派发的事件:
| 实际事件 | 已派发事件 |
|---|---|
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2)含 1 个
合并事件 |
指针(pointerId=1)
坐标变化 |
pointerrawupdate(pointerId=1)含 1 个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2)含 1 个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2)含 1 个
合并事件 |
指针(pointerId=1)
坐标变化 |
pointerrawupdate(pointerId=1)含 1 个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2)含 1 个
合并事件 |
指针(pointerId=1)按钮按下
|
pointermove
(pointerId=1)含 2 个
合并事件pointermove
(pointerId=2)含 4 个
合并事件pointerdown
(pointerId=1)含 0 个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2)含 1 个
合并事件 |
指针(pointerId=2)
坐标变化 |
pointerrawupdate(pointerId=2)含 1 个
合并事件 |
指针(pointerId=1)按钮释放
|
pointermove
(pointerId=2)含 2 个
合并事件pointerup(pointerId=1)含 0 个
合并事件 |
一些用户代理内建算法会在一系列已确认的指针移动之后,
根据当前手势的先前事件以及移动的速度/轨迹,对未来指针移动的位置进行预测。
应用可使用 getPredictedEvents 方法
利用该信息,以推测方式向预测位置“提前绘制”,从而降低感知到的延迟,
并在收到实际点位后丢弃这些预测点位。
pointermove 事件中的合并坐标,并展示用户
代理预测的未来点(灰色圆圈)。PointerEvent 具有一个关联的 预测事件列表(一个包含零个或多个
PointerEvent 的列表)。对于可信 pointermove 事件,它是一系列用户代理预测将在未来跟随该事件发生的
PointerEvent。对于所有其他可信事件类型,该列表为空列表。
不可信事件的预测事件列表会被初始化为传给构造函数的值。
列表中的事件数量以及它们与当前时间戳之间的距离由 用户代理及其使用的预测算法决定。
可信事件的预测事件列表中的事件将具有:
timeStamp 值
[DOM] —— 所有预测事件的
timeStamp 都大于或等于调用了
getPredictedEvents
方法的已派发指针事件的
timeStamp。
预测事件列表 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)特性。 为了与现有遗留内容获得最佳兼容性,鼓励用户代理支持该特性。
从高层次来看,兼容鼠标事件旨在与其各自的 指针事件进行“交错(interleaved)”派发。然而,这一特定顺序并非强制要求, 实现兼容鼠标事件的用户代理 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
其中任意一个未设置的值视为窗口外的鼠标位置。
传统鼠标指针的有效位置建模了这样一个事实:我们并不总能将指针过渡事件(pointerover、pointerout、
pointerenter 与 pointerleave)直接映射到对应的传统鼠标过渡事件(mouseover、
mouseout、mouseenter 与 mouseleave)。
以下动画展示了一个案例:为了能够使用单一传统鼠标输入来协调两个主指针,用户代理需要派发比指针过渡事件更多的传统鼠标过渡事件。
在该动画中,请注意鼠标点击与触摸轻触之间的时间段。按钮 1
没有收到 pointerout 事件(因为“真实”的鼠标指针在此期间并未离开按钮矩形),
但当触摸轻触导致传统鼠标指针的有效位置移动到按钮 2 时,
按钮 1 会收到一个 mouseout 事件。类似地,在触摸轻触与鼠标离开按钮 1 之前的那段时间里,
按钮 1 出于同样原因没有收到 pointerover 事件,
但当传统鼠标指针的有效位置移回按钮 1 内部时,
按钮 1 会收到一个 mouseover 事件。
每当用户代理要为支持悬停的设备派发指针事件时,它 SHOULD 执行以下步骤:
isPrimary 属性为 false,
则派发该指针事件并终止这些步骤。pointerdown、pointerup 或 pointermove 事件,
或在 window 上的 pointerleave 事件,
则按 跟踪传统鼠标指针的有效位置
中所述派发兼容鼠标过渡事件。pointerdown,并且该事件的 canceled flag 被设置,则为该
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,并且该事件的 canceled flag 被设置,则为该
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] 中定义的)与指针事件,则 用户 代理 MUST NOT 同时生成本节所述的兼容鼠标事件,以及 [TOUCH-EVENTS] 中概述的 回退鼠标事件。
使用一个不支持悬停的主指针(例如触摸屏上的单指)激活某元素(click)通常会产生如下事件序列:
mousemovepointeroverpointerentermouseovermouseenterpointerdownmousedownpointermove 与
mousemove 事件,取决于指针的移动
pointerupmouseuppointeroutpointerleavemouseoutmouseleaveclick然而,如果在该交互期间 pointerdown 事件的 canceled flag
被设置,则事件序列将为:
mousemovepointeroverpointerentermouseovermouseenterpointerdownpointermove
事件,取决于指针的移动pointeruppointeroutpointerleavemouseoutmouseleaveclick本附录讨论指针事件(Pointer Events)实现的安全与隐私注意事项。讨论仅限于 由本规范所定义的事件模型、API 与事件的实现直接引发的安全与隐私问题。
本规范中定义的许多事件类型会因用户操作而被派发。这使得恶意的事件监听器能够获取 用户通常认为是机密的信息,例如:用户在与页面交互时,其鼠标/触控笔/手指的精确路径/移动轨迹。
指针事件包含额外信息(在用户设备支持的情况下),例如笔输入的持笔角度或倾斜角, 接触面的几何形状,以及施加在触控笔或触摸屏上的压力。角度、倾斜、几何形状与压力信息 直接与用户设备上的传感器相关,这意味着本规范允许某个源(origin)访问这些传感器。
这些传感器数据,以及用于确定所使用输入机制类型(鼠标、触摸、笔)的能力, 可能被用于推断用户的特征,或用户设备与环境的特征。这些被推断的特征以及任何设备/环境信息 本身也可能是敏感的——例如,它们可能让恶意网站进一步推断用户是否在使用辅助技术。 这些信息也可能被用于构建用户画像和/或尝试对特定用户进行“指纹识别(fingerprint)”并跟踪。
作为缓解措施,用户代理可以考虑提供能力,使用户能够禁用对特定 传感器数据(例如角度、倾斜、压力)的访问,和/或仅在用户明确选择加入(opt-in)后才提供这些数据。
本规范定义了作者可以访问“预测事件(predicted events)”的方法。本规范本身 并未定义用户代理应使用的预测算法。规范作者设想这些算法仅依赖于与用户正在执行的当前手势相关的先前指针事件。 用户代理有责任确保其预测算法的具体实现不会依赖任何额外数据——例如用户跨不同站点的完整交互历史—— 因为这些数据可能泄露用户的敏感信息,或被用于对其进行“指纹识别”并跟踪。
除上述注意事项之外,工作组认为本规范:
本节为非规范性内容。
buttons 属性具有非零值时的状态。对于鼠标,这是指设备至少有一个按钮处于按下状态。
对于触摸,这是指与数字化仪发生物理接触。对于笔,这是指笔与数字化仪发生物理接触,或在悬停时至少有一个按钮处于按下状态。pointerId 标识)
仍可能在该文档内产生额外事件,则该指针仍被视为活动。示例:
WheelEvent 接口的输入设备(例如鼠标滚轮或触控板)的物理移动,
而对页面执行滚动或缩放的估计量(以像素、行或页为单位)。
delta 的值(例如
deltaX、deltaY 或 deltaZ 属性)应当在当前 deltaMode 属性的语境中解释。
滚轮(或其他设备)的物理移动与 delta 为正或为负之间的关系取决于环境与设备。
然而,如果用户代理将滚动作为 默认动作,
则 delta
的符号由右手坐标系给出,
其中正的 X、Y 与 Z 轴分别指向 文档
的最右边缘、最下边缘与最远的深度(远离用户)。
可测量属性表示与连续指针传感器数据相关的值,这些值使用实数或来自大范围域的整数来表示。
对于指针事件,width、height、
pressure、
tangentialPressure、tiltX、tiltY、twist、
altitudeAngle、azimuthAngle,以及 [UIEVENTS] 鼠标事件模型属性
screenX、screenY、clientX、clientY 都属于可测量属性。
相对地,pointerId、pointerType、
isPrimary,以及 [UIEVENTS] 鼠标事件模型属性 button、
buttons、ctrlKey、
shiftKey、altKey 与 metaKey 不被视为可测量属性,
因为它们与传感器数据无关。
WheelEvent 接口的输入设备上的增量变化指示。
在某些设备上,这 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;
};
dictionary WheelEventInit : MouseEventInit {
double deltaX = 0.0;
double deltaY = 0.0;
double deltaZ = 0.0;
unsigned long deltaMode = 0;
};
partial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
partial interface mixin GlobalEventHandlers {
attribute EventHandler onpointerover;
attribute EventHandler onpointerenter;
attribute EventHandler onpointerdown;
attribute EventHandler onpointermove;
[SecureContext] attribute EventHandler onpointerrawupdate;
attribute EventHandler onpointerup;
attribute EventHandler onpointercancel;
attribute EventHandler onpointerout;
attribute EventHandler onpointerleave;
attribute EventHandler ongotpointercapture;
attribute EventHandler onlostpointercapture;
};
partial interface Navigator {
readonly attribute long maxTouchPoints;
};
partial interface MouseEvent {
// Deprecated in this specification
undefined initMouseEvent(DOMString typeArg,
optional boolean bubblesArg = false,
optional boolean cancelableArg = false,
optional Window? viewArg = null,
optional long detailArg = 0,
optional long screenXArg = 0,
optional long screenYArg = 0,
optional long clientXArg = 0,
optional long clientYArg = 0,
optional boolean ctrlKeyArg = false,
optional boolean altKeyArg = false,
optional boolean shiftKeyArg = false,
optional boolean metaKeyArg = false,
optional short buttonArg = 0,
optional EventTarget? relatedTargetArg = null);
};
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: