fix(V0.2): 打卡排序闭包陈旧 + 把手拖动双保险
Docker Build and Push / build-image (push) Successful in 1m1s

- useHabitDrag: onDrop 经 ref 桥接实时闭包 —— bind/bindHandle 空依赖
  useCallback 固化了首次渲染(groups=[] 数据未加载)的落位函数, 松手
  静默早退, 顺序永远不变
- 把手路径挂非 passive touchstart preventDefault: 规范上禁止浏览器对
  整个触摸的默认处理 (含滚动), 与 touch-action:none 双保险
- 把手触区放大 (36px 高), 降低按到行体触发不可靠长按路径的概率
This commit is contained in:
jif2.zhang
2026-10-25 01:31:27 +08:00
parent 2725f00f68
commit 215263bf2f
3 changed files with 25 additions and 6 deletions
+8 -3
View File
@@ -59,12 +59,15 @@ export default function useRowDrag({ columns, onDrop }) {
cleanup()
}
// 指针监听装配 (capture + 非 passive touchmove: 激活后尽力拦截滚动接管)
const armListeners = (ev) => {
// 指针监听装配 (capture + 非 passive touchmove: 激活后尽力拦截滚动接管;
// instant=true 把手路径再挂 touchstart preventDefault, 规范上禁止浏览器对
// 整个触摸的默认处理, 彻底杜绝滚动抢占)
const armListeners = (ev, instant = false) => {
try { ev.currentTarget.setPointerCapture(ev.pointerId) } catch { /* ignore */ }
const el = ev.currentTarget
const move = (e2) => onMove(e2)
const tm = (e2) => { if (st.current.active) e2.preventDefault() }
const ts = (e2) => e2.preventDefault()
const up = () => { onUp(); detach() }
const cancel = () => {
if (st.current.active) lastEnd.current = Date.now()
@@ -76,11 +79,13 @@ export default function useRowDrag({ columns, onDrop }) {
el.removeEventListener('pointerup', up)
el.removeEventListener('pointercancel', cancel)
el.removeEventListener('touchmove', tm)
el.removeEventListener('touchstart', ts)
}
el.addEventListener('pointermove', move)
el.addEventListener('pointerup', up)
el.addEventListener('pointercancel', cancel)
el.addEventListener('touchmove', tm, { passive: false })
if (instant) el.addEventListener('touchstart', ts, { passive: false })
}
/** 绑定到列表行: 行元素需设置 touch-action: pan-y (长按路径, 可滚场景不可靠) */
@@ -115,7 +120,7 @@ export default function useRowDrag({ columns, onDrop }) {
st.current.active = true
if (navigator.vibrate) navigator.vibrate(15)
setDrag({ task, fromIdx, toIdx: fromIdx })
armListeners(ev)
armListeners(ev, true)
},
onContextMenu: (ev) => ev.preventDefault(),
// eslint-disable-next-line react-hooks/exhaustive-deps