为什么 touchstart 事件在 iOS 上没反应?
我在做一个移动端的滑动组件,用 touchstart 监听触摸开始,但在 iPhone 上完全没触发,安卓却正常。是不是哪里写错了?
我给元素加了下面这个 CSS,会不会是影响了事件冒泡?
.slider {
touch-action: none;
-webkit-user-select: none;
user-select: none;
overflow: hidden;
}
JS 里就是简单的 element.addEventListener('touchstart', handler),试过加 passive: false 也没用……
最可能的原因是元素没有实际的可点击区域。iOS 对触摸元素有严格要求,如果元素没有宽高、或者是个空标签、或者父元素把点击区域吃掉了,touchstart 根本不会触发。
检查一下:
1. 你的 .slider 元素有没有实际的宽高?如果是 0x0 或者靠内容撑开的,得确保有明确的尺寸
2. 元素是否被其他东西覆盖了?用 Safari 开发者工具看看有没有 z-index 问题
3. 试试先加个简单的背景色和尺寸确认元素确实渲染出来了
如果元素没问题,那还有个常见的坑:iOS Safari 有时候会把 touchstart 吞掉直接触发 click,特别是页面用了 viewport 或者有 meta 标签干预的时候。
你可以试一下这个写法:
另外提醒一下,现在移动端更推荐用 pointer 事件(pointerdown、pointermove、pointerup),一套代码兼容鼠标和触摸,比单独处理 touch 事件省心多了。
iOS Safari 有个很恶心的机制,普通的 div 元素默认被认为是"非交互元素",不会响应 touch 事件。你给它绑定 listener,iOS 直接无视,安卓倒是没这毛病。
解决方法很简单,给你的
.slider加一行 CSS:加上
cursor: pointer之后,iOS 就会把这个元素当成"可交互元素",touch 事件就能正常触发了。你原来的 CSS 里
touch-action: none和user-select: none都没问题,不会影响事件冒泡,反而是做滑动组件的标准配置,能防止页面跟着滚动和文字被选中。另外提一嘴,如果你后面要处理
touchmove做拖拽,记得加passive: false,不然preventDefault()会失效:这个问题只会在 iOS 上出现,苹果这波操作属实坑了不少人。