diff --git a/src/layout/components/TagsView/ScrollPane.vue b/src/layout/components/TagsView/ScrollPane.vue index c5f25cd..4f2434f 100644 --- a/src/layout/components/TagsView/ScrollPane.vue +++ b/src/layout/components/TagsView/ScrollPane.vue @@ -1,10 +1,19 @@ <script lang="ts" setup> -import { computed, ref } from "vue" +import { type PropType, computed, ref, watch, nextTick } from "vue" +import { RouterLink, useRoute } from "vue-router" import { ElScrollbar } from "element-plus" import { ArrowLeft, ArrowRight } from "@element-plus/icons-vue" import { useSettingsStore } from "@/store/modules/settings" import Screenfull from "@/components/Screenfull/index.vue" +const props = defineProps({ + tagRefs: { + type: Object as PropType<InstanceType<typeof RouterLink>[]>, + required: true + } +}) + +const route = useRoute() const settingsStore = useSettingsStore() const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>() @@ -20,6 +29,7 @@ const scroll = ({ scrollLeft }: { scrollLeft: number }) => { currentScrollLeft = scrollLeft } +/** 鼠标滚轮滚动时触发 */ const wheelScroll = ({ deltaY }: WheelEvent) => { if (/^-/.test(deltaY.toString())) { scrollTo("left") @@ -28,24 +38,70 @@ const wheelScroll = ({ deltaY }: WheelEvent) => { } } -/** 点击滚动 */ -const scrollTo = (direction: "left" | "right") => { - let scrollLeft = 0 +/** 获取可能需要的宽度 */ +const getWidth = () => { /** 可滚动内容的长度 */ const scrollbarContentRefWidth = scrollbarContentRef.value!.clientWidth /** 滚动可视区宽度 */ const scrollbarRefWidth = scrollbarRef.value!.wrapRef!.clientWidth /** 最后剩余可滚动的宽度 */ const lastDistance = scrollbarContentRefWidth - scrollbarRefWidth - currentScrollLeft + + return { scrollbarContentRefWidth, scrollbarRefWidth, lastDistance } +} + +/** 左右滚动 */ +const scrollTo = (direction: "left" | "right", distance: number = translateDistance) => { + let scrollLeft = 0 + const { scrollbarContentRefWidth, scrollbarRefWidth, lastDistance } = getWidth() // 没有横向滚动条,直接结束 if (scrollbarRefWidth > scrollbarContentRefWidth) return if (direction === "left") { - scrollLeft = Math.max(0, currentScrollLeft - translateDistance) + scrollLeft = Math.max(0, currentScrollLeft - distance) } else { - scrollLeft = Math.min(currentScrollLeft + translateDistance, currentScrollLeft + lastDistance) + scrollLeft = Math.min(currentScrollLeft + distance, currentScrollLeft + lastDistance) } scrollbarRef.value!.setScrollLeft(scrollLeft) } + +/** 移动到目标位置 */ +const moveTo = () => { + const tagRefs = props.tagRefs + for (let i = 0; i < tagRefs.length; i++) { + // @ts-ignore + if (route.path === tagRefs[i].$props.to.path) { + // @ts-ignore + const el: HTMLElement = tagRefs[i].$el + const offsetWidth = el.offsetWidth + const offsetLeft = el.offsetLeft + const { scrollbarRefWidth } = getWidth() + // 当前 tag 在可视区域左边时 + if (offsetLeft < currentScrollLeft) { + const distance = currentScrollLeft - offsetLeft + scrollTo("left", distance) + return + } + // 当前 tag 在可视区域右边时 + const width = scrollbarRefWidth + currentScrollLeft - offsetWidth + if (offsetLeft > width) { + const distance = offsetLeft - width + scrollTo("right", distance) + return + } + } + } +} + +watch( + route, + () => { + nextTick(moveTo) + }, + { + deep: true + } +) + const showScreenfull = computed(() => { return settingsStore.showScreenfull }) diff --git a/src/layout/components/TagsView/index.vue b/src/layout/components/TagsView/index.vue index 97338b9..a49fb22 100644 --- a/src/layout/components/TagsView/index.vue +++ b/src/layout/components/TagsView/index.vue @@ -1,6 +1,6 @@ <script lang="ts" setup> import { getCurrentInstance, onMounted, ref, watch } from "vue" -import { type RouteRecordRaw, useRoute, useRouter } from "vue-router" +import { type RouteRecordRaw, RouterLink, useRoute, useRouter } from "vue-router" import { type ITagView, useTagsViewStore } from "@/store/modules/tags-view" import { usePermissionStore } from "@/store/modules/permission" import ScrollPane from "./ScrollPane.vue" @@ -13,6 +13,8 @@ const route = useRoute() const tagsViewStore = useTagsViewStore() const permissionStore = usePermissionStore() +const tagRefs = ref<InstanceType<typeof RouterLink>[]>([]) + const visible = ref(false) const top = ref(0) const left = ref(0) @@ -161,8 +163,9 @@ onMounted(() => { <template> <div class="tags-view-container"> - <ScrollPane class="tags-view-wrapper"> + <ScrollPane class="tags-view-wrapper" :tagRefs="tagRefs"> <router-link + ref="tagRefs" v-for="tag in tagsViewStore.visitedViews" :key="tag.path" :class="isActive(tag) ? 'active' : ''"