diff --git a/src/layout/components/TagsView/ScrollPane.vue b/src/layout/components/TagsView/ScrollPane.vue index 0189a17..c7c25ce 100644 --- a/src/layout/components/TagsView/ScrollPane.vue +++ b/src/layout/components/TagsView/ScrollPane.vue @@ -17,6 +17,8 @@ const { proxy } = getCurrentInstance() const scrollWrapper = computed(() => proxy.$refs.scrollContainer.$refs.wrapRef) +const emits = defineEmits(['scroll', 'updateArrows']) + onMounted(() => { scrollWrapper.value.addEventListener('scroll', emitScroll, true) }) @@ -25,15 +27,46 @@ onBeforeUnmount(() => { scrollWrapper.value.removeEventListener('scroll', emitScroll) }) +const emitScroll = () => { + emits('scroll') + emits('updateArrows') +} + +function smoothScrollTo(target) { + const $scrollWrapper = scrollWrapper.value + const start = $scrollWrapper.scrollLeft + const distance = target - start + const duration = 300 + let startTime = null + + // easeInOutQuad + function ease(t, b, c, d) { + t /= d / 2 + if (t < 1) return c / 2 * t * t + b + t-- + return -c / 2 * (t * (t - 2) - 1) + b + } + + function step(timestamp) { + 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) +} + function handleScroll(e) { const eventDelta = e.wheelDelta || -e.deltaY * 40 const $scrollWrapper = scrollWrapper.value $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4 -} - -const emits = defineEmits() -const emitScroll = () => { - emits('scroll') + emits('updateArrows') } const tagsViewStore = useTagsViewStore() @@ -47,16 +80,15 @@ function moveToTarget(currentTag) { let firstTag = null let lastTag = 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 => item === currentTag) @@ -72,22 +104,38 @@ function moveToTarget(currentTag) { } } } - - // 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() { + smoothScrollTo(0) +} + +function scrollToEnd() { + const $scrollWrapper = scrollWrapper.value + smoothScrollTo($scrollWrapper.scrollWidth - $scrollWrapper.clientWidth) +} + +function getScrollState() { + const $scrollWrapper = scrollWrapper.value + return { + canLeft: $scrollWrapper.scrollLeft > 0, + canRight: $scrollWrapper.scrollLeft < $scrollWrapper.scrollWidth - $scrollWrapper.clientWidth - 1 + } +} + defineExpose({ moveToTarget, + scrollToStart, + scrollToEnd, + getScrollState }) @@ -97,11 +145,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 6ffd914..e0ece10 100644 --- a/src/layout/components/TagsView/index.vue +++ b/src/layout/components/TagsView/index.vue @@ -1,6 +1,12 @@