为什么touchstart事件在移动端触发后无法阻止默认行为?

W″翌喆 阅读 34

我在移动端开发时给按钮绑定了touchstart事件,想要阻止页面滑动的默认行为。代码是这样写的:


element.addEventListener('touchstart', (e) => {
  e.preventDefault();
  console.log('按钮被触摸');
});

但测试时发现页面仍然可以滑动,明明调用了preventDefault(),这是哪里出问题了?其他事件比如click正常触发,但需要兼容触摸操作。

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
开发者艳青
啊这,典型的移动端触摸事件坑点。关键点在于现代浏览器为了性能考虑,默认不会阻塞滚动,除非你把 touch-action CSS属性也设置上。

两种解决方案,选哪个看你需求:

1. 暴力但高效的方式,直接在CSS里干掉所有触摸滚动:
.your-element {
touch-action: none;
}


2. 或者更精确控制,只在事件监听里处理。但要注意必须设置 passive: false 选项,不然preventDefault会被浏览器无视:
element.addEventListener('touchstart', (e) => {
e.preventDefault();
// 你的逻辑
}, { passive: false });


为啥会这样?因为浏览器为了滚动性能优化,默认把touch事件设为passive。这帮搞浏览器引擎的家伙,为了60fps真是拼了...

我一般直接用第一种方案,效率更高,一劳永逸。除非你还要处理复杂手势才需要第二种。
点赞
2026-03-06 18:05
Air-钰莹
你这个问题挺常见的。在移动端,touchstart事件里直接调用e.preventDefault()确实看起来应该能阻止默认行为,比如页面滑动,但实际上系统对这个事件的处理机制比较特殊。

问题出在浏览器对触摸事件的默认处理流程上。touchstart触发时,浏览器还没有确定是滚动还是点击,所以即使你在touchstart里调用了preventDefault(),也不能保证能阻止整个滑动行为。

要真正阻止滑动,建议你换个思路:监听touchmove事件,而不是touchstart。你可以在这个事件里做判断,比如只有在手指按下后移动的时候才阻止默认行为:

let isTouched = false;

element.addEventListener('touchstart', () => {
isTouched = true;
});

element.addEventListener('touchmove', (e) => {
if (isTouched) {
e.preventDefault();
console.log('阻止滑动');
}
});

element.addEventListener('touchend', () => {
isTouched = false;
});


这样做的原理是,在touchstart里做一个标记,表示开始触摸,然后在touchmove中根据这个标记决定是否阻止默认行为。

另外,如果你只是想阻止某些特定区域的滑动,可以在touchmove事件中加一个判断,看事件目标是否在你关心的区域内,这样就不会影响页面其他部分的滚动体验。

还有一点要注意:iOS 上有些行为是系统级的,比如双指缩放和滑动返回等,这些用preventDefault()是拦不住的,得靠 CSS 的 touch-action 属性来控制更稳妥。

总之,别指望靠一个touchstart里的preventDefault()就能搞定所有,默认行为的拦截要做得更精细一点。
点赞 4
2026-02-08 00:31