From e3d59968b74806dd169df82fe291e92e13353aa2 Mon Sep 17 00:00:00 2001 From: RuoYi Date: Sun, 22 Mar 2026 14:43:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=A1=B5=E7=AD=BE=E5=8A=9F?= =?UTF-8?q?=E8=83=BD&=E6=94=AF=E6=8C=81=E5=85=A8=E5=B1=8F=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/components/TagsView/ScrollPane.vue | 78 ++++++- src/layout/components/TagsView/index.vue | 221 +++++++++++++++--- 2 files changed, 259 insertions(+), 40 deletions(-) diff --git a/src/layout/components/TagsView/ScrollPane.vue b/src/layout/components/TagsView/ScrollPane.vue index edd6749..a393194 100644 --- a/src/layout/components/TagsView/ScrollPane.vue +++ b/src/layout/components/TagsView/ScrollPane.vue @@ -29,11 +29,46 @@ function handleScroll(e: WheelEvent): void { const eventDelta = -e.deltaY * 40 const $scrollWrapper = scrollWrapper.value $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4 + emits('updateArrows') } -const emits = defineEmits() +function smoothScrollTo(target: number): void { + const $scrollWrapper = scrollWrapper.value + const start: number = $scrollWrapper.scrollLeft + const distance: number = target - start + const duration = 300 + let startTime: number | null = null + + function ease(t: number, b: number, c: number, d: number): number { + t /= d / 2 + if (t < 1) return c / 2 * t * t + b + t-- + return -c / 2 * (t * (t - 2) - 1) + b + } + + function step(timestamp: number): void { + if (!startTime) startTime = timestamp + const elapsed = timestamp - startTime + $scrollWrapper.scrollLeft = ease(elapsed, start, distance, duration) + if (elapsed < duration) { + requestAnimationFrame(step) + } else { + $scrollWrapper.scrollLeft = target + emits('updateArrows') + } + } + + requestAnimationFrame(step) +} + +const emits = defineEmits<{ + (e: 'scroll'): void + (e: 'updateArrows'): void +}>() + const emitScroll = (): void => { emits('scroll') + emits('updateArrows') } const tagsViewStore = useTagsViewStore() @@ -47,16 +82,15 @@ function moveToTarget(currentTag: any): void { let firstTag: any = null let lastTag: any = null - // find first tag and last tag if (visitedViews.value.length > 0) { firstTag = visitedViews.value[0] lastTag = visitedViews.value[visitedViews.value.length - 1] } if (firstTag === currentTag) { - $scrollWrapper.scrollLeft = 0 + smoothScrollTo(0) } else if (lastTag === currentTag) { - $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth + smoothScrollTo($scrollWrapper.scrollWidth - $containerWidth) } else { const tagListDom = document.getElementsByClassName('tags-view-item') const currentIndex = visitedViews.value.findIndex((item: any) => item === currentTag) @@ -75,22 +109,39 @@ function moveToTarget(currentTag: any): void { } if (prevTag && nextTag) { - // the tag's offsetLeft after of nextTag const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value - - // the tag's offsetLeft before of prevTag const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) { - $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth + smoothScrollTo(afterNextTagOffsetLeft - $containerWidth) } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) { - $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft + smoothScrollTo(beforePrevTagOffsetLeft) } } } } +function scrollToStart(): void { + smoothScrollTo(0) +} + +function scrollToEnd(): void { + const $scrollWrapper = scrollWrapper.value + smoothScrollTo($scrollWrapper.scrollWidth - $scrollWrapper.clientWidth) +} + +function getScrollState(): { canLeft: boolean; canRight: boolean } { + const $scrollWrapper = scrollWrapper.value + return { + canLeft: $scrollWrapper.scrollLeft > 0, + canRight: $scrollWrapper.scrollLeft < $scrollWrapper.scrollWidth - $scrollWrapper.clientWidth - 1 + } +} + defineExpose({ moveToTarget, + scrollToStart, + scrollToEnd, + getScrollState }) @@ -100,11 +151,16 @@ defineExpose({ position: relative; overflow: hidden; width: 100%; + height: 100%; :deep(.el-scrollbar__bar) { - bottom: 0px; + display: none; } :deep(.el-scrollbar__wrap) { - height: 39px; + height: 34px; + display: flex; + align-items: center; + overflow-x: auto; + overflow-y: hidden; } } \ No newline at end of file diff --git a/src/layout/components/TagsView/index.vue b/src/layout/components/TagsView/index.vue index d1460ea..203445c 100644 --- a/src/layout/components/TagsView/index.vue +++ b/src/layout/components/TagsView/index.vue @@ -1,6 +1,12 @@