使用 TouchEvent 监听器构建双指捏合检测的开发者,会发布在安卓手机上完美运行但在 Windows 笔记本上无任何反应的代码。原因是架构上的,而非浏览器错误:桌面触控板根本不会触发 TouchEvent。了解每种输入设备实际产生的事件及其原因,是编写跨设备类别手势代码的前提。
PointerEvent 和 TouchEvent 是什么
TouchEvent 是两个 API 中较早的一个。它为移动触摸屏上的手指输入设计,事件中传递活动接触点列表(touches、targetTouches、changedTouches),事件名称为 touchstart、touchmove、touchend 和 touchcancel。列表中的每个条目都是带有坐标和标识符的 Touch 对象。该 API 专为触摸屏设计,因此没有鼠标、手写笔或触控板的概念。
PointerEvent 是 W3C 统一的替代方案,首次在 Internet Explorer 11 中推出,现在已被所有主流浏览器支持。它通过一组事件——pointerdown、pointermove、pointerup、pointercancel——统一处理鼠标、手写笔和触摸,并在每个事件上暴露 pointerType 属性,标明来源:"mouse"、"pen" 或 "touch"。详见 MDN Pointer Events 文档;W3C 规范维护于 w3c.github.io/pointerevents。
桌面触控板实际触发的事件
这部分让大多数开发者感到意外:桌面操作系统上的笔记本触控板不会触发 TouchEvent,也不会产生带有 pointerType: "touch" 的 PointerEvent。它触发的是:
- 带有
pointerType: "mouse"的 PointerEvent——单点移动和点击作为普通的指针鼠标事件到达。浏览器无法仅凭事件判断物理输入设备是鼠标还是触控板。 - WheelEvent——触控板上的双指滚动产生
wheel事件,行为与鼠标滚轮相同。deltaX和deltaY属性报告滚动量。 - 带有
ctrlKey: true的 WheelEvent——操作系统将触控板的捏合缩放手势转换为带有ctrlKey标志的wheel事件。这是跨浏览器的标准触控板缩放信号。网页拦截ctrl+wheel实现自定义缩放行为正是利用了这一约定。
相比之下,触摸屏会触发带有 pointerType: "touch" 的 PointerEvent,在仍支持旧版 API 的浏览器中,还会触发 TouchEvent。触摸屏上的两指会产生两个同时的 pointerdown 事件,每个事件带有不同的 pointerId,网页代码可以直接利用这些信息通过比较指针间距离计算捏合缩放比例。
为何区分对手势代码很重要
实际影响分为三种模式:
- 触摸屏上的双指捏合——通过跟踪两个同时的
pointerdown事件(或TouchEvent.touches中的两个条目)并计算它们在pointermove事件间的距离变化来检测。此模式在移动设备上有效,但在桌面触控板上无效,因为触控板不会向浏览器发送两个同时的指针接触。 - 触控板捏合缩放——只能通过带有
ctrlKey === true的wheel事件检测。无需也无法进行双指计算。操作系统已在浏览器接收事件前将双指手势转换为标量缩放增量。 - 两种设备上的滚动——都触发相同的
wheel事件,使滚动成为最通用的手势:addEventListener("wheel", handler)同时捕获触控板双指滚动和触摸屏的超滚动委托。
这种架构上的差异是有意设计的。操作系统处理触控板的多指原始接触数据,向浏览器传递已完成且语义明确的事件。相比之下,触摸屏将原始接触数据传递给浏览器,这就是为什么网页代码可以在触摸屏上实现自定义捏合逻辑,但无法在桌面触控板上实现,除非跳出标准网页平台。
测试工具如何体现这一设计
测试工具的 GestureDetector 模块有意利用了这种区分。点击、双击、长按和滑动通过 PointerEvent 监听器检测——这些事件与触控板触发的 pointerType: "mouse" 事件相同。滚动通过 wheel 事件监听检测。捏合则通过 TouchEvent(touchstart、touchmove)检测——特别检查两个同时接触点并测量它们之间距离的变化。如果距离变化超过 30 像素,则触发捏合。在桌面触控板上,这条路径永远不会触发,因为不会收到 TouchEvent;触控板上的捏合只作为 ctrl+wheel 事件到达,手势面板将其计入滚动而非捏合。在触摸屏上,TouchEvent 路径正常触发,捏合计数器递增。
值得注意的一个实际限制是:无论哪个 API,都不会向网页暴露桌面触控板的原始手指接触数据。测试工具可以检测到 ctrl+wheel 事件触发,但无法报告产生该事件的手指数量或原始接触位置——这些信息在到达浏览器前已被操作系统处理。
自测提示:在笔记本触控板上使用上述工具尝试双指捏合手势。如果手势检测面板未显示捏合计数增加,说明你使用的是桌面触控板,其捏合事件以ctrl+wheel形式出现,而非TouchEvent。切换到触摸屏设备并重复手势,捏合计数应递增,确认双指TouchEvent路径已激活。