mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-05-21 08:19:16 +08:00
feat: 重构tab滚动逻辑,新增useTabScroll钩子以优化当前tab滚动体验
This commit is contained in:
parent
5f7002a5a3
commit
85a5b17721
64
src/hooks/useTabScroll.ts
Normal file
64
src/hooks/useTabScroll.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,8 @@ import ContentFullScreen from './ContentFullScreen.vue'
|
|||||||
import DropTabs from './DropTabs.vue'
|
import DropTabs from './DropTabs.vue'
|
||||||
import Reload from './Reload.vue'
|
import Reload from './Reload.vue'
|
||||||
import TabBarItem from './TabBarItem.vue'
|
import TabBarItem from './TabBarItem.vue'
|
||||||
import { throttle } from 'radash'
|
|
||||||
|
import { useTabScroll } from '@/hooks/useTabScroll'
|
||||||
|
|
||||||
const tabStore = useTabStore()
|
const tabStore = useTabStore()
|
||||||
const { tabs } = storeToRefs(useTabStore())
|
const { tabs } = storeToRefs(useTabStore())
|
||||||
@ -105,65 +106,7 @@ function onClickoutside() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const el = ref()
|
const el = ref()
|
||||||
const scrollbar = ref<InstanceType<typeof NScrollbar>>()
|
const {scrollbar, onWheel } = useTabScroll(computed(() => tabStore.currentTabPath))
|
||||||
|
|
||||||
// 新增:滚动到当前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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useDraggable(el, tabs, {
|
useDraggable(el, tabs, {
|
||||||
animation: 150,
|
animation: 150,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user