@@ -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 . changedT ouches[ 0 ] . clientX - swipeStartX . value
const dy = e . changedT ouches[ 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 . t ouches[ 0 ] . clientX
swipeEndY . value = e . t ouches[ 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 ] )
}
}