fix(ui): 拖动松手从手指位置平滑契合到目标 tab
- 拖动状态与位置状态分离 - 松手先恢复过渡但保留手指位置,下一帧再吸附到目标 tab,避免从旧位置跳变
This commit is contained in:
@@ -41,6 +41,8 @@ export default function CustomTabBar() {
|
||||
// 微信自定义 tabBar 不会自动感知 page 路由变化,用 state 保持选中态响应式
|
||||
const [activeTab, setActiveTab] = useState<string>(currentTabPath)
|
||||
const [dragPercent, setDragPercent] = useState<number | null>(null)
|
||||
const [isDragging, setIsDragging] = useState<boolean>(false)
|
||||
const isDraggingRef = useRef<boolean>(false)
|
||||
const dragPercentRef = useRef<number | null>(null)
|
||||
const startXRef = useRef<number>(0)
|
||||
const barFrameRef = useRef<{ left: number; width: number } | null>(null)
|
||||
@@ -105,6 +107,8 @@ export default function CustomTabBar() {
|
||||
const frame = getTabBarFrame(Taro.getSystemInfoSync().windowWidth)
|
||||
barFrameRef.current = frame
|
||||
startXRef.current = touch.clientX
|
||||
isDraggingRef.current = false
|
||||
setIsDragging(false)
|
||||
dragPercentRef.current = null
|
||||
setDragPercent(null)
|
||||
}
|
||||
@@ -113,8 +117,10 @@ export default function CustomTabBar() {
|
||||
const frame = barFrameRef.current
|
||||
const touch = e.touches && e.touches[0]
|
||||
if (!frame || !touch) return
|
||||
if (dragPercentRef.current === null && !hasDragged(startXRef.current, touch.clientX, DRAG_THRESHOLD_PX)) {
|
||||
return
|
||||
if (!isDraggingRef.current) {
|
||||
if (!hasDragged(startXRef.current, touch.clientX, DRAG_THRESHOLD_PX)) return
|
||||
isDraggingRef.current = true
|
||||
setIsDragging(true)
|
||||
}
|
||||
const nextPercent = clampPercent(((touch.clientX - frame.left) / frame.width) * 100)
|
||||
dragPercentRef.current = nextPercent
|
||||
@@ -125,8 +131,14 @@ export default function CustomTabBar() {
|
||||
const frame = barFrameRef.current
|
||||
if (!frame) return
|
||||
let targetIndex: number
|
||||
if (dragPercentRef.current !== null) {
|
||||
targetIndex = tabIndexAtPercent(dragPercentRef.current, TABS.length)
|
||||
if (isDraggingRef.current) {
|
||||
targetIndex = tabIndexAtPercent(dragPercentRef.current ?? 0, TABS.length)
|
||||
isDraggingRef.current = false
|
||||
setIsDragging(false)
|
||||
Taro.nextTick(() => {
|
||||
dragPercentRef.current = null
|
||||
setDragPercent(null)
|
||||
})
|
||||
} else {
|
||||
const touch = e.changedTouches && e.changedTouches[0]
|
||||
const x = touch ? touch.clientX : startXRef.current
|
||||
@@ -136,13 +148,13 @@ export default function CustomTabBar() {
|
||||
if (target && target.pagePath !== activeTab) switchTab(target.pagePath)
|
||||
barFrameRef.current = null
|
||||
startXRef.current = 0
|
||||
dragPercentRef.current = null
|
||||
setDragPercent(null)
|
||||
}
|
||||
|
||||
const cancelDrag = () => {
|
||||
barFrameRef.current = null
|
||||
startXRef.current = 0
|
||||
isDraggingRef.current = false
|
||||
setIsDragging(false)
|
||||
dragPercentRef.current = null
|
||||
setDragPercent(null)
|
||||
}
|
||||
@@ -163,7 +175,7 @@ export default function CustomTabBar() {
|
||||
<View className='tab-bar-caustic' />
|
||||
<View className='tab-bar-rim' />
|
||||
<View
|
||||
className={`tab-indicator ${dragPercent !== null ? 'dragging' : ''}`}
|
||||
className={`tab-indicator ${isDragging ? 'dragging' : ''}`}
|
||||
style={{ left: dragPercent === null ? `${(activeIndex + 0.5) * TAB_CENTER_STEP}%` : `${dragPercent}%` }}
|
||||
/>
|
||||
{TABS.map((tab) => {
|
||||
|
||||
Reference in New Issue
Block a user