移动端 touchstart 未触发需设 passive: false;位移计算应基于 getboundingclientrect() 基准值叠加 Δx;回弹卡顿需配对 will-change: transform 与 transition;ios 拖拽穿透须用 pointer-events 精确隔离;切后台导致 touchend 丢失需监听 visibilitychange 补全状态。

移动端 touchstart 事件没触发?检查 passive: false 设置
现代浏览器对 touchstart 默认启用 passive 模式,一旦监听函数里调用了 preventDefault()(比如阻止页面滚动来实现侧滑),就会被静默忽略——你拖不动,但控制台还不报错。
- 必须在
addEventListener中显式传{ passive: false } - 只对真正需要拦截默认行为的元素绑定,避免全局加
passive: false影响滚动性能 - Vue/React 组件中用 ref 绑定时,别写成
ref.addEventListener('touchstart', ...)后再手动清理,容易漏掉移除监听器
transform 移动距离不准?优先用 getBoundingClientRect() 而非 clientX 差值
直接用两次 touchmove 的 clientX 相减算位移,在快速滑动或页面缩放下误差明显;更稳的方式是基于元素当前真实位置做增量更新。
- 初始化时记录侧边栏
getBoundingClientRect().left作为基准 - 每次
touchmove计算手指位移 Δx,再叠加到基准上,用transform: translateX(...)更新 - 避免用
offsetLeft或style.left——它们不反映 transform 状态,读出来是旧值
侧滑菜单回弹卡顿?CSS will-change 和 transform 3D 要配对开
纯 translateX 在某些安卓 WebView 或低端 iOS 上会掉帧,尤其配合 opacity 渐变时。浏览器需要明确知道这个元素要频繁变化。
- 给侧边栏容器加
style="will-change: transform;"(注意:仅在拖拽中动态加,拖完立刻移除) - 或者统一加
transform: translateZ(0)强制 GPU 加速,但别和will-change叠加用,反而可能触发重绘 - 回弹动画用
transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94),比 linear 更符合物理直觉
iOS Safari 拖拽穿透到 body?用 pointer-events 隔离交互层
iOS Safari 的 touch 事件冒泡机制特殊,侧边栏遮罩层(mask)如果没正确拦截,手指一划就触发了背后的页面滚动,菜单直接“消失”。
立即学习“前端免费学习笔记(深入)”;
- 遮罩层必须设
pointer-events: auto,且 z-index 高于内容区 - 侧边栏内容区域设
pointer-events: none,只在按钮、链接等可点元素上单独设pointer-events: auto - 别依赖
event.stopPropagation()—— iOS 下 touchcancel 可能仍会透出
最麻烦的其实是状态同步:拖拽中用户切后台再切回来,touchend 就永远不触发,得靠 visibilitychange 补一手收尾逻辑。这个点很多人写了半年才意识到。










