fix: 修改TagsView样式问题

This commit is contained in:
戴业伟 2024-02-05 11:07:48 +08:00
parent 6fff76e3f8
commit 58337f771e

View File

@ -2,8 +2,8 @@
<div <div
class="box-border tabs-view" class="box-border tabs-view"
:class="{ :class="{
'tabs-view-fix': state.multiTabsSetting.fixed, 'tabs-view-fix': multiTabsSetting.fixed,
'tabs-view-fixed-header': state.isMultiHeaderFixed, 'tabs-view-fixed-header': isMultiHeaderFixed,
'tabs-view-default-background': getDarkTheme === false, 'tabs-view-default-background': getDarkTheme === false,
'tabs-view-dark-background': getDarkTheme === true, 'tabs-view-dark-background': getDarkTheme === true,
}" }"
@ -13,11 +13,11 @@
<div <div
ref="navWrap" ref="navWrap"
class="tabs-card" class="tabs-card"
:class="{ 'tabs-card-scrollable': state.scrollable }" :class="{ 'tabs-card-scrollable': scrollable }"
> >
<span <span
class="tabs-card-prev" class="tabs-card-prev"
:class="{ 'tabs-card-prev-hide': !state.scrollable }" :class="{ 'tabs-card-prev-hide': !scrollable }"
@click="scrollPrev" @click="scrollPrev"
> >
<n-icon size="16" color="#515a6e"> <n-icon size="16" color="#515a6e">
@ -26,7 +26,7 @@
</span> </span>
<span <span
class="tabs-card-next" class="tabs-card-next"
:class="{ 'tabs-card-next-hide': !state.scrollable }" :class="{ 'tabs-card-next-hide': !scrollable }"
@click="scrollNext" @click="scrollNext"
> >
<n-icon size="16" color="#515a6e"> <n-icon size="16" color="#515a6e">
@ -44,7 +44,7 @@
<div <div
:id="`tag${element.fullPath.split('/').join('\/')}`" :id="`tag${element.fullPath.split('/').join('\/')}`"
class="tabs-card-scroll-item" class="tabs-card-scroll-item"
:class="{ 'active-item': state.activeKey === element.fullPath }" :class="{ 'active-item': activeKey === element.fullPath }"
@click.stop="goPage(element)" @click.stop="goPage(element)"
@contextmenu="handleContextMenu($event, element)" @contextmenu="handleContextMenu($event, element)"
> >
@ -76,9 +76,9 @@
</n-dropdown> </n-dropdown>
</div> </div>
<n-dropdown <n-dropdown
:show="state.showDropdown" :show="showDropdown"
:x="state.dropdownX" :x="dropdownX"
:y="state.dropdownY" :y="dropdownY"
@clickoutside="onClickOutside" @clickoutside="onClickOutside"
placement="bottom-start" placement="bottom-start"
@select="closeHandleSelect" @select="closeHandleSelect"
@ -88,13 +88,26 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts">
import {
defineComponent,
reactive,
computed,
ref,
toRefs,
provide,
watch,
onMounted,
nextTick,
} from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { storage } from '@/utils'; import { storage } from '@/utils';
import { StorageEnum } from '@/enums/storageEnum';
import { useTabsViewStore } from '@/store/modules/tabsView'; import { useTabsViewStore } from '@/store/modules/tabsView';
import { useAsyncRouteStore } from '@/store/modules/asyncRoute'; import { useAsyncRouteStore } from '@/store/modules/asyncRoute';
import { RouteItem } from '@/store/modules/tabsView'; import { RouteItem } from '@/store/modules/tabsView';
import { useProjectSetting } from '@/hooks/setting/useProjectSetting'; import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
import { useMessage } from 'naive-ui';
import Draggable from 'vuedraggable'; import Draggable from 'vuedraggable';
import { PageEnum } from '@/enums/pageEnum'; import { PageEnum } from '@/enums/pageEnum';
import { import {
@ -107,42 +120,53 @@ import {
RightOutlined, RightOutlined,
} from '@vicons/antd'; } from '@vicons/antd';
import { renderIcon } from '@/utils'; 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';
import { useThemeVars } from 'naive-ui'; import { useThemeVars } from 'naive-ui';
import { useGo } from '@/hooks/web/usePage'; import { useGo } from '@/hooks/web/usePage';
import { StorageEnum } from '@/enums/storageEnum';
const props = defineProps({ export default defineComponent({
name: 'TabsView',
components: {
DownOutlined,
CloseOutlined,
LeftOutlined,
RightOutlined,
Draggable,
},
props: {
collapsed: { collapsed: {
type: Boolean, type: Boolean,
}, },
}); },
const { getDarkTheme, getAppTheme } = useDesignSetting(); setup(props) {
const { navMode, headerSetting, menuSetting, multiTabsSetting, isMobile } = const { getDarkTheme, getAppTheme } = useDesignSetting();
const { navMode, headerSetting, menuSetting, multiTabsSetting, isMobile } =
useProjectSetting(); useProjectSetting();
const settingStore = useProjectSettingStore(); const settingStore = useProjectSettingStore();
const route = useRoute(); const message = useMessage();
const router = useRouter(); const route = useRoute();
const tabsViewStore = useTabsViewStore(); const router = useRouter();
const asyncRouteStore = useAsyncRouteStore(); const tabsViewStore = useTabsViewStore();
const navScroll: any = ref(null); const asyncRouteStore = useAsyncRouteStore();
const navWrap: any = ref(null); const navScroll: any = ref(null);
const isCurrent = ref(false); const navWrap: any = ref(null);
const go = useGo(); const isCurrent = ref(false);
const go = useGo();
const themeVars = useThemeVars(); const themeVars = useThemeVars();
const getCardColor = computed(() => { const getcardcolor = computed(() => {
return themeVars.value.cardColor; return themeVars.value.cardColor;
}); });
const getBaseColor = computed(() => { const getbasecolor = computed(() => {
return themeVars.value.textColor1; return themeVars.value.textColor1;
}); });
const state = reactive({ const state = reactive({
activeKey: route.fullPath, activeKey: route.fullPath,
scrollable: false, scrollable: false,
dropdownX: 0, dropdownX: 0,
@ -150,15 +174,15 @@ const state = reactive({
showDropdown: false, showDropdown: false,
isMultiHeaderFixed: false, isMultiHeaderFixed: false,
multiTabsSetting: multiTabsSetting, multiTabsSetting: multiTabsSetting,
}); });
// //
const getSimpleRoute = (route): RouteItem => { const getSimpleRoute = (route): RouteItem => {
const { fullPath, hash, meta, name, params, path, query } = route; const { fullPath, hash, meta, name, params, path, query } = route;
return { fullPath, hash, meta, name, params, path, query }; return { fullPath, hash, meta, name, params, path, query };
}; };
const isMixMenuNoneSub = computed(() => { const isMixMenuNoneSub = computed(() => {
const mixMenu = settingStore.menuSetting.mixMenu; const mixMenu = settingStore.menuSetting.mixMenu;
const currentRoute = useRoute(); const currentRoute = useRoute();
if (navMode.value != 'horizontal-mix') return true; if (navMode.value != 'horizontal-mix') return true;
@ -167,10 +191,10 @@ const isMixMenuNoneSub = computed(() => {
mixMenu && mixMenu &&
currentRoute.meta.isRoot currentRoute.meta.isRoot
); );
}); });
// //
const getChangeStyle = computed(() => { const getChangeStyle = computed(() => {
const { collapsed } = props; const { collapsed } = props;
const { minMenuWidth, menuWidth }: any = menuSetting.value; const { minMenuWidth, menuWidth }: any = menuSetting.value;
const { fixed }: any = multiTabsSetting.value; const { fixed }: any = multiTabsSetting.value;
@ -191,10 +215,10 @@ const getChangeStyle = computed(() => {
left: lenNum, left: lenNum,
width: `calc(100% - ${!fixed ? '0px' : lenNum})`, width: `calc(100% - ${!fixed ? '0px' : lenNum})`,
}; };
}); });
//tags //tags
const TabsMenuOptions = computed(() => { const TabsMenuOptions = computed(() => {
const isDisabled = tabsList.value.length <= 1; const isDisabled = tabsList.value.length <= 1;
return [ return [
{ {
@ -221,35 +245,35 @@ const TabsMenuOptions = computed(() => {
icon: renderIcon(MinusOutlined), icon: renderIcon(MinusOutlined),
}, },
]; ];
}); });
let cacheRoutes: RouteItem[] = []; let cacheRoutes: RouteItem[] = [];
const simpleRoute = getSimpleRoute(route); const simpleRoute = getSimpleRoute(route);
try { try {
const routesStr = storage.get(StorageEnum.ZS_TABS_ROUTES) as const routesStr = storage.get(StorageEnum.ZS_TABS_ROUTES) as
| string | string
| null | null
| undefined; | undefined;
cacheRoutes = routesStr ? JSON.parse(routesStr) : [simpleRoute]; cacheRoutes = routesStr ? JSON.parse(routesStr) : [simpleRoute];
} catch (e) { } catch (e) {
cacheRoutes = [simpleRoute]; cacheRoutes = [simpleRoute];
} }
// localStorage // localStorage
const routes = router.getRoutes(); const routes = router.getRoutes();
cacheRoutes.forEach((cacheRoute) => { cacheRoutes.forEach((cacheRoute) => {
const route = routes.find((route) => route.path === cacheRoute.path); const route = routes.find((route) => route.path === cacheRoute.path);
if (route) { if (route) {
cacheRoute.meta = route.meta || cacheRoute.meta; cacheRoute.meta = route.meta || cacheRoute.meta;
cacheRoute.name = (route.name || cacheRoute.name) as string; cacheRoute.name = (route.name || cacheRoute.name) as string;
} }
}); });
// //
tabsViewStore.initTabs(cacheRoutes); tabsViewStore.initTabs(cacheRoutes);
// //
function onScroll(e) { function onScroll(e) {
let scrollTop = let scrollTop =
e.target.scrollTop || e.target.scrollTop ||
document.documentElement.scrollTop || document.documentElement.scrollTop ||
@ -260,12 +284,12 @@ function onScroll(e) {
multiTabsSetting.value.fixed && multiTabsSetting.value.fixed &&
scrollTop >= 64 scrollTop >= 64
); );
} }
window.addEventListener('scroll', onScroll, true); window.addEventListener('scroll', onScroll, true);
// //
const delKeepAliveCompName = () => { const delKeepAliveCompName = () => {
if (route.meta.keepAlive) { if (route.meta.keepAlive) {
const name = router.currentRoute.value.matched.find( const name = router.currentRoute.value.matched.find(
(item) => item.name == route.name (item) => item.name == route.name
@ -275,17 +299,17 @@ const delKeepAliveCompName = () => {
asyncRouteStore.keepAliveComponents.filter((item) => item != name); asyncRouteStore.keepAliveComponents.filter((item) => item != name);
} }
} }
}; };
// //
const tabsList: any = computed(() => tabsViewStore.tabsList); const tabsList: any = computed(() => tabsViewStore.tabsList);
const whiteList: string[] = [ const whiteList: string[] = [
PageEnum.BASE_LOGIN_NAME, PageEnum.BASE_LOGIN_NAME,
PageEnum.REDIRECT_NAME, PageEnum.REDIRECT_NAME,
PageEnum.ERROR_PAGE_NAME, PageEnum.ERROR_PAGE_NAME,
]; ];
watch( watch(
() => route.fullPath, () => route.fullPath,
(to) => { (to) => {
if (whiteList.includes(route.name as string)) return; if (whiteList.includes(route.name as string)) return;
@ -294,73 +318,74 @@ watch(
updateNavScroll(true); updateNavScroll(true);
}, },
{ immediate: true } { immediate: true }
); );
// //
window.addEventListener('beforeunload', () => { window.addEventListener('beforeunload', () => {
storage.set(StorageEnum.ZS_TABS_ROUTES, JSON.stringify(tabsList.value)); storage.set(StorageEnum.ZS_TABS_ROUTES, JSON.stringify(tabsList.value));
}); });
// //
const removeTab = (route) => { const removeTab = (route) => {
if (tabsList.value.length === 1) { if (tabsList.value.length === 1) {
return window['$message'].warning('这已经是最后一页,不能再关闭了!'); return message.warning('这已经是最后一页,不能再关闭了!');
} }
delKeepAliveCompName(); delKeepAliveCompName();
tabsViewStore.closeCurrentTab(route); tabsViewStore.closeCurrentTab(route);
// //
if (state.activeKey === route.fullPath) { if (state.activeKey === route.fullPath) {
const currentRoute = tabsList.value[Math.max(0, tabsList.value.length - 1)]; const currentRoute =
tabsList.value[Math.max(0, tabsList.value.length - 1)];
state.activeKey = currentRoute.fullPath; state.activeKey = currentRoute.fullPath;
router.push(currentRoute); router.push(currentRoute);
} }
updateNavScroll(); updateNavScroll();
}; };
// //
const reloadPage = () => { const reloadPage = () => {
delKeepAliveCompName(); delKeepAliveCompName();
router.push({ router.push({
path: '/redirect' + route.fullPath, path: '/redirect' + route.fullPath,
}); });
}; };
// //
provide('reloadPage', reloadPage); provide('reloadPage', reloadPage);
// //
const closeLeft = (route) => { const closeLeft = (route) => {
tabsViewStore.closeLeftTabs(route); tabsViewStore.closeLeftTabs(route);
state.activeKey = route.fullPath; state.activeKey = route.fullPath;
router.replace(route.fullPath); router.replace(route.fullPath);
updateNavScroll(); updateNavScroll();
}; };
// //
const closeRight = (route) => { const closeRight = (route) => {
tabsViewStore.closeRightTabs(route); tabsViewStore.closeRightTabs(route);
state.activeKey = route.fullPath; state.activeKey = route.fullPath;
router.replace(route.fullPath); router.replace(route.fullPath);
updateNavScroll(); updateNavScroll();
}; };
// //
const closeOther = (route) => { const closeOther = (route) => {
tabsViewStore.closeOtherTabs(route); tabsViewStore.closeOtherTabs(route);
state.activeKey = route.fullPath; state.activeKey = route.fullPath;
router.replace(route.fullPath); router.replace(route.fullPath);
updateNavScroll(); updateNavScroll();
}; };
// //
const closeAll = () => { const closeAll = () => {
tabsViewStore.closeAllTabs(); tabsViewStore.closeAllTabs();
router.replace(PageEnum.BASE_HOME); router.replace(PageEnum.BASE_HOME);
updateNavScroll(); updateNavScroll();
}; };
//tab //tab
const closeHandleSelect = (key) => { const closeHandleSelect = (key) => {
switch (key) { switch (key) {
// //
case '1': case '1':
@ -381,13 +406,13 @@ const closeHandleSelect = (key) => {
} }
updateNavScroll(); updateNavScroll();
state.showDropdown = false; state.showDropdown = false;
}; };
/** /**
* @param value 要滚动到的位置 * @param value 要滚动到的位置
* @param amplitude 每次滚动的长度 * @param amplitude 每次滚动的长度
*/ */
function scrollTo(value: number, amplitude: number) { function scrollTo(value: number, amplitude: number) {
const currentScroll = navScroll.value.scrollLeft; const currentScroll = navScroll.value.scrollLeft;
const scrollWidth = const scrollWidth =
(amplitude > 0 && currentScroll + amplitude >= value) || (amplitude > 0 && currentScroll + amplitude >= value) ||
@ -397,9 +422,9 @@ function scrollTo(value: number, amplitude: number) {
navScroll.value && navScroll.value.scrollTo(scrollWidth, 0); navScroll.value && navScroll.value.scrollTo(scrollWidth, 0);
if (scrollWidth === value) return; if (scrollWidth === value) return;
return window.requestAnimationFrame(() => scrollTo(value, amplitude)); return window.requestAnimationFrame(() => scrollTo(value, amplitude));
} }
function scrollPrev() { function scrollPrev() {
const containerWidth = navScroll.value.offsetWidth; const containerWidth = navScroll.value.offsetWidth;
const currentScroll = navScroll.value.scrollLeft; const currentScroll = navScroll.value.scrollLeft;
@ -407,9 +432,9 @@ function scrollPrev() {
const scrollLeft = const scrollLeft =
currentScroll > containerWidth ? currentScroll - containerWidth : 0; currentScroll > containerWidth ? currentScroll - containerWidth : 0;
scrollTo(scrollLeft, (scrollLeft - currentScroll) / 20); scrollTo(scrollLeft, (scrollLeft - currentScroll) / 20);
} }
function scrollNext() { function scrollNext() {
const containerWidth = navScroll.value.offsetWidth; const containerWidth = navScroll.value.offsetWidth;
const navWidth = navScroll.value.scrollWidth; const navWidth = navScroll.value.scrollWidth;
const currentScroll = navScroll.value.scrollLeft; const currentScroll = navScroll.value.scrollLeft;
@ -420,12 +445,12 @@ function scrollNext() {
? currentScroll + containerWidth ? currentScroll + containerWidth
: navWidth - containerWidth; : navWidth - containerWidth;
scrollTo(scrollLeft, (scrollLeft - currentScroll) / 20); scrollTo(scrollLeft, (scrollLeft - currentScroll) / 20);
} }
/** /**
* @param autoScroll 是否开启自动滚动功能 * @param autoScroll 是否开启自动滚动功能
*/ */
async function updateNavScroll(autoScroll?: boolean) { async function updateNavScroll(autoScroll?: boolean) {
await nextTick(); await nextTick();
if (!navScroll.value) return; if (!navScroll.value) return;
const containerWidth = navScroll.value.offsetWidth; const containerWidth = navScroll.value.offsetWidth;
@ -446,13 +471,13 @@ async function updateNavScroll(autoScroll?: boolean) {
} else { } else {
state.scrollable = false; state.scrollable = false;
} }
} }
function handleResize() { function handleResize() {
updateNavScroll(true); updateNavScroll(true);
} }
function handleContextMenu(e, item) { function handleContextMenu(e, item) {
e.preventDefault(); e.preventDefault();
isCurrent.value = PageEnum.BASE_HOME === item.path; isCurrent.value = PageEnum.BASE_HOME === item.path;
state.showDropdown = false; state.showDropdown = false;
@ -461,36 +486,66 @@ function handleContextMenu(e, item) {
state.dropdownX = e.clientX; state.dropdownX = e.clientX;
state.dropdownY = e.clientY; state.dropdownY = e.clientY;
}); });
} }
function onClickOutside() { function onClickOutside() {
state.showDropdown = false; state.showDropdown = false;
} }
//tags //tags
function goPage(e) { function goPage(e) {
const { fullPath } = e; const { fullPath } = e;
if (fullPath === route.fullPath) return; if (fullPath === route.fullPath) return;
state.activeKey = fullPath; state.activeKey = fullPath;
go(e, true); go(e, true);
} }
//tab //tab
function closeTabItem(e) { function closeTabItem(e) {
const { fullPath } = e; const { fullPath } = e;
const routeInfo = tabsList.value.find((item) => item.fullPath == fullPath); const routeInfo = tabsList.value.find(
(item) => item.fullPath == fullPath
);
removeTab(routeInfo); removeTab(routeInfo);
} }
onMounted(() => { onMounted(() => {
// onElementResize(); // onElementResize();
}); });
// function onElementResize() { // function onElementResize() {
// let observer; // let observer;
// observer = elementResizeDetectorMaker(); // observer = elementResizeDetectorMaker();
// observer.listenTo(navWrap.value, handleResize); // observer.listenTo(navWrap.value, handleResize);
// } // }
return {
...toRefs(state),
navWrap,
navScroll,
route,
tabsList,
goPage,
closeTabItem,
closeLeft,
closeRight,
closeOther,
closeAll,
reloadPage,
getChangeStyle,
TabsMenuOptions,
closeHandleSelect,
scrollNext,
scrollPrev,
handleContextMenu,
onClickOutside,
getDarkTheme,
getAppTheme,
getcardcolor,
getbasecolor,
};
},
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>