移动端的点击延迟、点击穿透和滚动性能问题怎样处理?
先理解原理和示例,再练习完整口述与追问。
回答要点
300ms 延迟来自浏览器等待判断是否双击缩放,设置 width=device-width 的 viewport 或 touch-action: manipulation 后现代浏览器已取消,FastClick 不再需要。点击穿透是 touchstart 关闭遮罩后,延迟派发的 click 落到下层元素,统一用 click 或 pointer 事件即可避免。滚动监听使用 passive,惯性滚动和 overscroll 用 CSS 控制。
原理拆解
触摸后浏览器的事件顺序通常是 touchstart → touchend → 延迟后的模拟鼠标事件和 click。若在 touchstart/touchend 中隐藏弹层,之后的 click 会作用在原坐标下方新露出的元素上,例如链接或输入框,就是点击穿透。统一使用 click 或 Pointer Events(pointerdown、pointerup 同时覆盖鼠标、触摸、笔)能避免混用两套事件。
touchstart、touchmove、wheel 的监听器可能调用 preventDefault 阻止滚动,浏览器必须等监听器执行完才能滚动;声明 { passive: true } 后可以立即滚动。Chrome 已把 document 级的 touch 监听默认设为 passive。弹窗打开时防止背景滚动,可用 overscroll-behavior: contain 阻止滚动链,iOS 上还需要锁定 body 并恢复滚动位置。
示例与推演
.button, a { touch-action: manipulation; }
.modal-content { overflow-y: auto; overscroll-behavior: contain; }
list.addEventListener('touchmove', onTouchMove, { passive: true })
在弹层关闭时,延迟一帧再移除遮罩,或在遮罩上统一使用 click 关闭,都能避免穿透。
易错点
在 passive 监听器中调用 preventDefault 会被忽略并打印警告;全局 touch-action: none 会禁用页面滚动和缩放,影响可访问性。iOS 输入框聚焦时,小于 16px 的字号会触发页面自动放大。
参考回答可直接练习口述
300ms 延迟是浏览器等双击缩放,现在设置 width=device-width 的 viewport 或 touch-action: manipulation 就没有了,不需要 FastClick。点击穿透是 touch 事件里关闭了遮罩,随后延迟的 click 落到下层元素,解决办法是统一用 click 或 Pointer Events,不混用。滚动相关的 touch 和 wheel 监听加 passive,弹窗内滚动用 overscroll-behavior: contain 防止带动背景。