Copyright © 2024 the Contributors to the Touch Events - Level 2 Specification, published by the Touch Events Community Group under the W3C Community Final Specification Agreement (FSA). A human-readable summary is available.
此规范由 触摸事件社区组发布。它不是W3C标准,也不属于W3C标准轨道。 请注意,根据 W3C社区最终规范协议 (FSA),其他条件适用。 了解更多关于 W3C社区和业务组的信息。
此规范由 触摸事件社区组 发布。它不是 W3C 标准,也不在 W3C 标准轨道上。
请注意,根据 W3C 社区最终规范协议 (FSA),适用其他条件。
触摸事件规范定义了一组低级事件,这些事件表示与触敏表面上的一个或多个接触点,以及这些接触点相对于表面和任何显示在其上的DOM元素(例如触摸屏)或与其相关的元素(例如没有显示器的绘图板)之间的变化。该规范还涉及诸如绘图板等的笔式平板设备,并考虑到触控笔的功能。
本节非规范性。
运行在提供触摸输入终端上的用户代理,通常使用解释后的鼠标事件来允许用户访问交互式网络应用程序。然而,由于这些解释后的事件是基于物理触摸输入的规范化数据,它们在传递预期的用户体验方面往往存在局限性。此外,由于鼠标事件的限制:系统级别的限制和遗留兼容性问题,无法处理并发输入,不论设备能力如何。
同时,原生应用程序可以通过提供的系统API处理这两种情况。
触摸事件规范通过指定接口提供了解决方案,允许网络应用程序直接处理触摸事件,以及处理具有多点触控功能的设备。
除了标记为非规范性的章节,本规范中的所有创作指南、图表、示例和注释均为非规范性。规范中的其他内容均为规范性。
本文档中的关键词 必须 应按 BCP 14 [RFC2119] [RFC8174] 的说明进行解释,且仅当它们以全部大写形式出现时,如此处所示。
本规范定义了适用于单个产品的合规标准:实现本规范中接口的用户代理。
WindowProxy 在 [HTML5] 中定义。
本规范中的IDL块是符合WebIDL规范的IDL片段 [WEBIDL]。
符合规范的用户代理还必须是本规范中IDL片段的符合规范的JavaScript实现,但有以下例外:
注意: 两种反映IDL属性的方式都允许直接在平台对象上获取和设置属性。例如,给定一个 Touch
对象 aTouch
,计算
aTouch.target
会返回 Touch
对象的
EventTarget
。如果用户代理将IDL属性实现为访问器属性,则属性访问会调用getter并返回
EventTarget
。如果用户代理将IDL属性实现为具有与访问器属性相同行为的平台对象上的数据属性,则该对象将表现为拥有一个名为 target
的自身属性,其值为 EventTarget
对象,并且属性访问将返回此值。
该接口描述了触摸事件的单个 触摸点。Touch
对象是不可变的;一旦创建,它的属性不得更改。
WebIDLenum TouchType
{
"direct
",
"stylus
"
};
dictionary TouchInit
{
required long identifier
;
required EventTarget target
;
double clientX
= 0;
double clientY
= 0;
double screenX
= 0;
double screenY
= 0;
double pageX
= 0;
double pageY
= 0;
float radiusX
= 0;
float radiusY
= 0;
float rotationAngle
= 0;
float force
= 0;
double altitudeAngle
= 0;
double azimuthAngle
= 0;
TouchType
touchType
= "direct";
};
[Exposed=Window]
interface Touch
{
constructor
(TouchInit
touchInitDict);
readonly attribute long identifier
;
readonly attribute EventTarget target
;
readonly attribute double screenX
;
readonly attribute double screenY
;
readonly attribute double clientX
;
readonly attribute double clientY
;
readonly attribute double pageX
;
readonly attribute double pageY
;
readonly attribute float radiusX
;
readonly attribute float radiusY
;
readonly attribute float rotationAngle
;
readonly attribute float force
;
readonly attribute float altitudeAngle
;
readonly attribute float azimuthAngle
;
readonly attribute TouchType
touchType
;
};
identifier
每个 触摸点 的识别号。
当触摸点变为活动状态时,必须为其分配一个 identifier
,它与任何其他
活动触摸点 不同。在触摸点保持活动状态期间,所有引用它的事件都必须为其分配相同的 identifier
。
target
在触摸点首次放置在表面上时,EventTarget
是触摸点开始的对象,即使触摸点已移动到该元素的交互区域之外。
某些实现会修改目标元素,以纠正粗略输入的不准确性。因此,目标元素不一定是事件坐标直接对应的元素。用于针对粗略输入的目标/去除模糊的技术超出了本规范的范围。
screenX
相对于屏幕的水平坐标,以像素为单位
screenY
相对于屏幕的垂直坐标,以像素为单位
clientX
相对于视口的水平坐标,不包括任何滚动偏移,以像素为单位
clientY
相对于视口的垂直坐标,不包括任何滚动偏移,以像素为单位
pageX
相对于视口的水平坐标,包括任何滚动偏移,以像素为单位
pageY
相对于视口的垂直坐标,包括任何滚动偏移,以像素为单位
radiusX
沿着由 rotationAngle 指示的轴的触摸区域(例如手指、触控笔)所围绕的椭圆的半径,以CSS像素为单位(如 [CSS-VALUES]
中定义),与 screenX 的比例相同;如果未知值则为 0
。该值不能为负。
radiusY
沿垂直于由 rotationAngle 指示的轴的触摸区域(例如手指、触控笔)所围绕的椭圆的半径,以CSS像素为单位(如 [CSS-VALUES]
中定义),与 screenY 的比例相同;如果未知值则为 0
。该值不能为负。
rotationAngle
椭圆(由 radiusX 和 radiusY 描述)绕其中心顺时针旋转的角度(以度为单位);如果未知值则为 0
。该值必须大于或等于 0
且小于
90
。
如果椭圆(由 radiusX 和 radiusY 描述)是圆形的,则 rotationAngle 无效。在这种情况下,用户代理可以使用 0
作为值,或者使用允许范围内的任何其他值。(例如,用户代理可以使用前一个触摸事件的 rotationAngle 值,以避免突然的变化。)
force
施加压力的相对值,范围为 0
到 1
,其中 0
表示无压力,1
表示触摸设备能够感知的最大压力;如果未知值则为 0
。在知道压力的环境中,由 force 属性表示的绝对压力以及压力的灵敏度级别可能会有所不同。
altitudeAngle
传感器(例如触控笔/笔)的仰角(以弧度为单位),范围为 [0,π/2]——其中0表示与表面平行(X-Y平面),π/2表示垂直于表面。对于不报告倾斜或角度的硬件和平台,值 必须 为0。
altitudeAngle
在此处定义的默认值为 0。这与 指针事件 -
第3级 [POINTEREVENTS] 规范中 altitudeAngle
属性的定义不同,后者的默认值为 π/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点钟”)。
touchType
触发触摸的设备类型。
TouchType
枚举表示不同类型的可能触摸输入。
direct
来自屏幕上的手指的直接触摸。
stylus
来自触控笔或笔设备的触摸。
该接口定义了触摸事件中多个单个接触点的列表。TouchList
对象是不可变的;一旦创建,其内容不得更改。
TouchList
对象的 支持的属性索引 ([WEBIDL]) 为从0到比列表长度少一的数字。
WebIDL[Exposed=Window]
interface TouchList
{
readonly attribute unsigned long length
;
getter Touch
? item
(unsigned long index);
};
该接口定义了
、touchstart
、touchend
和 touchmove
事件类型。touchcancel
TouchEvent
对象是不可变的;一旦创建并初始化,其属性不得更改。TouchEvent
继承自 [DOM-LEVEL-3-EVENTS] 中定义的
UIEvent
接口。
TouchEventInit
字典用于 TouchEvent
接口的构造函数,提供一种机制来构造不受信任的(合成的)触摸事件。它继承自 [DOM-LEVEL-3-EVENTS] 中定义的
EventModifierInit
字典。事件的构造步骤在 [DOM4] 中定义。参见 示例,了解如何触发不受信任的触摸事件的示例代码。
WebIDLdictionary TouchEventInit
: EventModifierInit {
sequence<Touch
> touches
= [];
sequence<Touch
> targetTouches
= [];
sequence<Touch
> changedTouches
= [];
};
[Exposed=Window]
interface TouchEvent
: UIEvent {
constructor
(DOMString type, optional TouchEventInit
eventInitDict = {});
readonly attribute TouchList
touches
;
readonly attribute TouchList
targetTouches
;
readonly attribute TouchList
changedTouches
;
readonly attribute boolean altKey
;
readonly attribute boolean metaKey
;
readonly attribute boolean ctrlKey
;
readonly attribute boolean shiftKey
;
getter boolean getModifierState
(DOMString keyArg);
};
touches
当前触摸表面上每个接触点的 Touch
对象列表。
targetTouches
当前接触表面并且从当前事件目标元素开始的每个接触点的 Touch
对象列表。
changedTouches
为事件做出贡献的每个接触点的 Touch
对象列表。
对于
事件,该列表必须包含刚刚变为活动状态的触摸点。对于
touchstart
事件,该列表必须包含自上次事件以来移动过的触摸点。对于
touchmove
和 touchend
事件,该列表必须包含刚刚从表面上移除的触摸点,以及它们在被移除之前的最后已知坐标。
touchcancel
altKey
如果激活了 alt(备用)键修饰符,则为 true
;否则为 false
metaKey
如果激活了 meta(Meta)键修饰符,则为 true
;否则为 false
。在某些平台上,此属性可能映射到一个不同名称的键修饰符。
ctrlKey
如果激活了 ctrl(Control)键修饰符,则为 true
;否则为 false
shiftKey
如果激活了 shift(Shift)键修饰符,则为 true
;否则为 false
getModifierState
(keyArg)使用键值查询修饰符的状态。如果它是修饰符键并且该修饰符已激活,则返回 true
,否则返回 false
。
本节为非规范性内容。
用户代理应确保从给定的 Touch
对象获得的所有信息与派发到同一文档的 TouchEvent
相关联。为了实现这一点,用户代理应维护当前
触摸活动 文档的概念。在首次触摸时,它被设置为触摸创建的目标文档。当所有活动触摸点释放后,触摸活动 文档被清除。所有 TouchEvent
都被派发到当前的 触摸活动
文档中,并且它包含的每个 Touch
对象仅引用该文档中的 DOM 元素(及坐标)。如果触摸完全在当前的
触摸活动 文档之外开始,则完全忽略它。
本节为非规范性内容。
以下示例展示了 TouchList
成员与 TouchEvent
的关系。
touches
和 targetTouches
在 TouchEvent
中此示例演示了 touches
和 targetTouches
成员在 TouchEvent
接口中的实用性及其关系。根据触摸元素和文档上的触摸点数,以下代码将生成不同的输出:
<div id="touchable">此元素是可触摸的。</div>
<script>
document.getElementById('touchable').addEventListener('touchstart', function(ev) {
if (ev.touches.item(0) == ev.targetTouches.item(0))
{
/**
* 如果表面上的第一个触摸点也定位在
* "touchable" 元素上,则下面的代码应该执行。
* 由于 targetTouches 是覆盖整个表面的 touches 的子集,
* TouchEvent.touches >= TouchEvents.targetTouches
* 始终为真。
*/
document.write('Hello Touch Events!');
}
if (ev.touches.length == ev.targetTouches.length)
{
/**
* 如果所有活动的触摸点都在 "touchable" 元素上,
* 则长度属性应该相同。
*/
document.write('所有触摸点都在目标元素上')
}
if (ev.touches.length > 1)
{
/**
* 在单触摸输入设备上,表面上只能有一个触摸点,
* 因此以下代码只能在支持多点触摸的设备上执行。
*/
document.write('你好,多点触摸!');
}
}, false);
</script>
changedTouches
在 TouchEvent
中的使用此示例演示了 changedTouches
的实用性及其与 TouchList
成员在 TouchEvent
接口中的关系。以下代码示例将在从定义的可触摸元素上移除触摸点时触发:
<div id="touchable">此元素是可触摸的。</div>
<script>
document.getElementById('touchable').addEventListener('touchend', function(ev) {
/**
* 当表面上有三个触摸点时的示例输出,
* 其中两个在 "touchable" 元素上,
* 并且一个点从 "touchable" 元素上被移除:
*
* 移除的触摸点:1
* 元素上剩余的触摸点:1
* 文档上剩余的触摸点:2
*/
document.write('移除的触摸点:' + ev.changedTouches.length);
document.write('元素上剩余的触摸点:' + ev.targetTouches.length);
document.write('文档上剩余的触摸点:' + ev.touches.length);
}, false);
</script>
TouchEvent
此示例演示了如何通过脚本创建并触发 TouchEvent
。
if (Touch.length < 1 || TouchEvent.length < 1)
throw "TouchEvent 构造函数不支持";
var touch = new Touch({
identifier: 42,
target: document.body,
clientX: 200,
clientY: 200,
screenX: 300,
screenY: 300,
pageX: 200,
pageY: 200,
radiusX: 5,
radiusY: 5
});
var touchEvent = new TouchEvent("touchstart", {
cancelable: true,
bubbles: true,
composed: true,
touches: [touch],
targetTouches: [touch],
changedTouches: [touch]
});
document.body.dispatchEvent(touchEvent);
TouchEvent
类型列表本节为非规范性内容。
下表总结了本规范中定义的 TouchEvent
事件类型。所有事件都应完成冒泡阶段。所有事件都应为合成的 [WHATWG-DOM] 事件。
事件类型 | 同步 / 异步 | 冒泡阶段 | 合成 | 可信的近端事件目标类型 | 接口 | 可取消 | 默认操作 |
---|---|---|---|---|---|---|---|
|
同步 | 是 | 是 | Document , Element |
TouchEvent
|
视情况而定 | 未定义 |
|
同步 | 是 | 是 | Document , Element |
TouchEvent
|
视情况而定 | 视情况而定:用户代理可能会派发 鼠标和点击事件 |
|
同步 | 是 | 是 | Document , Element |
TouchEvent
|
视情况而定 | 未定义 |
|
同步 | 是 | 是 | Document , Element |
TouchEvent
|
否 | 无 |
取消触摸事件可以阻止或中断滚动(这可能与脚本执行并行进行)。为了获得最大的滚动性能,用户代理可能不会等待处理与滚动相关的每个触摸事件来判断是否会被取消。在这种情况下,用户代理应生成其cancelable
属性为false
的触摸事件,表示无法使用preventDefault
来阻止或中断滚动。否则,cancelable
属性将为true
。
特别是,当用户代理观察到事件没有非被动监听器时,应该只生成不可取消的触摸事件。
用户代理必须调度此事件类型以指示用户何时在触摸屏上放置一个 触摸点。
此事件的目标必须是一个 Element
。如果触摸点在一个框架内,则应将事件分派给该框架的子浏览上下文中的元素。
用户代理必须调度此事件类型以指示用户何时将 触摸点从触摸表面移除,包括触摸点物理上离开触摸表面的情况,例如被拖出屏幕。
此事件的目标必须是与触摸点首次放置在触摸表面时的Element
相同,即使触摸点已移动到目标元素的交互区域之外。
被移除的触摸点必须包含在changedTouches
属性中,且不能包含在touches
和targetTouches
属性中。
用户代理必须调度此事件类型以指示用户何时沿着触摸表面移动一个触摸点。
此事件的目标必须是与触摸点首次放置在表面时的Element
相同,即使触摸点已移动到目标元素的交互区域之外。
请注意,用户代理发送
事件的频率是实现定义的,可能取决于硬件能力和其他实现细节。
touchmove
用户代理应抑制由
事件引发的默认操作,直到与同一活动触摸点相关的至少一个 touchmove
事件没有被取消。对于同一个活动触摸点,是否在至少一个 touchmove
事件没有被取消后抑制默认操作,取决于实现。touchmove
用户代理必须调度此事件类型以指示触摸点由于实现特定的方式被中断,例如同步事件或用户代理发起的操作取消了触摸,或者触摸点离开了文档窗口,进入了能够处理用户交互的非文档区域(例如用户代理的本地用户界面,或由插件管理的文档区域)。当用户在触摸表面上放置的触摸点超过了设备或实现配置的存储数量时,用户代理也可以调度此事件类型,在这种情况下,应该移除Touch
列表中的最早对象。
此事件的目标必须是与触摸点首次放置在表面时的Element
相同,即使触摸点已移动到目标元素的交互区域之外。
被移除的触摸点必须包含在changedTouches
属性中,且不能包含在touches
和targetTouches
属性中。
以下部分描述了[WHATWG-DOM]中定义的重定向步骤。
Touch
对象有一个关联的未调整目标(null或EventTarget
)。除非另有说明,默认为null。
在给定touchEvent的情况下,TouchEvent
的重定向步骤必须执行以下步骤:
用户代理有一个关联的布尔值暴露旧的触摸事件 API,其值为实现定义。
现有的网页内容通常将这些API的存在视为用户代理是启用触摸功能的“移动”设备的信号,因此即使在非移动设备上启用了触摸功能,暴露这些API也可能导致此类网页内容的用户体验不佳。
以下部分描述了[HTML5]中定义的现有GlobalEventHandlers
混入的扩展,以便于事件处理程序的注册。对于暴露旧的触摸事件 API为false的用户代理,不得实现此混入。
WebIDLpartial interface mixin GlobalEventHandlers
{
attribute EventHandler ontouchstart
;
attribute EventHandler ontouchend
;
attribute EventHandler ontouchmove
;
attribute EventHandler ontouchcancel
;
}
用户代理可以同时分派触摸事件和鼠标事件(为兼容非触摸设计的网页内容)[DOM-LEVEL-2-EVENTS],以响应同一个用户输入。如果用户代理在单个用户操作响应中同时分派了触摸事件和鼠标事件,那么在任何鼠标事件类型之前,必须首先分派
事件类型。如果touchstart
、touchstart
或touchmove
被取消,用户代理不应分派与阻止的触摸事件相应的任何鼠标事件。touchend
如果Web应用程序能够处理触摸事件,它可以取消这些事件,用户代理将不再需要分派相应的鼠标事件。如果Web应用程序没有专门为触摸输入设备编写,它将响应后续的鼠标事件。
用户代理通常仅为单指激活手势(如点击和长按)分派鼠标和点击事件。涉及触点移动或多指交互(如两个或更多活跃触点)的手势通常只会生成触摸事件。
如果用户代理将一系列触摸事件解释为点击手势,则应按照mousemove
、mousedown
、mouseup
和click
的顺序在对应的
事件位置处分派这些事件。如果文档内容在处理触摸事件期间发生了变化,则用户代理可能会将鼠标事件分派到与触摸事件不同的目标。
touchend
任何进一步的触摸和鼠标事件的默认行为和顺序是实现定义的,除非在其他地方另有规定。
激活一个元素(例如,在某些实现中,点击)通常会产生以下事件顺序(尽管根据具体的用户代理行为可能会略有不同):
touchstart
touchmove
事件touchend
mousemove
(为兼容旧的鼠标特定代码)mousedown
mouseup
click
但是,如果在此交互过程中,touchstart
、touchmove
或touchend
事件被取消,则不会触发鼠标或点击事件,事件顺序将简单为:
touchstart
touchmove
事件touchend
即使用户代理支持触摸事件,这并不一定意味着触摸屏是用户唯一可用的输入机制。尤其是在触摸屏笔记本电脑或传统的“仅触摸”设备(如手机和平板电脑)配有外部输入设备时,用户可能会结合使用触摸屏、触控板、鼠标或键盘。因此,开发者应避免使用“触摸或鼠标/键盘”条件代码来绑定事件监听器,因为这会导致网站/应用程序仅支持触摸输入,阻止用户使用任何其他输入机制。
// 条件的“触摸或鼠标/键盘”事件绑定
// 不要这样做,因为这会使交互仅限于触摸
// 在同时具有触摸和鼠标/键盘的设备上
if ('ontouchstart' in window) {
// 设置触摸事件监听器
target.addEventListener('touchend', ...);
...
} else {
// 设置鼠标/键盘事件监听器
target.addEventListener('click', ...);
...
}
相反,开发者应该同时处理不同形式的输入。
// 同时绑定“触摸和鼠标/键盘”事件
// 设置触摸事件监听器
target.addEventListener('touchend', function(e) {
// 阻止兼容的鼠标事件和点击
e.preventDefault();
...
});
...
// 设置鼠标/键盘事件监听器
target.addEventListener('click', ...);
...
为了避免针对同一次触摸处理两次交互(一次是触摸事件,一次是兼容的鼠标事件),开发者应确保取消触摸事件,阻止生成进一步的鼠标或点击事件。或者,请参阅InputDeviceCapabilities API以检测由触摸事件生成的鼠标事件。
touchstart
事件来指示它的出现时,触点变为活跃。当用户代理分派touchend
或touchcancel
事件来指示触点从表面移除或不再跟踪时,它不再活跃。
preventDefault()
、在事件处理程序中返回false
,或其他由[DOM-LEVEL-3-EVENTS]和[HTML5]定义的手段阻止的事件。
本节为非规范性内容。
特别感谢WebKit工程师为该规范开发的模型,Neil Roberts (SitePen) 对WebKit触摸事件的总结,Peter-Paul Koch (PPK) 的文章和建议,Robin Berjon 开发的ReSpec.js规范撰写工具,以及WebEvents WG的诸多贡献。
随着规范的进展,许多人提出了更多的评论,导致了持续的改进。其中包括Matthew Schinckel、Andrew Grieve、Cathy Chan、Boris Zbarsky、Patrick H. Lauke 和 Simon Pieters。如果我们不慎遗漏了您的名字,请告诉我们。
该小组感谢以下对本规范测试套件作出贡献的人员:Matt Brubeck、Olli Pettay、Art Barstow、Cathy Chan 和 Rick Byers。
本节为非规范性内容。
以下是自2013年10月10日建议发布以来的主要更改摘要。完整提交历史也可用。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: