feat: 添加菜单树结构事例

This commit is contained in:
xiaoxian521 2021-12-16 11:03:20 +08:00
parent eb0771e7ec
commit 10fa0ee8c8
9 changed files with 135 additions and 2 deletions

View File

@ -13,6 +13,8 @@ export function findIconReg(icon: string) {
const faReg = /^FA-/;
// iconfont
const iFReg = /^IF-/;
// remixicon
const riReg = /^RI-/;
// typeof icon === "function" 属于SVG
if (faReg.test(icon)) {
const text = icon.split(faReg)[1];
@ -25,12 +27,14 @@ export function findIconReg(icon: string) {
return findIcon(icon.split(iFReg)[1], "IF");
} else if (typeof icon === "function") {
return findIcon(icon, "SVG");
} else if (riReg.test(icon)) {
return findIcon(icon.split(riReg)[1], "RI");
} else {
return findIcon(icon, "EL");
}
}
// 支持fontawesome、iconfont、element-plus/icons、自定义svg
// 支持fontawesome、iconfont、remixicon、element-plus/icons、自定义svg
export function findIcon(icon: String, type = "EL", property?: string) {
if (type === "FA") {
return defineComponent({
@ -49,6 +53,14 @@ export function findIcon(icon: String, type = "EL", property?: string) {
},
template: `<i :class="icon" />`
});
} else if (type === "RI") {
return defineComponent({
name: "RIIcon",
data() {
return { icon: `ri-${icon}` };
},
template: `<i :class="icon" />`
});
} else if (type === "EL") {
const components = iconComponents.filter(
component => component.name === icon

View File

@ -43,6 +43,7 @@ import {
ElEmpty,
ElCollapse,
ElCollapseItem,
ElTreeV2,
// 指令
ElLoading,
ElInfiniteScroll
@ -94,7 +95,8 @@ const components = [
ElAvatar,
ElEmpty,
ElCollapse,
ElCollapseItem
ElCollapseItem,
ElTreeV2
];
// https://element-plus.org/zh-CN/component/icon.html

View File

@ -43,6 +43,7 @@ export const menusConfig = {
permissionPage: "页面权限",
permissionButton: "按钮权限",
hstabs: "标签页操作",
hsMenuTree: "菜单树结构",
externalLink: "外链"
}
},
@ -80,6 +81,7 @@ export const menusConfig = {
permissionPage: "Page Permission",
permissionButton: "Button Permission",
hstabs: "Tabs Operate",
hsMenuTree: "Menu Tree",
externalLink: "External Link"
}
}

View File

@ -7,6 +7,7 @@ const homeRouter = {
redirect: "/welcome",
meta: {
icon: "HomeFilled",
title: "message.hshome",
showLink: true,
i18n: true,
rank: 0

View File

@ -3,6 +3,7 @@ import homeRouter from "./home";
import errorRouter from "./error";
import editorRouter from "./editor";
import nestedRouter from "./nested";
import menuTreeRouter from "./menuTree";
import externalLink from "./externalLink";
import flowChartRouter from "./flowchart";
import remainingRouter from "./remaining";
@ -22,6 +23,7 @@ const routes = [
nestedRouter,
externalLink,
editorRouter,
menuTreeRouter,
flowChartRouter,
componentsRouter
];

View File

@ -0,0 +1,29 @@
import Layout from "/@/layout/index.vue";
const menuTreeRouter = {
path: "/menuTree",
name: "reMenuTree",
component: Layout,
redirect: "/menuTree/index",
meta: {
icon: "RI-node-tree",
title: "message.hsMenuTree",
i18n: true,
showLink: true,
rank: 9
},
children: [
{
path: "/menuTree/index",
name: "reMenuTree",
component: () => import("/@/views/menu-tree/index.vue"),
meta: {
title: "message.hsMenuTree",
showLink: true,
i18n: true
}
}
]
};
export default menuTreeRouter;

View File

@ -1,6 +1,7 @@
import { defineStore } from "pinia";
import { store } from "/@/store";
import { cacheType } from "./types";
import { cloneDeep } from "lodash-es";
import { RouteConfigs } from "/@/layout/types";
import { constantMenus } from "/@/router/modules";
import { ascending, filterTree } from "/@/router/utils";
@ -12,6 +13,8 @@ export const usePermissionStore = defineStore({
constantMenus,
// 整体路由生成的菜单(静态、动态)
wholeMenus: [],
// 深拷贝一个菜单树,与导航菜单不突出
menusTree: [],
buttonAuth: [],
// 缓存页面keepAlive
cachePageList: []
@ -24,6 +27,10 @@ export const usePermissionStore = defineStore({
ascending(this.constantMenus.concat(routes))
);
this.menusTree = cloneDeep(
filterTree(ascending(this.constantMenus.concat(routes)))
);
const getButtonAuth = (arrRoutes: Array<RouteConfigs>) => {
if (!arrRoutes || !arrRoutes.length) return;
arrRoutes.forEach((v: RouteConfigs) => {

42
src/utils/tree.ts Normal file
View File

@ -0,0 +1,42 @@
/**
* path
* @param {Object} {menuTree }
* @param {return}} expandedPaths path组成的数组
*/
const expandedPaths = [];
export function extractPathList(menuTree) {
if (!Array.isArray(menuTree)) {
console.warn("menuTree must be an array");
return;
}
if (!menuTree || menuTree.length === 0) return;
for (const node of menuTree) {
const hasChildren = node.children && node.children.length > 0;
if (hasChildren) {
extractPathList(node.children);
}
expandedPaths.push(node.path);
}
return expandedPaths;
}
/**
* children的length为1children
* @param {Object} {menuTree }
* @param {return}}
*/
export function deleteChildren(menuTree) {
if (!Array.isArray(menuTree)) {
console.warn("menuTree must be an array");
return;
}
if (!menuTree || menuTree.length === 0) return;
for (const node of menuTree) {
if (node.children && node.children.length === 1) delete node.children;
const hasChildren = node.children && node.children.length > 0;
if (hasChildren) {
deleteChildren(node.children);
}
}
return menuTree;
}

View File

@ -0,0 +1,36 @@
<script lang="ts">
export default {
name: "reMenuTree"
};
</script>
<script setup lang="ts">
import { ref, computed } from "vue";
import { extractPathList, deleteChildren } from "/@/utils/tree";
import { usePermissionStoreHook } from "/@/store/modules/permission";
let dataProps = ref({
value: "path",
children: "children"
});
let menusData = computed(() => {
return deleteChildren(usePermissionStoreHook().menusTree);
});
let expandedKeys = extractPathList(menusData.value);
</script>
<template>
<el-tree-v2
:data="menusData"
:props="dataProps"
show-checkbox
:height="500"
:default-expanded-keys="expandedKeys"
>
<template #default="{ data }">
<span>{{ $t(data.meta.title) }}</span>
</template>
</el-tree-v2>
</template>