fix: 手机左右滑动切换页面不生效 #43

Merged
fam merged 1 commits from fix/mobile-swipe-tabs into main 2026-04-16 14:02:20 +00:00

View File

@@ -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])
}
}