菜单栏配置化
图标配置化参考vite动态配置svg图标及其他方式集合
咱分为两个组件,一个母组件menu
,还有个子组件sub-menu
(兼容多级菜单,递归使用)
components/menu/index.vue
<script lang="ts" src="./index.ts">script>
<template>
<el-menu
class="el-menu-demo"
:default-active="activeIndex"
:text-color="textColor"
:active-text-color="activeTextColor"
:background-color="bgColor"
:mode="mode"
:unique-opened="uniqueOpened"
:collapse="collapse"
:router="router"
:ellipsis="ellipsis"
@select="handleSelect"
>
<template v-for="item in menuList" :key="item + 'menu' + item.index">
<SubMenu :menu="item">SubMenu>
template>
el-menu>
template>
components/menu/index.ts
import { computed, defineComponent } from "vue";
import type { MenuType } from "@/interface/index";
import { IndexHooks } from "@/composables";
import SvgIcon from "@/components/svg-icon/index.vue";
import { translateRouteTitle } from "@/lang";
import SubMenu from "./sub-menu/index.vue";
export default defineComponent({
components: {
SvgIcon,
SubMenu,
},
props: {
/**
* 菜单列表
*/
menuList: {
type: Array<MenuType>,
default: [
{
title: "菜单一",
index: "0",
icon: "document",
subMenu: [
{
title: "子单一",
icon: "document",
index: "0-0",
subMenu: [
{ title: "子单2.1", icon: "document", index: "0-0-0" },
{
title: "子单2.1",
icon: "document",
index: "0-0-1",
subMenu: [
{ title: "子单2.1.1", icon: "document", index: "0-0-1-0" },
{ title: "子单2.1.2", icon: "document", index: "0-0-1-1" },
],
},
],
},
{ title: "子单二", icon: "document", index: "0-1" },
],
},
{
title: "菜单二",
index: "1",
icon: "document",
subMenu: [
{ title: "子单一", icon: "document", index: "1-0" },
{ title: "子单二", icon: "document", index: "1-1" },
],
},
{
title: "菜单三",
index: "2",
icon: "document",
},
],
},
/**
* 菜单展示模式
*/
mode: {
type: String,
default: "vertical", // horizontal - 横向 / vertical - 纵向
},
/**
* 是否水平折叠收起菜单(仅在 mode 为 vertical 时可用)
*/
collapse: {
type: Boolean,
default: false,
},
/**
* 是否省略多余的子项(仅在横向模式生效)
*/
ellipsis: {
type: Boolean,
default: false,
},
/**
* 菜单的背景颜色(十六进制格式)(已被废弃,使用--bg-color)
*/
bgColor: {
type: String,
default: "#545c64",
},
/**
* 文字颜色(十六进制格式)(已被废弃,使用--text-color)
*/
textColor: {
type: String,
default: "#fff",
},
/**
* 活动菜单项的文本颜色(十六进制格式)(已被废弃,使用--active-color)
*/
activeTextColor: {
type: String,
default: "#ffd04b",
},
/**
* 菜单高亮显示index
*/
active: {
type: String,
default: "0-1",
},
/**
* 是否只保持一个子菜单的展开
*/
uniqueOpened: {
type: Boolean,
default: false,
},
/**
* 是否启用 vue-router 模式。 启用该模式会在激活导航时以 index 作为 path 进行路由跳转 使用 default-active 来设置加载时的激活项。
*/
router: {
type: Boolean,
default: false,
},
},
setup(props, { emit }) {
const activeIndex = computed({
get: () => props.active,
set: (val) => {
emit("update:active", val);
},
});
const { menuList } = props;
const inDepthValueOfArray = (
arr: Array<MenuType>,
indexs: Array<string>
): Array<MenuType> | MenuType | undefined => {
const index = Number(indexs[0]);
if (indexs.length > 1) {
const val = arr[index].subMenu;
indexs.shift();
return val && inDepthValueOfArray(val, indexs);
} else if (indexs.length === 1) {
return arr[index];
} else {
return arr;
}
};
const { goTo } = IndexHooks();
const handleSelect = (key: string, keyPath: string[]) => {
if (!menuList) return;
const indexs = key.split("-");
activeIndex.value = indexs[0];
const MenuType = inDepthValueOfArray(menuList, indexs);
if (MenuType && !(MenuType instanceof Array)) {
// goTo(MenuType?.path || "/", { t: new Date().getTime() });
}
};
return {
activeIndex,
translateRouteTitle,
handleSelect,
};
},
});
components/menu/sub-menu/index.vue
<script lang="ts" src="./index.js">script>
<template>
<el-sub-menu v-if="menu.subMenu" :index="menu.index">
<template #title>
<SvgIcon v-if="menu.icon" :icon-class="menu.icon" />
{{ translateRouteTitle(menu.title) }}
template>
<template
v-for="subItem in menu.subMenu"
:key="subItem + 'subItem' + menu.index">
<SubMenu :menu="subItem" />
template>
el-sub-menu>
<el-menu-item v-else :index="menu.index">
<SvgIcon v-if="menu.icon" :icon-class="menu.icon" />
{{ translateRouteTitle(menu.title) }}
el-menu-item>
template>
components/menu/sub-menu/index.ts
import { defineComponent } from "vue";
import SvgIcon from "@/components/svg-icon/index.vue";
import { translateRouteTitle } from "@/lang";
export default defineComponent({
name: "SubMenu",
components: {
SvgIcon,
},
props: {
menu: {
type: Object,
required: true,
default: {
title: "子单一",
icon: "document",
index: "0-0",
subMenu: [
{ title: "子单2.1", icon: "document", index: "0-0-0" },
{ title: "子单2.1", icon: "document", index: "0-0-1" },
],
},
},
},
setup() {
return {
translateRouteTitle,
};
},
});
咱直接以默认值做例子,具体数据可自定义,格式需以menu组件定义的,不然会报错
<script lang="ts" src="./index.ts" />
<template>
<Menu />
template>
import { defineComponent, reactive, ref } from "vue";
import Menu from "@/components/menu/index.vue";
export default defineComponent({
components: {
Menu,
},
setup() {
return {
};
},
});
如有启发,可点赞收藏哟~