You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仅iOS移动设备上touchmove事件触发两次问题求助

问题现象

仅iOS系列移动设备(含Safari浏览器、iOS端WebView)上,执行单次滑动操作时,绑定在window上的touchmove事件会被触发两次,导致回调内逻辑重复执行,例如下方代码会连续弹出两次alert弹窗,安卓等其他设备无该异常:

$(window).bind('touchmove', function(e) { 
  alert('something'); 
});
触发原因
  1. iOS部分版本(集中在iOS13~iOS16)的Web内核触摸事件派发机制存在特殊逻辑:滑动手势触发时,系统手势识别模块会先派发一次touchmove事件用于滚动行为判定,判定完成后会再次向DOM树派发正式的触摸事件,两次事件都会冒泡到window层被监听到,且两次触发的时间差通常在10ms以内。
  2. alert属于同步阻塞API,第一次事件回调触发弹窗时,第二次事件已经进入事件队列等待执行,关闭第一个弹窗后会立刻执行第二个回调弹出弹窗,让双触发问题被放大;如果回调是普通日志、DOM操作等非阻塞逻辑,该问题几乎不会被感知。
  3. jQuery早期版本的bind方法没有对同源瞬时重复事件做过滤,会完整响应两次事件触发。
修复方案
  • 事件触发节流兜底(通用兼容方案,不影响原有页面逻辑)
    通过时间戳判定过滤掉短时间内的重复触发,阈值设置为20ms即可覆盖iOS双触发的时间差,同时不会影响正常滑动时连续触发的touchmove事件(正常滑动的事件触发间隔约16ms/帧):
let lastTouchMoveStamp = 0;
// 建议替换过时的bind为on绑定,jQuery1.7+版本均支持on方法
$(window).on('touchmove', function(e) {
  const currentStamp = Date.now();
  // 拦截瞬时重复触发
  if (currentStamp - lastTouchMoveStamp < 20) return;
  lastTouchMoveStamp = currentStamp;
  // 原有业务逻辑
  alert('something');
});
  • 阻止事件重复冒泡(适合单页无复杂嵌套滚动的场景)
    在回调内拦截事件的重复冒泡传播,注意不要随意添加e.preventDefault(),否则会导致页面原生滚动失效:
$(window).on('touchmove', function(e) {
  e.stopPropagation();
  // 仅全屏自定义滑动场景可开启下面这行,会禁用默认滚动
  // e.preventDefault();
  alert('something');
});

注意:不要通过移除事件监听再重新绑定的方式处理该问题,会导致正常滑动过程中的事件响应中断,出现滑动卡顿。

内容的提问来源于stack exchange,提问作者ibrahimnsall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 12:06:20