feat: TagsView自动滚动功能

This commit is contained in:
devlemoe
2021-08-19 11:56:56 +08:00
parent a0490e3b97
commit 8c7dd14004
+49 -49
View File
@@ -30,10 +30,10 @@
</n-icon> </n-icon>
</span> </span>
<div ref="navScroll" class="tabs-card-scroll"> <div ref="navScroll" class="tabs-card-scroll">
<div ref="navRef" class="tabs-card-nav" :style="getNavStyle">
<Draggable :list="tabsList" animation="300" item-key="fullPath" class="flex"> <Draggable :list="tabsList" animation="300" item-key="fullPath" class="flex">
<template #item="{ element }"> <template #item="{ element }">
<div <div
:id="`tag${element.fullPath.split('/').join('\/')}`"
class="tabs-card-scroll-item" class="tabs-card-scroll-item"
:class="{ 'active-item': activeKey === element.path }" :class="{ 'active-item': activeKey === element.path }"
@click.stop="goPage(element)" @click.stop="goPage(element)"
@@ -43,7 +43,7 @@
<n-icon <n-icon
size="14" size="14"
@click.stop="closeTabItem(element)" @click.stop="closeTabItem(element)"
v-if="element.path != baseHome" v-if="element.path !== baseHome"
> >
<CloseOutlined /> <CloseOutlined />
</n-icon> </n-icon>
@@ -52,7 +52,6 @@
</Draggable> </Draggable>
</div> </div>
</div> </div>
</div>
<div class="tabs-close"> <div class="tabs-close">
<n-dropdown <n-dropdown
trigger="hover" trigger="hover"
@@ -87,7 +86,6 @@
computed, computed,
ref, ref,
toRefs, toRefs,
toRaw,
unref, unref,
provide, provide,
watch, watch,
@@ -143,7 +141,6 @@
const router = useRouter(); const router = useRouter();
const tabsViewStore = useTabsViewStore(); const tabsViewStore = useTabsViewStore();
const asyncRouteStore = useAsyncRouteStore(); const asyncRouteStore = useAsyncRouteStore();
const navRef: any = ref(null);
const navScroll: any = ref(null); const navScroll: any = ref(null);
const navWrap: any = ref(null); const navWrap: any = ref(null);
const isCurrent = ref(false); const isCurrent = ref(false);
@@ -281,7 +278,9 @@
if (whiteList.includes(route.name as string)) return; if (whiteList.includes(route.name as string)) return;
state.activeKey = to; state.activeKey = to;
tabsViewStore.addTabs(getSimpleRoute(route)); tabsViewStore.addTabs(getSimpleRoute(route));
updateNavScroll(); nextTick().then(() => {
updateNavScroll(true);
});
}, },
{ immediate: true } { immediate: true }
); );
@@ -374,58 +373,70 @@
state.showDropdown = false; state.showDropdown = false;
}; };
function getCurrentScrollOffset() { /**
const { navStyle } = state; * @param value 要滚动到的位置
const transform: any = toRaw(navStyle.transform); * @param amplitude 每次滚动的长度
return transform ? Number(transform.match(/translateX\(-(\d+(\.\d+)*)px\)/)[1]) : 0; */
} function scrollTo(value: number, amplitude: number) {
const currentScroll = navScroll.value.scrollLeft;
function setOffset(value) { const scrollWidth =
state.navStyle.transform = `translateX(-${value}px)`; (amplitude > 0 && currentScroll + amplitude >= value) ||
(amplitude < 0 && currentScroll + amplitude <= value)
? value
: currentScroll + amplitude;
navScroll.value && navScroll.value.scrollTo(scrollWidth, 0);
if (scrollWidth === value) return;
return window.requestAnimationFrame(() => scrollTo(value, amplitude));
} }
function scrollPrev() { function scrollPrev() {
const containerWidth = navScroll.value.offsetWidth; const containerWidth = navScroll.value.offsetWidth;
const currentOffset = getCurrentScrollOffset(); const currentScroll = navScroll.value.scrollLeft;
if (!currentOffset) return;
let newOffset = currentOffset > containerWidth ? currentOffset - containerWidth : 0; if (!currentScroll) return;
setOffset(newOffset); const scrollLeft = currentScroll > containerWidth ? currentScroll - containerWidth : 0;
scrollTo(scrollLeft, (scrollLeft - currentScroll) / 20);
} }
function scrollNext() { function scrollNext() {
const navWidth = navRef.value.scrollWidth;
const containerWidth = navScroll.value.offsetWidth; const containerWidth = navScroll.value.offsetWidth;
const currentOffset = getCurrentScrollOffset(); const navWidth = navScroll.value.scrollWidth;
if (navWidth - currentOffset <= containerWidth) return; const currentScroll = navScroll.value.scrollLeft;
let newOffset = if (navWidth - currentScroll <= containerWidth) return;
navWidth - currentOffset > containerWidth * 2 const scrollLeft =
? currentOffset + containerWidth navWidth - currentScroll > containerWidth * 2
? currentScroll + containerWidth
: navWidth - containerWidth; : navWidth - containerWidth;
scrollTo(scrollLeft, (scrollLeft - currentScroll) / 20);
setOffset(newOffset);
} }
function updateNavScroll() { /**
if (!navRef.value) return; * @param autoScroll 是否开启自动滚动功能
let navWidth = navRef.value.scrollWidth; */
let containerWidth = navScroll.value.offsetWidth; function updateNavScroll(autoScroll?: boolean) {
const currentOffset = getCurrentScrollOffset(); if (!navScroll.value) return;
const containerWidth = navScroll.value.offsetWidth;
const navWidth = navScroll.value.scrollWidth;
if (containerWidth < navWidth) { if (containerWidth < navWidth) {
state.scrollable = true; state.scrollable = true;
if (navWidth - currentOffset < containerWidth) { if (autoScroll) {
setOffset(navWidth - containerWidth); let tagList = navScroll.value.querySelectorAll('.tabs-card-scroll-item') || [];
[...tagList].forEach((tag: HTMLElement) => {
// fix SyntaxError
if (tag.id === `tag${state.activeKey.split('/').join('\/')}`) {
tag.scrollIntoView && tag.scrollIntoView();
}
});
} }
} else { } else {
state.scrollable = false; state.scrollable = false;
if (currentOffset > 0) {
setOffset(0);
}
} }
} }
function handleResize() { function handleResize() {
updateNavScroll(); updateNavScroll(true);
} }
const getNavStyle = computed(() => { const getNavStyle = computed(() => {
@@ -475,7 +486,6 @@
return { return {
...toRefs(state), ...toRefs(state),
navWrap, navWrap,
navRef,
navScroll, navScroll,
route, route,
tabsList, tabsList,
@@ -552,18 +562,8 @@
} }
&-scroll { &-scroll {
overflow: hidden;
white-space: nowrap; white-space: nowrap;
overflow: hidden;
.tabs-card-nav {
padding-left: 0;
margin: 0;
float: left;
list-style: none;
box-sizing: border-box;
position: relative;
transition: transform 0.5s ease-in-out;
}
&-item { &-item {
background: var(--color); background: var(--color);