😀大家好!我是向阳🌞,一个想成为优秀全栈开发工程师的有志青年!	
📔今天来说一说如何实现vue-router动态路由菜单。

1.前言

在后台管理系统或复杂前端应用中,动态路由菜单是不可缺少的。它需要根据用户权限、业务场景动态展示不同的导航结构。本文将手把手教你如何利用Vue Router的meta字段和Ant Design Vue的菜单组件,实现灵活的动态路由菜单。

在没有实现动态路由的时候,你只能重新在头部菜单栏一个一个再添加上你需要展示的菜单项,但使用动态路由后,你不再需要在routes.ts中写一遍,再到头部菜单栏写一遍。’

本篇文章代码是使用ant-design-vue组件vue-router完成的。

2.实现步骤

2.1.路由初始化

我们这里把要使用的路由和配置分离开来,不直接写在createRouter中,因为我们后面要对routes进行过滤。
在这里插入图片描述
index.ts代码演示:

const router = createRouter({
  history: createWebHistory(),
  routes,
})

2.2.路由配置与meta字段设计

过滤的核心就是使用vue-router提供的属性meta来进行过滤,看下面的代码中,我们的登录页面和注册页面是不需要展示在头部导航栏上的,所以我们来给他们指定一个hideInMenu属性,当设置为true时,则进行隐藏不展示。

routes.ts代码演示:

export const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: '主页',
    component: HomePage,
    meta: {
      icon: () => h(HomeOutlined),
    },
  },
  {
    path: '/user/login',
    name: '用户登录',
    component: UserLoginPage,
    meta: {
      hideInMenu: true,
      access: ACCESS_ENUM.NOT_LOGIN,
    },
  },
  {
    path: '/user/register',
    name: '用户注册',
    component: UserRegisterPage,
    meta: {
      hideInMenu: true,
      access: ACCESS_ENUM.NOT_LOGIN,
    },
  },
]

2.3. 菜单过滤

接下来,我们在头部导航栏组件中获取routes,使用计算属性computed进行动态计算过滤,如果路由中meta中的hideInMenu属性为true,则返回false,因为filter过滤是将返回true的元素保留下来,最后我们将获取到的元素进行转换,转换为菜单组件展示需要的元素属性。

其中有一行代码是进行权限校验,如果我们这里不做介绍,直接忽略掉即可。

// 过滤菜单项
import { routes } from '@/router/routes.ts'

const items = computed(() => {
  return routes
    .filter((item) => {
      if (item?.meta?.hideInMenu) {
        return false
      }
      // 根据权限过滤菜单,有权限则返回 true,则保留该菜单
      // return checkAccess(loginUserStore.loginUser, item?.meta?.access as string)
      return true
    })
    .map(menuToRouteItem) // 转换为菜单项格式
})

转换代码中,如果有孩子节点则进行进一步的转换,这样就可以完成菜单过滤了。

// 把路由项转换为菜单项
const menuToRouteItem = (item: any) => {
  const isHome = item.path === '/'
  return {
    key: item.path,
    label: item.name,
    title: item.name,
    icon: h(item.meta?.icon) ?? undefined,
    children: item.children?.map((child: any) => menuToRouteItem(child)),
  }
}

const menus = ref<MenuProps['items']>(items)

2.4.在菜单组件中设置

<a-menu
  v-model:selectedKeys="current"
  @click="doMenuClick"
  mode="horizontal"
  :items="menus"
  class="custom-menu"
/>

上面代码中的current是被选中的菜单,doMenuClick是点击菜单后触发的事件。

const current = ref<string[]>(['/'])

const doMenuClick = ({ key }: any) => {
  console.log(key)
  router.push({
    path: key,
  })
}

3.展示效果

刚刚我们展示的代码当中,是设置了hideInMenu属性为true的,所以头部菜单栏没有进行展示。
在这里插入图片描述
我们现在去掉hideInMenu属性,或者你也可以设置属性为false,后续可以更方便的进行修改需不需要展示,代码如下:

export const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: '主页',
    component: HomePage,
    meta: {
      icon: () => h(HomeOutlined),
    },
  },
  {
    path: '/user/login',
    name: '用户登录',
    component: UserLoginPage,
  },
  {
    path: '/user/register',
    name: '用户注册',
    component: UserRegisterPage,
  },
]

可以看到,用户登录和用户注册就展示出来了。
在这里插入图片描述

4.常见问题解答

  1. Q:页面刷新后菜单选中状态丢失怎么办?
    A:通过useRoute()获取当前路由路径,初始化时设置selectedKeys的值。

  2. Q:如何实现菜单项的权限颗粒化控制?
    A:在meta.access中定义权限标识,结合RBAC(基于角色的访问控制)或ABAC(基于属性的访问控制)方案。

  3. Q:图标显示异常如何处理?
    A:确保:

    • 图标组件已正确注册/导入
    • 使用h()函数渲染Vue组件
    • 第三方图标库已正确引入样式文件

结语

通过本文,你已经掌握了动态路由菜单的核心实现技巧。
本部分代码在我的一个项目中有完整使用,如有需要点击该链接:Github,欢迎Star⭐️学习!如有问题,欢迎在评论区留言讨论~请添加图片描述

——👦[作者]:向阳256
——⏳[更新]:2025.4.15
——🥰本人技术有限,如果有不对指正需要更改或者有更好的方法,欢迎到评论区留言。
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