Files
vue3-element-admin/src/layout/components/Sidebar/components/SidebarMenuItem/index.vue
2024-02-14 16:44:35 +08:00

190 lines
4.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div v-if="!item.meta || !item.meta.hidden">
<!-- 显示具有单个子路由的菜单项或没有子路由的父路由 -->
<template
v-if="
hasOneShowingChild(item.children, item as RouteRecordRaw) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
!item.meta?.alwaysShow
"
>
<AppLink v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item
:index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
>
<MenuIconTitle
:icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)"
:title="onlyOneChild.meta.title"
/>
</el-menu-item>
</AppLink>
</template>
<!-- 显示具有多个子路由的父菜单项 -->
<el-sub-menu v-else :index="resolvePath(item.path)" teleported>
<template #title>
<MenuIconTitle
v-if="item.meta"
:icon="item.meta && item.meta.icon"
:title="item.meta.title"
/>
</template>
<SidebarMenuItem
v-for="child in item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
/>
</el-sub-menu>
</div>
</template>
<script setup lang="ts">
defineOptions({
name: "SidebarMenuItem",
inheritAttrs: false,
});
import path from "path-browserify";
import { isExternal } from "@/utils/index";
import { RouteRecordRaw } from "vue-router";
const props = defineProps({
/**
* 路由(eg:user)
*/
item: {
type: Object,
required: true,
},
/**
* 父层级完整路由路径(eg:/system)
*/
basePath: {
type: String,
required: true,
},
isNest: {
type: Boolean,
default: false,
},
});
const onlyOneChild = ref(); // 临时变量,唯一子路由
/**
* 判断当前路由是否只有一个子路由
*
* 1如果只有一个子路由 返回 true
* 2如果无子路由 :返回 true
*
* @param children 子路由数组
* @param parent 当前路由
*/
function hasOneShowingChild(
children: RouteRecordRaw[] = [],
parent: RouteRecordRaw
) {
// 子路由集合
const showingChildren = children.filter((route: RouteRecordRaw) => {
if (route.meta?.hidden) {
// 过滤不显示的子路由
return false;
} else {
route.meta!.hidden = false;
// 临时变量(多个子路由 onlyOneChild 变量是用不上的)
onlyOneChild.value = route;
return true;
}
});
// 如果只有一个子路由, 返回 true
if (showingChildren.length === 1) {
return true;
}
// 如果没有子路由,显示父级路由
if (showingChildren.length === 0) {
onlyOneChild.value = { ...parent, path: "", noShowingChildren: true };
return true;
}
return false;
}
/**
* 解析路由路径(相对路径 → 绝对路径)
*
* @param routePath 路由路径
*/
function resolvePath(routePath: string) {
if (isExternal(routePath)) {
return routePath;
}
if (isExternal(props.basePath)) {
return props.basePath;
}
// 完整路径(/system/user) = 父级路径(/system) + 路由路径(user)
const fullPath = path.resolve(props.basePath, routePath);
return fullPath;
}
</script>
<style lang="scss">
.hideSidebar {
.submenu-title-noDropdown {
position: relative;
padding: 0 !important;
.el-tooltip {
padding: 0 !important;
.sub-el-icon {
margin-left: 19px;
}
}
& > span {
display: inline-block;
width: 0;
height: 0;
overflow: hidden;
visibility: hidden;
}
}
.el-sub-menu {
overflow: hidden;
& > .el-sub-menu__title {
padding: 0 !important;
.sub-el-icon {
margin-left: 19px;
}
.el-sub-menu__icon-arrow {
display: none;
}
}
}
.el-menu--collapse {
.el-sub-menu {
& > .el-sub-menu__title {
& > span {
display: inline-block;
width: 0;
height: 0;
overflow: hidden;
visibility: hidden;
}
}
}
}
}
</style>