1.创建目录结构
进入cmd,先cd到项目目录(项目vue3-project)
cd vue3-project
mkdir -p src\\views\\home\\components\\menubar
2.创建组件文件
3.编辑menu-item.content.vue
<template>
<template v-if="item.icon">
<i :class="`iconfont el-input__icon ${item.icon}`"
:title="item.title" ></i>
</template>
<span :title="item.title">{{ item.title }}</span>
</template>
<script setup lang="ts">
import { computed } from 'vue';
const props= defineProps({
// 菜单内容
content: null,
});
// 获取父级菜单数据
const item = computed(() => {
return props.content;
});
</script>
<style scoped lang="scss">
.el-menu i.iconfont {
padding-bottom: 2px;
}
</style>
4.编辑menu-item.vue
<template>
<el-menu-item v-if="!item.children || (item.children && item.children.length==0)"
:index="item.path"
:key="item.path" >
<MenuItemContent :content="item" />
</el-menu-item>
<el-sub-menu v-else :index="item.path" :key="item.path">
<template #title>
<MenuItemContent :content="item" />
</template>
<o-menu v-for="data in item.children"
:index="data.path"
:key="data.path"
:content="data" />
</el-sub-menu>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import MenuItemContent from './menu-item-content.vue';
defineOptions({
name:"OMenu"
}
);
const props= defineProps({
// 菜单内容
content: null,
});
// 获取父级菜单数据
const item = computed(() => {
return props.content;
});
</script>
<style scoped lang="scss">
.el-menu-item.is-active, .el-menu-item:hover {
color:white!important;
background-color: #1890ff !important;
}
:deep(.el-sub-menu__title) {
&:hover {
color: #fff !important;
}
}
</style>
5. 编辑menubar.vue
<template>
<el-menu router
:default-active="$route.path"
:unique-opened="true"
text-color='#ffffffb3'
background-color="transparent">
<template v-for="menu in menus">
<MenuItem :content="menu" />
</template>
</el-menu>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import { storeToRefs } from 'pinia';
import { useMenuStore } from '@/store/menu'
import MenuItem from './menu-item.vue';
const menuStore = useMenuStore()
const { menus } = storeToRefs(menuStore)
</script>
<style scoped lang="scss">
</style>
6.添加菜单数据类型定义
types/menu.d.ts
declare interface Meta{
id: string;
name: string;
path: string;
title: string;
}
declare interface MenuMeta extends Meta{
icon?: string;
}
declare interface MenuJsonInfo extends MenuMeta{
parentId: number;
}
declare interface MenuInfo extends MenuMeta{
children?: MenuInfo[];
}
// 菜单信息
declare interface MenuInfoState {
activeName: string;
menu: MenuInfo;
}
7.添加store
stroes/menu.ts
import {defineStore} from 'pinia';
import { MENU_ROOT,MENU_DEFAULT_ACTIVE } from '@/utils/constant';
/**
*
* @methods 设置菜单信息
*/
export const useMenuStore = defineStore('menu',{
persist: true,//本地保存设置
state: (): MenuInfoState => ({
activeName: MENU_DEFAULT_ACTIVE,
menu: {
id: '',
name: '',
title: '',
path: '/',
children: [],
type: 0
},
}),
getters:{
menus(state){
return state.menu.children;
},
root(state){
return MENU_ROOT;
},
},
actions: {
async gen(datas:MenuJsonInfo[]) {
const that = this;
const map = {};
datas.forEach((item: MenuJsonInfo) =>{
map[item.id] = {...item, children: [] };
});
const findParent = (parentId: number, item: MenuJsonInfo)=>{
if(parentId == 0 ){
that.menu.children?.push(map[item.id]);
}else {
const parent = map[parentId.toString()];
if(parent){
parent.children.push(item);
}
}
};
datas.forEach((item: MenuJsonInfo) =>{
findParent(item.parentId, map[item.id]);
});
},
clear(){
this.menu.children =[];
this.activeName = MENU_DEFAULT_ACTIVE;
},
},
});
展示菜单效果: