最近项目有一个需求:根据用户角色权限,前端通过接口从后台动态获取到该用户的多层级菜单内容并在前端的侧边栏显示。这里需要注意的是,该菜单的层级可以是无限的,并没有从需求层面限制菜单只能是两级或者三级。我们项目使用的是vue+elementui,vue作为一个先进的现代化框架,特色就是数据绑定,我们来看一下如何使用vue框架来通过递归的方式来动态渲染无限层级的菜单列表,这是更优雅的方式!
vue动态渲染多层级菜单的难点
1、该菜单的层级理论上可以是无限的,并没有从需求层面限制菜单只能是两级或者三级的,因此增加了我们编程的难度。因为如果规定了是两级菜单,那么我们在vue的模板中使用两个v-for就能轻松搞定。可是现在你不知道有多少个层级,你不可能在vue模板中写无数个嵌套的v-for吧!
2、我们的菜单使用的是elementui的el-menu组件,我们肯定不能在javascript代码中使用createElement和appendChild这种原生的方式来不断递归组装menu的层级结构。因为el-menu不是原生的标签,并且想要在vue中动态渲染出elementui中的组件,是一个比较复杂且开销很大的活儿,这种通过js代码组装原生标签的写法只适合以前的jquery时代,现在还用这种办法就有点舍近求远的感觉。
vue实现动态渲染多层级菜单
我们要知道,像vue这种先进的现代化框架,其最大的特点之一就是数据绑定,我想用过的同学应该都知道是咋回事,比如当我们初始化模板的时候,一个组件的内容通过一个变量A赋值为null或者[]
,当我们获取到非空的数据后,直接赋值给该变量A,那么该组件就会自动刷新内容,显示出A变量的最新内容。我们根本无需关心怎样将新内容刷新到组件中显示。
由此,我们想到在vue中使用自定义组件+v-for+v-if来实现递归以及递归中所需的条件渲染和列表渲染。首先,我们创建一个menu-ro组件,该组件代表了菜单中的某一个目录,并包括了该目录中所有的子层级内容。这里我们在menu-ro组件中调用自身,来实现递归。menu-ro组件的模板代码如下:
1 | <template> |
我们翻译一下这段代码:将菜单列表中的某个目录层级对象A传递到menu-ro组件的item属性中。如果A存在children,那么说明还有子节点存在,所以他自己是一个目录,因此递归调用menu-ro,并使用v-for将children中每个子节点都传入menu-ro中。如果不存在children,说明没有子目录了,他自己显示为菜单选项而非目录。
我们从接口获取的JSON结构示例如下:
1 | { |
在“系统管理”目录中有子目录“租户管理”,“租户管理”中有两个子选项“租户列表”、“租户套餐”。
在容纳菜单的侧边栏组件中的代码如下:
1 | ... |
最后实现的动态多层级菜单列表递归渲染效果如下图所示:
此时无论获取的菜单列表JSON数据有多少个层级的children嵌套,都可以非常优雅地更新菜单列表显示。而我们需要做的仅仅是通过接口获取到菜单列表JSON数据即可,其他的事情全部由vue内部机制给你处理好了,不需要我们通过javascript来手动重新组织标签结构,不需要像以前jquery中那样大费周章。说到底,其实就是把以前开发时存在于javascript中的递归,优雅地移动到了自定义组件中,完美结合了VUE这种现代化框架的优势。