fix: 手机左右滑动切换 tab 不生效
All checks were successful
PR Preview / test (pull_request) Has been skipped
Deploy Production / test (push) Successful in 7s
PR Preview / teardown-preview (pull_request) Successful in 14s
PR Preview / deploy-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 6s
Test / build-check (push) Successful in 4s
Deploy Production / deploy (push) Successful in 6s
Test / e2e-test (push) Successful in 3m1s
All checks were successful
PR Preview / test (pull_request) Has been skipped
Deploy Production / test (push) Successful in 7s
PR Preview / teardown-preview (pull_request) Successful in 14s
PR Preview / deploy-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 6s
Test / build-check (push) Successful in 4s
Deploy Production / deploy (push) Successful in 6s
Test / e2e-test (push) Successful in 3m1s
- 加 touch-action: pan-y 阻止浏览器抢占水平手势 - 用 touchmove 实时跟踪手指位置(比 touchend.changedTouches 更可靠) - 用 touchstart 的 target 判断 no-swipe 区域(手指移动后 target 可能变) - 弹窗/遮罩层打开时跳过滑动切换 - 阈值从 50px 调到 60px 减少误触 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #43.
This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Main content -->
|
||||
<div class="main" @touchstart="onSwipeStart" @touchend="onSwipeEnd">
|
||||
<div class="main" @touchstart.passive="onSwipeStart" @touchmove.passive="onSwipeMove" @touchend="onSwipeEnd" style="touch-action: pan-y">
|
||||
<router-view />
|
||||
</div>
|
||||
|
||||
@@ -167,23 +167,36 @@ function toggleUserMenu() {
|
||||
}
|
||||
|
||||
// ── 左右滑动切换 tab ──
|
||||
// 滑动顺序 = visibleTabs 的顺序(根据用户角色动态决定)
|
||||
// 轮播区域(data-no-tab-swipe)内的滑动不触发 tab 切换
|
||||
// touch-action: pan-y on .main tells the browser to only handle vertical scroll natively,
|
||||
// leaving horizontal swipe gestures to our JS handler.
|
||||
const swipeStartX = ref(0)
|
||||
const swipeStartY = ref(0)
|
||||
const swipeEndX = ref(0)
|
||||
const swipeEndY = ref(0)
|
||||
const swipeStartTarget = ref(null)
|
||||
|
||||
function onSwipeStart(e) {
|
||||
swipeStartX.value = e.touches[0].clientX
|
||||
swipeStartY.value = e.touches[0].clientY
|
||||
swipeEndX.value = e.touches[0].clientX
|
||||
swipeEndY.value = e.touches[0].clientY
|
||||
swipeStartTarget.value = e.target
|
||||
}
|
||||
|
||||
function onSwipeEnd(e) {
|
||||
const dx = e.changedTouches[0].clientX - swipeStartX.value
|
||||
const dy = e.changedTouches[0].clientY - swipeStartY.value
|
||||
// 必须是水平滑动 > 50px,且水平距离大于垂直距离
|
||||
if (Math.abs(dx) < 50 || Math.abs(dy) > Math.abs(dx)) return
|
||||
// 轮播区域内不触发 tab 切换
|
||||
if (e.target.closest && e.target.closest('[data-no-tab-swipe]')) return
|
||||
function onSwipeMove(e) {
|
||||
swipeEndX.value = e.touches[0].clientX
|
||||
swipeEndY.value = e.touches[0].clientY
|
||||
}
|
||||
|
||||
function onSwipeEnd() {
|
||||
const dx = swipeEndX.value - swipeStartX.value
|
||||
const dy = swipeEndY.value - swipeStartY.value
|
||||
// Must be primarily horizontal (>60px) and more horizontal than vertical
|
||||
if (Math.abs(dx) < 60 || Math.abs(dy) > Math.abs(dx)) return
|
||||
// Carousel area excluded
|
||||
if (swipeStartTarget.value?.closest?.('[data-no-tab-swipe]')) return
|
||||
// Skip when modal/overlay is open
|
||||
if (document.querySelector('.modal-overlay, .detail-overlay, .dialog-overlay')) return
|
||||
|
||||
const tabs = visibleTabs.value.map(t => t.key)
|
||||
const currentIdx = tabs.indexOf(ui.currentSection)
|
||||
@@ -193,8 +206,7 @@ function onSwipeEnd(e) {
|
||||
if (dx < 0 && currentIdx < tabs.length - 1) nextIdx = currentIdx + 1
|
||||
else if (dx > 0 && currentIdx > 0) nextIdx = currentIdx - 1
|
||||
if (nextIdx >= 0) {
|
||||
const tab = visibleTabs.value[nextIdx]
|
||||
handleTabClick(tab)
|
||||
handleTabClick(visibleTabs.value[nextIdx])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user