Vue 里,多级菜单要如何设计才显得专业?

老生常谈了!

虽然我们是 Java 猿,但是写起来前端代码也不含糊!今天我想来和大家聊聊这个前端的动态菜单,要如何设计才显得专业!还是以我们的 TienChin 项目为例,大家一起来看看。

先来一张截图看看效果:

Vue 里,多级菜单要如何设计才显得专业?插图亿华云

那么这样的菜单是如何设计出来的呢?

今天我也不想和大家聊过多的技术细节,就聊聊这个路由是如何设计的,一旦大家明白了路由是如何设计的,剩下的问题都是细枝末节的问题了。

1. 路由设计

有的小伙伴做过 vhr,知道 vhr 里的动态菜单实现方式,松哥和大家一样,也是在不断学习不断进步中,今天我想和大家探讨 TienChin 项目中动态菜单的实现方案,看看是否是一种更佳的解决方案。

1.1 菜单设计

先来和小伙伴们回顾下 vhr 中的方案:

在 vhr 中,权限的控制,只控制到二级菜单,也就是一级菜单和权限没关系。举个例子,现在有一级菜单 A 和 二级菜单 B,B 是 A 中的菜单,现在假设:

如果当前用户权限可以查看 B 菜单,那么 A 菜单会自动显示出来。如果当前用户权限无法查看 B 菜单,且 A 菜单中也没有其他子菜单可以展示,那么 A 菜单就不会显示出来。

换言之,A 菜单显示与否,主要看它里边有没有子菜单需要展示,如果有,A 菜单就显示,如果没有,A 菜单就不显示。

vhr 中的思路是这样的。

在 TienChin 项目中,这一块有一些变化:

如果 A 中只有一个 B,那么似乎就没有必要再做一个两级菜单了,直接把 B 展示出来不就行了?用户操作也方便!

这是第一个不一样的地方。

1.2 路由数据

基于第一点,就涉及到一个问题,就是路由接口该如何设计?最主要是接口返回的数据格式应该是什么样子的?

首先有一点小伙伴们应该知道,这里的路由是一个嵌套路由,也就是一级菜单中嵌套着二级菜单。即使这个地方在展示的时候,不存在层级关系,例如上图中的促销活动,但是底层的数据结构也应该是嵌套路由。

好啦,不卖关子了,我们来看一段路由 JSON:

[{

"name": "Monitor",

"path": "/monitor",

"hidden": false,

"redirect": "noRedirect",

"component": "Layout",

"alwaysShow": true,

"meta": {

"title": "系统监控",

"icon": "monitor",

"noCache": false,

"link": null

},

"children": [{

"name": "Online",

"path": "online",

"hidden": false,

"component": "monitor/online/index",

"meta": {

"title": "在线用户",

"icon": "online",

"noCache": false,

"link": null

}

}, {

"name": "Job",

"path": "job",

"hidden": false,

"component": "monitor/job/index",

"meta": {

"title": "定时任务",

"icon": "job",

"noCache": false,

"link": null

}

}]

}, {

"path": "/",

"hidden": false,

"component": "Layout",

"children": [{

"name": "Role",

"path": "role",

"hidden": false,

"component": "system/role/index",

"meta": {

"title": "角色管理",

"icon": "peoples",

"noCache": false,

"link": null

}

}]

}]

这里我举了两个菜单的例子,这两个例子比较具有代表性,这个菜单最终显示效果大概类似下面这样:

系统监控

在线用户

定时任务

角色管理

大概显示效果如上图。

接下来我就来说一下这里几个典型属性:

redirect:noRedirect 表示该路由在面包屑导航中不可被点击。alwaysShow:如果这个属性设置为 false,那么当当前菜单只有一个子菜单的时候,默认情况下就只会显示子菜单,而忽略父菜单(如 1.1 小节所述),但是如果将该属性设置为 true,则无论当前菜单有几个子菜单,都会将当前菜单展示出来(这就类似于 vhr 中的效果了)。每一个父菜单都有自己的 path,每一个 children 也有自己的 path,父菜单的 path 加上每一个 children 的 path,共同组成每一个 children 的路径。再来看第二个角色管理这个菜单项,由于它的父菜单中只有一个子菜单项,并且父菜单中也没有 alwaysShow 属性,所以这个菜单项在最终展示的时候,就只展示里边的角色管理,父菜单则不会展示出来(正好,生成的 JSON 中也没说父菜单的名字、图标等属性)。

当然,不是说你的 JSON 这么写就自动这么显示,JSON 中的东西只是一个标记,最终怎么显示,还要看渲染:

v-for="child in item.children"

:key="child.path"

:is-nest="true"

:item="child"

:base-path="resolvePath(child.path)"

class="nest-menu"

/

THE END
Copyright © 2024 亿华云