feat: 项目结构重构优化
This commit is contained in:
245
src/layouts/components/LayoutSidebar.vue
Normal file
245
src/layouts/components/LayoutSidebar.vue
Normal file
@@ -0,0 +1,245 @@
|
||||
<!-- 闖懷黒扈<EFBFBD>サカ -->
|
||||
<template>
|
||||
<el-menu
|
||||
ref="menuRef"
|
||||
:default-active="activeMenuPath"
|
||||
:collapse="!appStore.sidebar.opened"
|
||||
:background-color="menuThemeProps.backgroundColor"
|
||||
:text-color="menuThemeProps.textColor"
|
||||
:active-text-color="menuThemeProps.activeTextColor"
|
||||
:popper-effect="theme"
|
||||
:unique-opened="false"
|
||||
:collapse-transition="false"
|
||||
:mode="menuMode"
|
||||
@open="onMenuOpen"
|
||||
@close="onMenuClose"
|
||||
>
|
||||
<!-- 闖懷黒鬘?-->
|
||||
<LayoutSidebarItem
|
||||
v-for="route in data"
|
||||
:key="route.path"
|
||||
:item="route"
|
||||
:base-path="resolveFullPath(route.path)"
|
||||
/>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRoute } from "vue-router";
|
||||
import path from "path-browserify";
|
||||
import type { MenuInstance } from "element-plus";
|
||||
import type { RouteRecordRaw } from "vue-router";
|
||||
import { SidebarColor } from "@/enums/settings";
|
||||
import { useSettingsStore, useAppStore } from "@/store";
|
||||
import { isExternal } from "@/utils/index";
|
||||
import LayoutSidebarItem from "./LayoutSidebarItem.vue";
|
||||
import variables from "@/styles/variables.module.scss";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array as PropType<RouteRecordRaw[]>,
|
||||
default: () => [],
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
example: "/system",
|
||||
},
|
||||
menuMode: {
|
||||
type: String as PropType<"vertical" | "horizontal">,
|
||||
default: "vertical",
|
||||
validator: (value: string) => ["vertical", "horizontal"].includes(value),
|
||||
},
|
||||
});
|
||||
|
||||
const menuRef = ref<MenuInstance>();
|
||||
const settingsStore = useSettingsStore();
|
||||
const appStore = useAppStore();
|
||||
const currentRoute = useRoute();
|
||||
|
||||
// 蟄伜お蟾イ螻募シ逧<C280>除蜊暮。ケ邏「蠑<EFBDA2>
|
||||
const expandedMenuIndexes = ref<string[]>([]);
|
||||
|
||||
// 闔キ蜿紋クサ鬚<EFBDBB>
|
||||
const theme = computed(() => settingsStore.theme);
|
||||
|
||||
// 闔キ蜿匁オ<E58C81>牡荳サ鬚倅ク狗噪萓ァ霎ケ譬城<E8ADAC>濶イ譁ケ譯?
|
||||
const sidebarColorScheme = computed(() => settingsStore.sidebarColorScheme);
|
||||
|
||||
// 闖懷黒荳サ鬚伜ア樊?
|
||||
const menuThemeProps = computed(() => {
|
||||
const isDarkOrClassicBlue =
|
||||
theme.value === "dark" || sidebarColorScheme.value === SidebarColor.CLASSIC_BLUE;
|
||||
|
||||
return {
|
||||
backgroundColor: isDarkOrClassicBlue ? variables["menu-background"] : undefined,
|
||||
textColor: isDarkOrClassicBlue ? variables["menu-text"] : undefined,
|
||||
activeTextColor: isDarkOrClassicBlue ? variables["menu-active-text"] : undefined,
|
||||
};
|
||||
});
|
||||
|
||||
// 隶。邂怜ス灘燕豼豢サ逧<EFBDBB>除蜊暮。?
|
||||
const activeMenuPath = computed((): string => {
|
||||
const { meta, path } = currentRoute;
|
||||
|
||||
// 螯よ棡霍ッ逕アmeta荳ュ隶セ鄂ョ莠<EFBDAE>ctiveMenu<6E>悟<EFBFBD>菴ソ逕ィ螳<EFBDA8>シ育畑莠主、<E4B8BB>炊荳莠帷音谿頑ュ蜀オ<E89C80>悟ヲりッヲ諠<EFBDA6>。オ<EFBDA1>?
|
||||
if (meta?.activeMenu && typeof meta.activeMenu === "string") {
|
||||
return meta.activeMenu;
|
||||
}
|
||||
|
||||
// 蜷ヲ蛻吩スソ逕ィ蠖灘燕霍ッ逕ア霍ッ蠕<EFBDAF>
|
||||
return path;
|
||||
});
|
||||
|
||||
/**
|
||||
* 闔キ蜿門ョ梧紛霍ッ蠕<EFBDAF>
|
||||
*
|
||||
* @param routePath 蠖灘燕霍ッ逕ア逧<EFBDB1>嶌蟇ケ霍ッ蠕? /user
|
||||
* @returns 螳梧紛逧<E7B49B>サ晏ッケ霍ッ蠕?D://vue3-element-admin/system/user
|
||||
*/
|
||||
function resolveFullPath(routePath: string) {
|
||||
if (isExternal(routePath)) {
|
||||
return routePath;
|
||||
}
|
||||
if (isExternal(props.basePath)) {
|
||||
return props.basePath;
|
||||
}
|
||||
|
||||
// 螯よ棡 basePath 荳コ遨コ<E981A8>磯。カ驛ィ蟶<EFBDA8>ア<EFBDB1>会シ檎峩謗・霑泌屓 routePath
|
||||
if (!props.basePath || props.basePath === "") {
|
||||
return routePath;
|
||||
}
|
||||
|
||||
// 隗」譫占キッ蠕<EFBDAF>シ檎函謌仙ョ梧紛逧<E7B49B>サ晏ッケ霍ッ蠕<EFBDAF>
|
||||
return path.resolve(props.basePath, routePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 謇灘シ闖懷黒
|
||||
*
|
||||
* @param index 蠖灘燕螻募シ逧<C280>除蜊暮。ケ邏「蠑<EFBDA2>
|
||||
*/
|
||||
const onMenuOpen = (index: string) => {
|
||||
expandedMenuIndexes.value.push(index);
|
||||
};
|
||||
|
||||
/**
|
||||
* 蜈ウ髣ュ闖懷黒
|
||||
*
|
||||
* @param index 蠖灘燕謾カ襍キ逧<EFBDB7>除蜊暮。ケ邏「蠑<EFBDA2>
|
||||
*/
|
||||
const onMenuClose = (index: string) => {
|
||||
expandedMenuIndexes.value = expandedMenuIndexes.value.filter((item) => item !== index);
|
||||
};
|
||||
|
||||
/**
|
||||
* 逶大成螻募シ逧<C280>除蜊暮。ケ蜿伜喧<E4BC9C>梧峩譁ー辷カ闖懷黒譬キ蠑<EFBDB7>
|
||||
*/
|
||||
watch(
|
||||
() => expandedMenuIndexes.value,
|
||||
() => {
|
||||
updateParentMenuStyles();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 逶大成闖懷黒讓。蠑丞序蛹厄シ壼ス楢除蜊墓ィ。蠑丞<E8A091>謐「荳コ豌エ蟷ウ讓。蠑乗慮<E4B997>悟<EFBFBD>髣ュ謇譛牙ア募シ逧<C280>除蜊暮。ケ<EFBDA1>?
|
||||
* 驕ソ蜈榊惠豌エ蟷ウ讓。蠑丈ク玖除蜊暮。ケ譏セ遉コ髞吩ス阪?
|
||||
*/
|
||||
watch(
|
||||
() => props.menuMode,
|
||||
(newMode) => {
|
||||
if (newMode === "horizontal" && menuRef.value) {
|
||||
expandedMenuIndexes.value.forEach((item) => menuRef.value!.close(item));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 逶大成豼豢サ闖懷黒蜿伜喧<E4BC9C>御クコ蛹<EFBDBA>性豼豢サ蟄占除蜊慕噪辷カ闖懷黒豺サ蜉<EFBDBB>譬キ蠑冗ア?
|
||||
*/
|
||||
watch(
|
||||
() => activeMenuPath.value,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
updateParentMenuStyles();
|
||||
});
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* 逶大成霍ッ逕ア蜿伜喧<E4BC9C>檎。ョ菫晁除蜊戊<E89C8A>髫週agsView蛻<77>困閠梧ュ」遑ョ豼豢?
|
||||
*/
|
||||
watch(
|
||||
() => currentRoute.path,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
updateParentMenuStyles();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 譖エ譁ー辷カ闖懷黒譬キ蠑?- 荳コ蛹<EFBDBA>性豼豢サ蟄占除蜊慕噪辷カ闖懷黒豺サ蜉<EFBDBB> has-active-child 邀?
|
||||
*/
|
||||
function updateParentMenuStyles() {
|
||||
if (!menuRef.value?.$el) return;
|
||||
|
||||
nextTick(() => {
|
||||
try {
|
||||
const menuEl = menuRef.value?.$el as HTMLElement;
|
||||
if (!menuEl) return;
|
||||
|
||||
// 遘サ髯、謇譛臥鴫譛臥噪 has-active-child 邀?
|
||||
const allSubMenus = menuEl.querySelectorAll(".el-sub-menu");
|
||||
allSubMenus.forEach((subMenu) => {
|
||||
subMenu.classList.remove("has-active-child");
|
||||
});
|
||||
|
||||
// 譟・謇セ蠖灘燕豼豢サ逧<EFBDBB>除蜊暮。?
|
||||
const activeMenuItem = menuEl.querySelector(".el-menu-item.is-active");
|
||||
|
||||
if (activeMenuItem) {
|
||||
// 蜷台ク頑衍謇セ辷カ郤ァ el-sub-menu 蜈<>エ<EFBFBD>
|
||||
let parent = activeMenuItem.parentElement;
|
||||
while (parent && parent !== menuEl) {
|
||||
if (parent.classList.contains("el-sub-menu")) {
|
||||
parent.classList.add("has-active-child");
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
} else {
|
||||
// 豌エ蟷ウ讓。蠑丈ク句庄閭ス髴隕∫音谿雁、<E99B81><EFBDA4>?
|
||||
if (props.menuMode === "horizontal") {
|
||||
// 蟇ケ莠取ーエ蟷ウ闖懷黒<E687B7>御スソ逕ィ霍ッ蠕<EFBDAF>源驟肴擂謇セ蛻ー辷カ闖懷<E99796>?
|
||||
const currentPath = activeMenuPath.value;
|
||||
|
||||
// 譟・謇セ謇譛臥宛闖懷黒鬘ケ<E9AC98>梧」譟・蜩ェ荳ェ蛹<EFBDAA>性蠖灘燕霍ッ蠕?
|
||||
allSubMenus.forEach((subMenu) => {
|
||||
const subMenuEl = subMenu as HTMLElement;
|
||||
const subMenuPath =
|
||||
subMenuEl.getAttribute("data-path") ||
|
||||
subMenuEl.querySelector(".el-sub-menu__title")?.getAttribute("data-path");
|
||||
|
||||
// 螯よ棡謇セ蛻ー蛹<EFBDB0>性蠖灘燕霍ッ蠕<EFBDAF>噪辷カ闖懷黒<E687B7>悟<EFBFBD>豺サ蜉<EFBDBB>豼豢サ邀サ
|
||||
if (subMenuPath && currentPath.startsWith(subMenuPath)) {
|
||||
subMenuEl.classList.add("has-active-child");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating parent menu styles:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 扈<>サカ謖りスス蜷守ォ句叉譖エ譁ー辷カ闖懷黒譬キ蠑<EFBDB7>
|
||||
*/
|
||||
onMounted(() => {
|
||||
// 遑ョ菫晏惠扈<E683A0>サカ謖りスス蜷取峩譁ー譬キ蠑擾シ御ク堺セ晁オ紋コ主シよュ・謫堺ス?
|
||||
updateParentMenuStyles();
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user