mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-03-01 00:23:11 +08:00
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user