app端手势识别需节流+坐标差值累积、手写touchtrack逻辑、自算双指缩放、禁用ios边缘返回并自实现,且须三端真机验证。

App端手势识别必须绕开 @touchmove 频繁触发陷阱
uni-app 在 App 端(iOS/Android)的 @touchmove 事件默认频率极高,尤其在快速滑动时每秒可能触发上百次。直接在里面做坐标计算或状态判断,不仅 CPU 占用高,还会导致 scale、rotation 等连续值抖动严重,缩放卡顿、旋转跳变就是这么来的。
实际做法是加节流 + 坐标差值累积:
- 用
requestAnimationFrame包裹移动逻辑,确保只在下一帧更新一次视图 - 不依赖单次
event.touches[0].clientX,而是记录上一次位置,算dx = currentX - lastX再累加到moveX - 对多点触控(如双指),优先取
event.touches.length === 2时的中心点和两点距离,避免单点误判 - iOS Webview 下
clientX/clientY可能含系统导航栏偏移,建议统一用pageX/pageY或通过getBoundingClientRect()校准容器基准
useTouchtrack 是最稳的手势跟踪工具,但别直接 import
uni-app 官方内部确实提供了 useTouchtrack(路径在 packages/uni-components/src/helpers/useTouchtrack.ts),但它不是公开 API,未导出到 uni 全局对象,也不能直接 import 使用——强行引入会导致 HBuilderX 编译报错或小程序端缺失。
替代方案是手写轻量版跟踪逻辑,核心只需三段:
-
@touchstart:存startX/startY、touches.length、timestamp,并标记isTracking = true -
@touchmove:仅当isTracking为真才计算位移,且用preventDefault()阻止页面滚动(尤其在scroll-view外层) -
@touchend或@touchcancel:清状态,同时判断是否构成“滑动”(如Math.abs(dx) > 30)再触发业务逻辑
双指缩放必须监听 touches 长度变化,不能只看 scale
很多开发者以为给元素加个 transform: scale({{scale}}) 就完事了,结果发现 iOS 上双指张开没反应,Android 上缩放方向反了。根本原因是:uni-app 的 App 端不自动提供 event.scale,这个字段只在部分浏览器环境存在,App 端必须自己算。
正确做法是:
- 在
@touchstart记录初始两点距离:initDistance = getDistance(e.touches[0], e.touches[1]) - 在
@touchmove(且e.touches.length === 2)时重算当前距离:currentDistance = getDistance(...) - 新缩放值 =
initScale * (currentDistance / initDistance),并限制范围(如Math.min(Math.max(newScale, 0.5), 3)) - 务必在
@touchend重置initDistance和initScale,否则下次双指操作会继承上次结束时的缩放基数
其中 getDistance 就是勾股定理:Math.hypot(x1 - x2, y1 - y2)。
边缘右滑返回要禁用系统手势,再自己实现
iOS 的边缘侧滑返回是系统级行为,uni-app App 端默认开启。如果你在页面里自己监听左滑手势做跳转,就会和系统手势冲突:手指从左侧划入,一半触发系统返回,一半触发你自己的逻辑,体验极差。
必须分两步处理:
- 在页面
onLoad中调用:this.$mp.page.$getAppWebview().setStyle({ popGesture: 'none' }),彻底关闭系统手势 - 自己监听
@touchstart判断起始clientX (约 20–30px 边缘区),再结合 <code>@touchmove的dx > 0和最小位移(如 80px)判定为有效右滑 - 动画要用
transform: translateX({{offset}}px)+transition: transform 0.2s ease-out,别用left或margin-left,否则 iOS Webview 渲染不连贯 - 注意 Android 端无系统边缘手势,所以该逻辑仅需在
process.env.UNI_PLATFORM === 'app-plus' && uni.getSystemInfoSync().platform === 'ios'下启用
真正难的不是手势识别本身,而是不同平台下 touch 坐标系、事件触发时机、Webview 行为的细微差异——这些不会报错,但会让同一个逻辑在 iOS 上丝滑、在 Android 上卡顿、在 H5 上完全失效。每次加新手势前,先在三端真机跑一遍基础位移和缩放,比写十行优化代码都管用。











