返回

浏览器触控板多指手势识别及处理方案

javascript

解决浏览器中使用触控板多指手势的问题

在桌面浏览器中利用触控板进行多指手势操作,这个需求为网页应用开发增添新的交互可能性。目标是在特定情境,例如当多个手指接触触控板时触发与标准滚动不同的操作(如拖拽滚动)。 了解是否以及如何在桌面浏览器中检测多指手势及事件十分关键。下面探讨此议题,剖析存在的技术挑战并提供切实可行的应对策略。

一、触控板多指手势识别的挑战

在网页环境中实现对触控板多指手势的可靠识别,存在着不小挑战。不同于移动端,桌面浏览器通常不直接提供全面的多点触控 API。导致获取触控事件细节面临不少限制,特别是在区分复杂手势的时候。尽管 W3C 标准包括 Pointer Events 规范,提供统一处理各种输入设备的接口。但这个规范,目前尚未得到全面支持,各浏览器厂商的具体实现情况也不尽相同。
Windows 和 MacOS 对多点触控和触摸板行为定义不一样。浏览器会处理触摸事件并将部分行为作为自身功能的事件执行(如前进,后退),不进行上报,导致我们接收到的事件并不全。MacOS 和 Safari 会直接阻止特定手势上报到应用中。在 Mac 上双指轻点作为了右键被支持,然而这是 OS 层面捕获并处理的事件,不会报告给浏览器中的应用程序。同时触摸板通常会被用来处理操作系统或浏览器的快捷手势。这种设计给应用造成了一些困扰,用户希望将自定义的多指操作映射为应用的特殊行为时会受到干扰,体验变得不可预测。

二、处理策略及代码实现

开发人员还是可以在已有的规范与方法中摸索前行。通过特定手段达到接近预期的效果,以下是一些可选方案:

1. Pointer Events 的使用

Pointer Events 为多点触控操作的实现提供了统一的方式,不同类型的指针设备都被视为 Pointer 。使用这个方案,不同于传统 Mouse Event 与 Touch Event ,其将鼠标,触摸等均当做一种通用的事件类型来看待。Pointer Events 支持按压力度检测,因此可以用来区分并忽略鼠标和触摸板点击产生的按下行为。以下是一个简单示例:

操作步骤:

  1. 在 HTML 文档中添加需要监听手势的元素。
  2. 使用 JavaScript 监听该元素的 pointerdownpointermovepointeruppointercancel 事件。
  3. 在事件处理函数中区分不同类型的输入设备以及不同数量的手指。
  4. 根据需求实现多指手势的特定逻辑。

代码示例:

const element = document.getElementById('touch-area');

element.addEventListener('pointerdown', (event) => {
  console.log("手指个数:", event.isPrimary); //如果手指是第一触点,则为true。后续的pointer down 都会为false
  if (event.pointerType === 'touch' && event.buttons == 1) {
      console.log('触控板多指手势开始');
      console.log(event);
  }

  // 防止滚动和缩放
  if (event.pointerType === 'touch') {
      event.preventDefault(); //需要视情况来控制是否阻止默认行为
  }
});

element.addEventListener('pointermove', (event) => {
  if (event.pointerType === 'touch' && event.isPrimary == false) {
    console.log('触控板多指手势移动');
    console.log(event);
  }
});

element.addEventListener('pointerup', (event) => {
    if (event.pointerType === 'touch') {
      console.log('触控板多指手势结束');
      console.log(event);
    }
});

element.addEventListener('pointercancel', (event) => {
    console.log('触控板多指手势被取消');
});

这个方式虽然可以通过按压来简单区分部分手指行为。但是,它依旧受到限制,无法捕获系统定义的手势或多个手指的按下事件。这种方式在 Firefox 可以正常运行,在 Chrome 可以使用组合按键绕过事件阻塞行为(在 Windows 上可以按下 Windows Key 或 Ctrl 键再双指触摸可以使 Chrome 上报两个 pointerdown 事件)。这属于系统的 BUG ,可能被修复或随时改变行为。

2. 触摸事件 (Touch Events)

除了指针事件,TouchEvent 也用于表示用户手指或触控笔和触控表面间接触状态变化发生的事件。一个 TouchEvent 实例通过一个changedTouches 属性来传递当前已改变状态的触点的信息。

操作步骤:

  1. 在你的HTML文件中,创建一个将接收触摸事件的目标元素。
  2. 通过 addEventListener 方法添加针对 touchstarttouchmovetouchendtouchcancel 事件的监听器到这个元素上。
  3. 在事件处理器中,访问每个事件的 touches 列表来跟踪触摸的ID,targetTouches 属性获取相对于当前元素触发的所有 Touch 对象的集合。或者 changedTouches 属性跟踪引发本次事件的触点的信息,获取相关数据比如屏幕坐标。
  4. 分析触摸行为以判定手势种类。

代码示例:

var myElement = document.getElementById("target");
myElement.addEventListener("touchstart", onTouchStart, false);
myElement.addEventListener("touchmove", onTouchMove, false);
myElement.addEventListener("touchend", onTouchEnd, false);

function onTouchStart(e){
    // 获取当前的触点信息
    console.log("Start", e.changedTouches[0]);
}

function onTouchMove(e){
    e.preventDefault();
    console.log("Move", e.changedTouches[0]);
}

