文章目录
- 前提条件
- 假设菜单等级只有两个等级
- 结果如下所示
- 但是如果菜单等级超过两个等级或者多个等级的话
- App.vue
- MenuItems.vue
- 结果如下所示
- 关于遍历时图标前的展示后续完善
- 关于点击路由跳转参考element plus的官网即可
前提条件
package.json如下所示,这是一个Vite + Vue3 + TS的项目
{
"name": "vue3-ts-vite-wen-zhang-ji-lu-xiang-mu",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"element-plus": "^2.4.2",
"vue": "^3.3.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.3",
"sass": "^1.69.5",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vue-tsc": "^1.8.5"
}
}
下面为了方便,直接在App.vue组件中,代码结构如下所示,就一纯净项目,然后直接在App.vue中写代码
假设菜单等级只有两个等级
如果菜单等级只有两个等级,那就没有必要使用到递归了,直接遍历,然后根据是否有children字段,判断是一级菜单还是二级菜单就可以了。具体代码如下所示:
<template>
<div style="width: 100%; height: 100%;">
<div class="common-layout">
<el-container>
<el-header>头部</el-header>
<el-container>
<!-- 侧边栏区域 -->
<el-aside width="200px">
<el-menu default-active="2" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose">
<template v-for="(item, index) in menuList" :key="index">
<el-sub-menu :index="item.path" v-if="item.children && item.children.length">
<template #title>
<el-icon>
<location />
</el-icon>
<span>{{ item.name }}</span>
</template>
<el-menu-item v-for="child in item.children" :key="child.id" :index="child.path">
{{ child.name }}
</el-menu-item>
</el-sub-menu>
<el-menu-item v-else :index="item.path">
<el-icon><setting /></el-icon>
<span>{{ item.name }}</span>
</el-menu-item>
</template>
</el-menu>
</el-aside>
<!-- 主题区域 -->
<el-main>
这是主题区域
</el-main>
</el-container>
</el-container>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Location, Setting } from '@element-plus/icons-vue'
interface MenuItem {
id: number;
name: string;
path: string;
icon?: string;
component?: string;
children?: MenuItem[];
}
const menuList = ref<MenuItem[]>(
[
{
id: 1,
name: '首页',
path: '/',
icon: 'location',
component: 'home',
children: []
},
{
id: 2,
name: '用户管理',
path: '/user',
icon: 'location',
component: 'user',
children: [
{
id: 3,
name: '用户列表',
path: 'list',
icon: '',
component: 'userList',
children: []
},
{
id: 5,
name: '角色列表',
path: 'roleList',
icon: '',
component: 'userList',
children: []
}
]
},
{
id: 6,
name: '权限管理',
path: '/permission',
icon: 'setting',
component: 'permission',
children: [
{
id: 7,
name: '权限列表',
path: 'permissionList',
icon: '',
component: 'permissionList',
}
]
}
]
)
const handleOpen = (key: string, keyPath: string[]) => {
console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
console.log(key, keyPath)
}
</script>
<style scoped lang="scss">
.el-container {
width: 100%;
height: 100%;
}
</style>
结果如下所示
但是如果菜单等级超过两个等级或者多个等级的话
但是如果菜单等级超过两个等级或者多个等级的话,这时就可以使用到组件递归的方式进行了。目录结构如下所示:
App.vue
<template>
<div style="width: 100%; height: 100%;">
<div class="common-layout">
<el-container>
<el-header>头部</el-header>
<el-container>
<!-- 侧边栏区域 -->
<el-aside width="200px">
<el-menu default-active="2" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose">
<menu-items :items="menuList"></menu-items>
</el-menu>
</el-aside>
<!-- 主题区域 -->
<el-main>
这是主题区域
</el-main>
</el-container>
</el-container>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MenuItems from './components/MenuItems.vue'
interface MenuItem {
id: number;
name: string;
path: string;
icon?: string;
component?: string;
children?: MenuItem[];
}
const menuList = ref<MenuItem[]>(
[
{
id: 1,
name: '首页',
path: '/',
icon: 'location',
component: 'home',
children: []
},
{
id: 2,
name: '用户管理',
path: '/user',
icon: 'location',
component: 'user',
children: [
{
id: 3,
name: '用户列表',
path: 'list',
icon: '',
component: 'userList',
children: [
{
id: 4,
name: '用户详情',
path: 'userDetail',
icon: '',
component: 'userDetail',
children: []
}
]
},
{
id: 5,
name: '角色列表',
path: 'roleList',
icon: '',
component: 'userList',
children: []
}
]
},
{
id: 6,
name: '权限管理',
path: '/permission',
icon: 'setting',
component: 'permission',
children: [
{
id: 7,
name: '权限列表',
path: 'permissionList',
icon: '',
component: 'permissionList',
children: [
{
id: 8,
name: '权限详情-1',
path: 'permissionDetail',
icon: '',
component: 'permissionDetail',
children: [
{
id: 9,
name: '权限详情-2',
path: 'permissionDetail2',
icon: '',
component: 'permissionDetail2',
children: []
}
]
}
]
}
]
}
]
)
const handleOpen = (key: string, keyPath: string[]) => {
console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
console.log(key, keyPath)
}
</script>
<style scoped lang="scss">
.el-container {
width: 100%;
height: 100%;
}
</style>
MenuItems.vue
<template>
<template v-for="item in items" :key="item.id">
<el-sub-menu v-if="item.children && item.children.length > 0" :index="item.path">
<template #title>
<span>{{ item.name }}</span>
</template>
<!-- 递归遍历 -->
<menu-items :items="item.children" />
</el-sub-menu>
<el-menu-item v-else :index="item.path">
<span>{{ item.name }}</span>
</el-menu-item>
</template>
</template>
<script setup lang="ts">
interface MenuItem {
id: number;
name: string;
path: string;
icon?: string;
component?: string;
children?: MenuItem[];
}
defineProps<{
items: MenuItem[];
}>()
</script>
结果如下所示
从图中可以看出,无论是一层,二层,三层,四层结构的树形数据,都可以在el-menu中展示。