如何vue实现动态菜单
Vue 实现动态菜单的方法
使用路由配置动态菜单
在 Vue 项目中,可以通过路由配置动态生成菜单。路由配置通常存储在 router/index.js 中,菜单数据可以根据路由信息动态渲染。
// router/index.js
const routes = [
{
path: '/dashboard',
name: 'Dashboard',
meta: { title: 'Dashboard', icon: 'el-icon-menu' }
},
{
path: '/user',
name: 'User',
meta: { title: 'User Management', icon: 'el-icon-user' }
}
]
在组件中通过 this.$router.options.routes 获取路由配置,动态渲染菜单:
<template>
<div>
<el-menu>
<el-menu-item
v-for="route in routes"
:key="route.name"
:index="route.path"
>
<i :class="route.meta.icon"></i>
<span>{{ route.meta.title }}</span>
</el-menu-item>
</el-menu>
</div>
</template>
<script>
export default {
computed: {
routes() {
return this.$router.options.routes
}
}
}
</script>
从后端 API 获取菜单数据
动态菜单数据通常由后端返回,通过 API 请求获取菜单数据后渲染。
// 假设 API 返回格式如下
[
{ path: '/dashboard', name: 'Dashboard', meta: { title: 'Dashboard', icon: 'icon-dashboard' } },
{ path: '/user', name: 'User', meta: { title: 'User', icon: 'icon-user' } }
]
在 Vue 组件中调用 API 并渲染菜单:

<template>
<div>
<el-menu>
<el-menu-item
v-for="item in menuList"
:key="item.name"
:index="item.path"
>
<i :class="item.meta.icon"></i>
<span>{{ item.meta.title }}</span>
</el-menu-item>
</el-menu>
</div>
</template>
<script>
import { getMenuList } from '@/api/menu'
export default {
data() {
return {
menuList: []
}
},
created() {
this.fetchMenuData()
},
methods: {
async fetchMenuData() {
const { data } = await getMenuList()
this.menuList = data
}
}
}
</script>
使用 Vuex 管理菜单状态
对于复杂的应用,可以使用 Vuex 集中管理菜单状态,方便全局共享和更新。
// store/modules/menu.js
const state = {
menuList: []
}
const mutations = {
SET_MENU_LIST(state, list) {
state.menuList = list
}
}
const actions = {
async fetchMenuList({ commit }) {
const { data } = await getMenuList()
commit('SET_MENU_LIST', data)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
在组件中通过 Vuex 获取和更新菜单数据:

<template>
<div>
<el-menu>
<el-menu-item
v-for="item in menuList"
:key="item.name"
:index="item.path"
>
<i :class="item.meta.icon"></i>
<span>{{ item.meta.title }}</span>
</el-menu-item>
</el-menu>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
...mapState('menu', ['menuList'])
},
created() {
this.fetchMenuList()
},
methods: {
...mapActions('menu', ['fetchMenuList'])
}
}
</script>
递归渲染多级菜单
如果菜单包含多级嵌套结构,可以通过递归组件实现。
定义递归组件 SubMenu.vue:
<template>
<el-submenu :index="item.path">
<template #title>
<i :class="item.meta.icon"></i>
<span>{{ item.meta.title }}</span>
</template>
<template v-for="child in item.children">
<sub-menu
v-if="child.children"
:key="child.path"
:item="child"
/>
<el-menu-item v-else :key="child.path" :index="child.path">
<i :class="child.meta.icon"></i>
<span>{{ child.meta.title }}</span>
</el-menu-item>
</template>
</el-submenu>
</template>
<script>
export default {
name: 'SubMenu',
props: {
item: {
type: Object,
required: true
}
}
}
</script>
在主菜单组件中使用递归组件:
<template>
<el-menu>
<template v-for="item in menuList">
<sub-menu v-if="item.children" :key="item.path" :item="item" />
<el-menu-item v-else :key="item.path" :index="item.path">
<i :class="item.meta.icon"></i>
<span>{{ item.meta.title }}</span>
</el-menu-item>
</template>
</el-menu>
</template>
<script>
import SubMenu from './SubMenu'
export default {
components: { SubMenu },
computed: {
...mapState('menu', ['menuList'])
}
}
</script>
注意事项
- 确保菜单数据的
path与路由配置一致,否则导航可能失效。 - 对于权限控制,可以在菜单数据或路由配置中添加
roles字段,过滤无权限的菜单项。 - 图标可以使用字体图标(如 Element UI 的图标)或自定义 SVG 图标。






