From 27d081cb236ba4c434b7ee4bf1f9ec31c7c8a1bf Mon Sep 17 00:00:00 2001 From: goodman <62012448+eq1024@users.noreply.github.com> Date: Wed, 30 Apr 2025 16:03:35 +0800 Subject: [PATCH] feat: add scrollable tab bar (#49) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add scrollbar support and enhance tab navigation finish:1/2 * update * feat: 添加当前tab滚动功能并优化滚动条样式 * feat: 重构tab滚动逻辑,新增useTabScroll钩子以优化当前tab滚动体验 * feat: 优化TabBar组件,移除冗余代码并整合useTabScroll钩子 * fix: silly bug * refactor: Remove the debugging log --------- Co-authored-by: Vigo.zhou --- src/hooks/useTabScroll.ts | 64 +++++++++++++++++++++++++++ src/layouts/components/tab/TabBar.vue | 51 ++++++++++++--------- 2 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 src/hooks/useTabScroll.ts diff --git a/src/hooks/useTabScroll.ts b/src/hooks/useTabScroll.ts new file mode 100644 index 0000000..fb449af --- /dev/null +++ b/src/hooks/useTabScroll.ts @@ -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) { + const scrollbar = ref>() + 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('.tab-bar-scroller-wrapper .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 + } +} diff --git a/src/layouts/components/tab/TabBar.vue b/src/layouts/components/tab/TabBar.vue index 01c8469..79c61d7 100644 --- a/src/layouts/components/tab/TabBar.vue +++ b/src/layouts/components/tab/TabBar.vue @@ -1,6 +1,7 @@