function onTouchEnd(e){
    console.log("End", e.changedTouches[0]);
}

这种方式是比较经典的用来做多点触控的方法。在 Mac 和 Safari 组合下无法实现需要的效果,TouchEventchangedTouches 只能监听到第一个手指触控点,且其余触摸点的任何事件都不会产生。在 Windows 环境下也仅能获取最多三个 touchstart 事件,且在 Windows Edge 浏览器上的 changedTouches 也存在一些问题(行为和上述类似),需要进一步尝试和处理兼容性问题。

3. Wheel 事件精细化识别

当触控板上的滚动操作过于缓慢导致难以触发 scroll 事件时,利用鼠标滚轮事件 (wheel events) 提供了一个备选的解决方案。可以通过监听滚轮事件,并从中获取精细的滚动行为数据。比如 Mac 系统的触控板可以生成一个包含非整数的 deltaX、deltaY 属性。用于表示滑动的极小偏移量。然后我们可以手动检测 deltaY 值为非整数来判断事件是否来源于触控板的双指操作。

操作步骤:

  1. 通过 addEventListener 注册滚轮事件处理函数。
  2. 事件发生时, 在处理函数里利用 event 对象的属性如 deltaX, deltaY , deltaMode来区分。判断这些数值的精度及范围来评估输入行为是否来源于高精度滚动设备的细微滑动。

代码示例:

document.addEventListener('wheel', (event) => {
  // 检查 event.deltaY 的值是否为小数
  if (!Number.isInteger(event.deltaY)) {
    // 在此处添加您想在Mac双指滑动时执行的代码
    console.log('Mac Touchpad 双指滑动事件');
    console.log('滚动差值:', event.deltaY);
  }

    if(event.ctrlKey)
    {
        console.log('这是双指缩放事件');
    }
}, { passive: false });

passive: false 可以让浏览器的 preventDefault 生效,如果不加入这句声明会导致滚轮事件的处理无效(表现为你监听到了 wheel 事件但是页面行为不受控制)。

当这个方案有缺陷,因为不是为了触控板和鼠标事件分离设计的,仅可以做到分辨 Mac 上 TouchPad 和其他鼠标产生的滚动。该事件不会包含双指单击触摸,因此仅能作为一个处理 Mac 上滑动的增强手段使用。在 Windows 环境下也有一定的应用价值,当多个手指在 Windows TouchPad 放置并产生滑动时也会引发该事件,因此也有办法识别该行为并用于应用的业务逻辑中。但是和之前两种方案一样存在一个问题是:仅有滑动行为可以识别。

4. 第三方库 - Hammer.js

Hammer.js 是一个开源 JavaScript 库, 能让你轻松处理手势操作。识别由触摸、鼠标、PointerEvent 触发的手势,让手势操作变得流畅、易用,不需要自己处理事件的捕获、解析。兼容 IE11+,并且拥有良好的文档支持。使用 Hammer 可以快速处理多点触摸的问题,也可以通过手势组合来自行处理自己想要的触摸行为。
Hammer 是比较老牌的多点触控库,能用于应对日常简单的需求。但是内部也是基于TouchEventPointerEvent 来处理用户输入。因此也无法有效处理触控板设备上的手势冲突问题。可以将其作为一个增强体验的选项来添加多设备输入支持。
例如下面简单的单击+移动处理事件:

const element = document.getElementById('yourElement');
const mc = new Hammer.Manager(element);
const pan = new Hammer.Pan({ direction: Hammer.DIRECTION_ALL, threshold: 0 });
const tap = new Hammer.Tap();

mc.add([pan, tap]);
mc.on('pan', function (e) {
    // e 对象将包含有关手势的信息,例如偏移量
    const offsetX = e.deltaX;
    const offsetY = e.deltaY;

    // 使用这些值来更新你元素的位置或执行其它你想要的任务
    console.log("Pan (拖动) 手势:", offsetX, offsetY);

    if(e.type === "panend")
    {
        console.log("Pan (拖动) 结束");
    }
});

mc.on("tap", function (e) {
    // 当一个单击事件发生的时候
    console.log("单击发生");
});

这展示了一个简单的单击 + 移动的手势。它还无法完成我们需要的多点操作,而且还会造成阻止事件默认行为(例如无法滑动)。需要修改手势配置并自己定义自己的手势识别和组合来进一步判断用户输入,达到所需目的。

安全建议

使用这些事件,安全需要考虑。处理用户输入应谨慎进行,避免引入 XSS 等漏洞。不将用户输入的内容直接嵌入 DOM 结构。对触控数据,应限定事件来源范围, 避免因为页面异常响应非预期的行为而造成的安全风险或应用稳定性问题。不应该对系统处理有潜在破坏的事件进行改写。

三、未来展望

针对触控板,提供更加完备的多指手势事件支持,还存在不少工作要做。各浏览器厂商可以不断改进实现方式。针对此情况提供更精准的控制选项。期待 W3C 相关标准的进一步推进及实现程度。使触控事件变得更为细化和可控。这有助于促进新的 Web 交互模式落地。增强体验同时也面临更多潜在的责任。需要在技术创新的道路上保持持续学习和优化,谨慎实践最佳实践。通过完善文档及相关教育普及,使得开发生态逐渐适应并掌握这类交互开发的方法。为应用的体验带来新的变革。