Merge pull request #33 from devlemoe/main

feat: TagsView自动滚动功能
This commit is contained in:
Ah jung
2021-09-15 17:11:01 +08:00
committed by GitHub
+56 -68
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,
@@ -113,7 +111,7 @@
LeftOutlined, LeftOutlined,
RightOutlined, RightOutlined,
} from '@vicons/antd'; } from '@vicons/antd';
import { renderIcon } from '@/utils/index'; import { renderIcon } from '@/utils';
import elementResizeDetectorMaker from 'element-resize-detector'; import elementResizeDetectorMaker from 'element-resize-detector';
import { useDesignSetting } from '@/hooks/setting/useDesignSetting'; import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
import { useProjectSettingStore } from '@/store/modules/projectSetting'; import { useProjectSettingStore } from '@/store/modules/projectSetting';
@@ -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);
@@ -151,9 +148,6 @@
const state = reactive({ const state = reactive({
activeKey: route.fullPath, activeKey: route.fullPath,
scrollable: false, scrollable: false,
navStyle: {
transform: '',
},
dropdownX: 0, dropdownX: 0,
dropdownY: 0, dropdownY: 0,
showDropdown: false, showDropdown: false,
@@ -172,10 +166,7 @@
const currentRoute = useRoute(); const currentRoute = useRoute();
const navMode = unref(getNavMode); const navMode = unref(getNavMode);
if (unref(navMode) != 'horizontal-mix') return true; if (unref(navMode) != 'horizontal-mix') return true;
if (unref(navMode) === 'horizontal-mix' && mixMenu && currentRoute.meta.isRoot) { return !(unref(navMode) === 'horizontal-mix' && mixMenu && currentRoute.meta.isRoot);
return false;
}
return true;
}); });
//动态组装样式 菜单缩进 //动态组装样式 菜单缩进
@@ -198,7 +189,7 @@
//tags 右侧下拉菜单 //tags 右侧下拉菜单
const TabsMenuOptions = computed(() => { const TabsMenuOptions = computed(() => {
const isDisabled = unref(tabsList).length <= 1 ? true : false; const isDisabled = unref(tabsList).length <= 1;
return [ return [
{ {
label: '刷新当前', label: '刷新当前',
@@ -245,11 +236,11 @@
document.documentElement.scrollTop || document.documentElement.scrollTop ||
window.pageYOffset || window.pageYOffset ||
document.body.scrollTop; // 滚动条偏移量 document.body.scrollTop; // 滚动条偏移量
if (!getHeaderSetting.fixed && getMultiTabsSetting.fixed && scrollTop >= 64) { state.isMultiHeaderFixed = !!(
state.isMultiHeaderFixed = true; !getHeaderSetting.fixed &&
} else { getMultiTabsSetting.fixed &&
state.isMultiHeaderFixed = false; scrollTop >= 64
} );
} }
window.addEventListener('scroll', onScroll, true); window.addEventListener('scroll', onScroll, true);
@@ -281,7 +272,7 @@
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(); updateNavScroll(true);
}, },
{ immediate: true } { immediate: true }
); );
@@ -374,64 +365,73 @@
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; async function updateNavScroll(autoScroll?: boolean) {
const currentOffset = getCurrentScrollOffset(); await nextTick();
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(() => {
return state.navStyle;
});
function handleContextMenu(e, item) { function handleContextMenu(e, item) {
e.preventDefault(); e.preventDefault();
isCurrent.value = PageEnum.BASE_HOME_REDIRECT === item.path; isCurrent.value = PageEnum.BASE_HOME_REDIRECT === item.path;
@@ -475,7 +475,6 @@
return { return {
...toRefs(state), ...toRefs(state),
navWrap, navWrap,
navRef,
navScroll, navScroll,
route, route,
tabsList, tabsList,
@@ -492,7 +491,6 @@
closeHandleSelect, closeHandleSelect,
scrollNext, scrollNext,
scrollPrev, scrollPrev,
getNavStyle,
handleContextMenu, handleContextMenu,
onClickOutside, onClickOutside,
getDarkTheme, getDarkTheme,
@@ -552,18 +550,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);