会,滑动事件会直接干扰 touchstart/touchmove 手势识别,因未阻止默认行为时浏览器立即启动原生滚动,导致 touchend 丢失、touches 清空或 pinch 跟踪中断;需延迟判定后按需 preventdefault() 或用 touch-action 精确控制。

滑动事件会干扰 touchstart/touchmove 手势识别吗
会,而且干扰很直接。浏览器在 touchmove 触发后若未阻止默认行为,会立即启动原生滚动(即 HTML 滑动),导致后续手势逻辑被中断或坐标失真——尤其在快速拖拽、长按、双指缩放等场景下,touchend 可能根本收不到,或 touches 列表突然清空。
常见现象包括:touchend 不触发、event.touches.length 在中途变为 0、自定义 pinch 手势无法持续跟踪两指距离。
- 关键判断点:只要页面有可滚动区域(
overflow: auto/scroll或 body 默认滚动),且未对 touch 事件调用preventDefault(),系统就会“抢走”手势控制权 - 不是所有
touchmove都需要阻止:仅当你要实现非滚动类手势(如画线、旋转、拖拽元素)时才需干预;若只是做滚动增强(如回弹、吸附),应让原生滚动继续 - 现代方案倾向用
{ passive: false }显式声明可取消,避免 Chrome 的被动监听警告
preventDefault() 调用时机不对会导致手势失效
在 touchstart 就调用 preventDefault() 是最常见错误——这会让整个区域彻底失去滚动能力,用户连正常上下滑都做不到,体验比手势失败还糟。
正确做法是“延迟判定”:先记录起始位置,在 touchmove 中根据位移方向和阈值决定是否接管。比如水平位移 > 10px 且你正做轮播切换,才阻止默认行为;否则放行,保留滚动。
- 别在
touchstart阻止,默认行为尚未触发,调用无效且可能被忽略 - 别在
touchmove无条件阻止,否则滚动瘫痪,iOS Safari 尤其敏感 - 推荐用
event.cancelable && !event.defaultPrevented双重校验再调用preventDefault()
CSS touch-action 是更轻量的替代方案
比起 JS 拦截事件,touch-action 是浏览器原生支持的手势策略开关,性能更好、兼容性也够用(Chrome 36+/Safari 13.1+/Firefox 69+)。
它不干涉事件流,而是告诉浏览器“这个区域允许哪些原生手势”,从而避免不必要的事件抢占。例如:touch-action: pan-y pinch-zoom 表示只允许竖向滚动和双指缩放,横向拖拽(pan-x)会被禁用,你的 JS 就能安全捕获横向 touchmove 做轮播。
-
touch-action: none等价于全局preventDefault(),慎用 -
touch-action: manipulation是快捷写法,等效于pan-x pan-y pinch-zoom,适合按钮类区域 - 注意层级继承:父元素设了
touch-action: none,子元素无法通过 CSS 覆盖,必须 JS 动态改或调整 DOM 结构
iOS Safari 的 overscroll-behavior 和弹性滚动陷阱
iOS Safari 的弹性滚动(rubber banding)会引发额外 touchmove 事件,即使手指已抬起,坐标还持续变化,导致手势状态机错乱。这不是 bug,是系统行为。
解决思路分两层:一是用 overscroll-behavior: contain 禁用容器溢出滚动(防止父容器被拖动),二是监听 touchend 后的 scroll 事件做兜底清理——比如清除当前拖拽状态、重置位移累计值。
-
overscroll-behavior不影响内部滚动,只控制边界行为,比 JS 拦截更干净 - iOS 下
touchcancel可能在弹性滚动开始时触发,要把它和touchend同等对待 - 不要依赖
event.changedTouches[0].clientX的绝对值做长按判定,优先用event.timeStamp和起始坐标差
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











