feat: 重构tab滚动逻辑,新增useTabScroll钩子以优化当前tab滚动体验

This commit is contained in:
Vigo.zhou 2025-04-30 15:24:25 +08:00
parent 5f7002a5a3
commit 85a5b17721
2 changed files with 67 additions and 60 deletions

64
src/hooks/useTabScroll.ts Normal file
View File

@ -0,0 +1,64 @@
import type { NScrollbar } from 'naive-ui'
import { ref, watchEffect, type Ref } from 'vue'
import { throttle } from 'radash'
export function useTabScroll(currentTabPath: Ref<string>) {
const scrollbar = ref<InstanceType<typeof NScrollbar>>()
const safeArea = ref(150)
const handleTabSwitch = (distance: number) => {
scrollbar.value?.scrollTo({
left: distance,
behavior: 'smooth'
})
}
const scrollToCurrentTab = () => {
nextTick(() => {
const currentTabElement = document.querySelector(`[data-tab-path="${currentTabPath.value}"]`) as HTMLElement
const tabBarScrollWrapper = document.querySelector('.n-scrollbar-container')
const tabBarScrollContent = document.querySelector('.tab-bar-scroller-content')
if (currentTabElement && tabBarScrollContent && tabBarScrollWrapper) {
const tabLeft = currentTabElement.offsetLeft
const tabBarLeft = tabBarScrollWrapper.scrollLeft
const wrapperWidth = tabBarScrollWrapper.getBoundingClientRect().width
const tabWidth = currentTabElement.getBoundingClientRect().width
const containerPR = Number.parseFloat(window.getComputedStyle(tabBarScrollContent).paddingRight)
if (tabLeft + tabWidth + safeArea.value + containerPR > wrapperWidth + tabBarLeft) {
handleTabSwitch(tabLeft + tabWidth + containerPR - wrapperWidth + safeArea.value)
} else if (tabLeft - safeArea.value < tabBarLeft) {
handleTabSwitch(tabLeft - safeArea.value)
}
}
})
}
const handleScroll = throttle({ interval: 120 }, (step: number) => {
scrollbar.value?.scrollBy({
left: step * 400,
behavior: 'smooth'
})
})
const onWheel = (e: WheelEvent) => {
e.preventDefault()
if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
handleScroll(e.deltaY > 0 ? 1 : -1)
}
}
watchEffect(() => {
if (currentTabPath.value) {
scrollToCurrentTab()
}
})
return {
scrollbar,
onWheel,
safeArea,
handleTabSwitch
}
}

View File

@ -13,7 +13,8 @@ import ContentFullScreen from './ContentFullScreen.vue'
import DropTabs from './DropTabs.vue'
import Reload from './Reload.vue'
import TabBarItem from './TabBarItem.vue'
import { throttle } from 'radash'
import { useTabScroll } from '@/hooks/useTabScroll'
const tabStore = useTabStore()
const { tabs } = storeToRefs(useTabStore())
@ -105,65 +106,7 @@ function onClickoutside() {
}
const el = ref()
const scrollbar = ref<InstanceType<typeof NScrollbar>>()
// tab
function scrollToCurrentTab() {
nextTick(() => {
const currentTabElement = document.querySelector(`[data-tab-path="${tabStore.currentTabPath}"]`) as HTMLElement
const tabBarScrollWrapper = document.querySelector('.tab-bar-scroller-wrapper .n-scrollbar-container')
const tabBarScrollContent = document.querySelector('.tab-bar-scroller-content')
if (currentTabElement && tabBarScrollContent && tabBarScrollWrapper) {
const tabLeft = currentTabElement.offsetLeft
const wrapper = tabBarScrollWrapper.getBoundingClientRect().width
const tabWidth = currentTabElement.getBoundingClientRect().width
const containerPR = Number.parseFloat(
window.getComputedStyle(tabBarScrollContent)
.getPropertyValue('padding-right'),
) || 0
if (tabLeft + tabWidth + 160 + containerPR > wrapper + tabBarScrollWrapper.scrollLeft) {
scrollbar.value?.scrollTo({
left: tabLeft + tabWidth + containerPR - wrapper + 160,
behavior: 'smooth',
})
}
else if (tabLeft - 100 < tabBarScrollWrapper.scrollLeft) {
scrollbar.value?.scrollTo({
left: tabLeft - 160,
behavior: 'smooth',
})
}
}
})
}
// tab
watchEffect(() => {
if (tabStore.currentTabPath) {
scrollToCurrentTab()
}
})
/**
* [todo)
* radash 给滚动加上防抖
* 遮盖右侧操作区问题 may fixed it
* 添加 类名 基于宽度(对上面的区域)
* 定位当前tab 始终显示
*/
const handleScroll = throttle({ interval: 120 }, (setp) => {
scrollbar.value?.scrollBy({
left: setp * 400,
behavior: 'smooth',
})
})
function onWheel(e: WheelEvent) {
e.preventDefault()
if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
handleScroll(e.deltaY > 0 ? 1 : -1)
}
}
const {scrollbar, onWheel } = useTabScroll(computed(() => tabStore.currentTabPath))
useDraggable(el, tabs, {
animation: 150,