uni-app中touchmove拿不到实时坐标,根本原因是平台对触摸事件封装不一致;需按平台分别处理:小程序用catchtouchmove+event.touches,H5用@touchmove.prevent+event.changedTouches[0],并加位移阈值防抖。

uni-app 中 touchmove 事件拿不到实时坐标?
根本原因是 uni-app 在部分平台(尤其是微信小程序和 H5)对原生触摸事件做了封装或拦截,touchmove 默认不触发,或者 event.touches 为空。不是你代码写错了,是平台行为不一致。
- 必须在
<view></view>或其他可触摸容器上显式添加catchtouchmove(小程序)或@touchmove.prevent(H5/APP),否则事件根本不会冒泡到你的处理逻辑 - 微信小程序中,
event.touches只在catchtouchmove下有效;H5 则要用event.changedTouches[0],不能依赖touches[0] - 安卓 APP 端偶尔会触发多次
touchmove但坐标没变,建议加个最小位移阈值(比如Math.abs(deltaY) > 2)再更新位置
用 uni.createSelectorQuery() 获取列表项位置太慢?
拖拽排序必须知道每个 <view class="item"></view> 的 top 值来判断插入位置,但 uni.createSelectorQuery() 是异步的,反复调用会导致卡顿甚至错位。
- 别在每次
touchmove都查一遍 DOM —— 初始化时用selectAll('.item')一次性获取所有节点信息并缓存到this.itemRects = [] - 缓存后,每次只需用当前触摸 Y 坐标遍历比对
itemRects[i].top和itemRects[i].bottom,就能定位目标索引 - 注意:H5 下
boundingClientRect()返回的是相对于视口的坐标,需减去页面滚动偏移uni.getSystemInfoSync().windowTop(实际用pageYOffset更准)
splice 直接改数组导致列表闪动或拖拽中断?
这是最常踩的坑:在拖拽过程中直接用 arr.splice(oldIndex, 1); arr.splice(newIndex, 0, item),Vue 的响应式系统会重渲染整个列表,视觉上出现跳动,且 touchend 后的动画状态丢失。
- 正确做法是维护一个独立的「拖拽态」数据:
this.draggingIndex和this.hoverIndex,只靠 CSStransform: translateY()模拟移动,真实数组不动 - 仅在
touchend时才执行一次真实交换:用Array.prototype.toSpliced()(推荐)或手写安全交换逻辑,避免负索引或越界 - 务必在
touchend后清空缓存的itemRects并重新查询 —— 否则下一次拖拽还是旧位置
微信小程序里 movable-view 能不能替代手写拖拽?
能,但只适用于单个可拖拽块(比如悬浮按钮),不适用于列表项之间互换顺序。它本质是“移动一个盒子”,不是“重排一个数组”。
-
movable-view的direction="vertical"只控制移动方向,无法感知下方哪个movable-area子元素被覆盖,更没法触发 insert 逻辑 - 如果你硬要套用,得配合
bindchange不断计算 top 值,再手动比对列表项位置 —— 最终代码量和复杂度反而超过原生 touch 方案 - 真想省事:用现成插件如
uni-drag-sort,但要注意它内部仍是基于touchstart/move/end封装,平台兼容性坑一个没少
拖拽排序真正难的不是“怎么动”,而是“什么时候算动到位”——不同平台触摸精度、事件节流、DOM 更新时机全都不一样。别迷信一套代码跑三端,至少 H5 和小程序的坐标获取逻辑必须分条件写。


















