不能用movable-area做列表排序,因其只返回像素坐标而非数组索引,不支持v-for动态渲染(致事件丢失、样式错乱、iOS微信无响应),横向滚动时width难匹配内容总长,且change回调仅松手触发一次,无法实时判定插入位置。

为什么不能用 movable-area 做列表排序
它只返回像素坐标,不返回数组索引;movable-view 不支持 v-for 动态渲染,一写就丢事件、样式错乱、iOS 微信直接无响应;横向滚动时 width 难匹配内容总长,设小了拖不出边界,设大了留白;change 回调只在松手时触发一次,无法实时判断“拖到第几个标签之间”。你强行套用,H5 看似能动,小程序端根本不动、松手复位、真机必卡。
touchstart + touchmove 怎么算对目标索引
核心不是比绝对坐标,而是每次 touchmove 都用 uni.createSelectorQuery() 查当前所有项的 boundingClientRect(),再算中线:midY = rect.top + rect.height / 2(垂直)或 midX = rect.left + rect.width / 2(水平)。只在手指 Y/X 坐标跨过中线时触发一次交换,用 this.lastSwappedIndex 缓存上一次目标,防抖。别缓存 DOM 位置——滚动、增删、切 Tab 后位置全变,必须每帧重查。
注意:event.touches[0].clientX 和 event.touches[0].clientY 是唯一可靠坐标源;pageX/pageY 在小程序里恒为 0,不能用。
松手后怎么安全更新数组顺序
不能直接 splice 原数组,尤其从右往左拖时,删掉一个后后面所有索引前移,插错位置是常态。正确做法是:
- 先深拷贝:
const newList = JSON.parse(JSON.stringify(this.list))(含对象时必需) - 取出被拖项:
const [movedItem] = newList.splice(this.dragIndex, 1) - 插入目标位置:
if (this.toIndex > this.dragIndex) { newList.splice(this.toIndex - 1, 0, movedItem) } else { newList.splice(this.toIndex, 0, movedItem) }
原因:删掉一项后,原 toIndex 后面的索引自动减 1;若拖向更前位置,不用减;若拖向更后位置,要减 1 才对齐视觉间隙。
拖拽过程中的性能与兼容性陷阱
高频 touchmove 直接改 data 或调 this.$forceUpdate() 必卡——小程序平台对 DOM 操作有限制。应只在 touchmove 中计算目标索引,不改数据;用节流(如 16ms)控制查询频率;禁用 scroll-view 滚动(加 scroll-y="false"),否则 iOS 小程序会抢 touch 事件。Android 真机可能重复触发 touchstart,开头加 if (this.isDragging) return 防误触。最后,别信 draggable 属性——小程序完全忽略它。


















