DoubleTap 手势在移动端怎么监听才靠谱?

UI艳兵 阅读 7

我在做一个图片预览功能,想用双击放大,但发现原生 touch 事件很难准确识别 DoubleTap,自己用 setTimeout 判断两次 tap 的时间间隔老是误触。

试过记录上次 tap 的时间戳,如果在 300ms 内再次 tap 就算 double tap,但有时候单击也会被误判成双击。有没有更稳定的实现方式?

现在代码大概长这样:

let lastTap = 0;
element.addEventListener('touchend', (e) => {
  const now = Date.now();
  if (now - lastTap < 300) {
    // 触发 double tap
    handleDoubleTap();
  }
  lastTap = now;
});
我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
培乐(打工版)
你的代码问题在于:每次 touchend 都会更新 lastTap,所以单击的时候第一次 tap 就会触发双击逻辑(因为初始值是 0),然后立刻更新 lastTap,第二次单击来的时候又满足条件又被误判。

真正的双击检测不能只看时间间隔,你得分清楚单击和双击的逻辑关系。

核心思路是这样的:第一次点击时不要立即执行任何操作,先等一会儿(比如 250ms),如果在这个时间内发生了第二次点击,那就是双击;如果没等到第二次点击,那就是单击,去执行单击的逻辑。

我给你写一个完整的实现:

// 用一个变量记录点击次数
let tapCount = 0;
// 用一个变量记录定时器
let tapTimer = null;
// 定义双击的间隔时间
const DOUBLE_TAP_DELAY = 250;

element.addEventListener('touchend', (e) => {
// 防止手指在屏幕上滑动时也触发(touches 为空说明手指已经离开)
if (e.touches.length > 0) return;

// 清除之前的定时器(如果有的话)
if (tapTimer) {
clearTimeout(tapTimer);
tapTimer = null;
}

tapCount += 1;

if (tapCount === 1) {
// 第一次点击:启动定时器,等待可能的第二次点击
tapTimer = setTimeout(() => {
// 定时器到期了,说明没有第二次点击,这就是单击
console.log('单击事件');
tapCount = 0;
tapTimer = null;
}, DOUBLE_TAP_DELAY);

} else if (tapCount === 2) {
// 第二次点击到来:取消单击的定时器,直接执行双击
if (tapTimer) {
clearTimeout(tapTimer);
tapTimer = null;
}
console.log('双击事件');
handleDoubleTap();
// 重置计数
tapCount = 0;
}
});


这样写为什么更靠谱:

第一次点击时启动定时器但不执行任何操作,如果 250ms 内有第二次点击,取消定时器并执行双击;如果 250ms 后定时器还在,说明用户只点了一次,执行单击逻辑。

你之前的问题就是第一次点击就执行了双击判断,没有给"这是单击"一个机会。

另外提醒一点:移动端还有原生的 dblclick 事件,但这个在某些浏览器上不太稳定,而且和上面的自定义实现效果差不多。如果你是在做图片预览放大这类功能,上面这个方案足够用了。

如果你的需求只是双击放大,不需要区分单击,那可以把第一次点击的定时器里什么都不干,只在第二次点击时触发双击就行,代码会更简单。
点赞 1
2026-03-11 18:44