问题形容
在后盾治理我的项目中,牵涉到权限的货色少数是后端传递过去的数据,前端去展现(当然前端也会做一些管制)。就导航菜单而言,也不能写死了,须要在用户登录了当前,发申请获取用户的对应菜单数据,依据对应的数据去展现对应的菜单。
本文记录一下应用组件递归的形式,封装一个动静的、多级的导航菜单,从而实现动态效果。
看这篇文章之前,能够看看我之前的《vue 组件的递归自调用~ 代码思路剖析》文章,本篇文章是之前文章的延长。地址如下:https://segmentfault.com/a/11…
效果图
咱们先看一下效果图:
思路剖析
-
首先,咱们要和后端沟通返回的数据格式,咱们晓得前端的 el-menu 菜单的外围数据属性有四个:
- 菜单的名字 name
- 点击菜单进行路由跳转的门路 path
- 菜单上小图标 icon
- 菜单是不是最内层的菜单,即 children 是否是空数组,当 children 为空的时候,就阐明到菜单最里层了。(最里层的菜单 children 为空数组的时候,点击的时候,做路由跳转)
- 所以须要有 name、path、icon、children 属性,且得是一个树结构的格局,和左侧导航菜单保持一致。
- 这里咱们模仿一下后端返回的代码
后端返回的 el-menu 菜单数据
menuArr: [
{
// 留神!留神!有 children 的菜单项,path 不会应用的,所以 path 为什么都无所谓;没 children 的,即 children 的 length 等于 0 的,才会应用 path 属性做路由跳转
name: "前端三大框架",
path: "前端三大框架",
icon: "el-icon-star-off",
children: [
{
name: "vue 页面",
path: "/vue",
icon: "el-icon-star-off",
children: [],},
{
name: "react 页面",
path: "/react",
icon: "el-icon-star-off",
children: [],},
{
name: "angular 页面",
path: "/angular",
icon: "el-icon-star-off",
children: [],},
],
},
{
name: "后端两大框架",
path: "后端两大框架",
icon: "el-icon-star-off",
children: [
{
name: "Spring Boot 页面",
path: "/springBoot",
icon: "el-icon-star-off",
children: [],},
{
name: "Spring 页面",
path: "Spring 页面",
icon: "el-icon-star-off",
children: [
{
name: "MySql 页面",
path: "/mysql",
icon: "el-icon-star-off",
children: [],},
{
name: "Redis 页面",
path: "/redis",
icon: "el-icon-star-off",
children: [],},
],
},
{
name: "Mybatis 页面",
path: "/mybatis",
icon: "el-icon-star-off",
children: [],},
],
},
]
咱们先看一下非动静多级菜单的写法,而后再看一下递归组件动静多级菜单的写法
非动静多级菜单(写死了,不灵便,不倡议应用)
<el-menu
:default-active="activeIndex"
class="elMenu"
background-color="#333"
text-color="#B0B0B2"
active-text-color="#fff"
:unique-opened="true"
router
ref="elMenu"
@select="menuSelect"
>
<el-submenu index="非叶子节点也须要 index 属性">
<template slot="title">
<i class="el-icon-star-off"></i>
<span> 前端三大框架 </span>
</template>
<!-- 这个是没子节点的 没有子内容,用 el-menu-item 构造 -->
<el-menu-item index="/vue">
<i class="el-icon-star-off"></i>
<span slot="title">vue 页面 </span>
</el-menu-item>
<el-menu-item index="/react">
<i class="el-icon-star-off"></i>
<span slot="title">react 页面 </span>
</el-menu-item>
<el-menu-item index="/angular">
<i class="el-icon-pear"></i>
<span slot="title">angular 页面 </span>
</el-menu-item>
</el-submenu>
<el-submenu index="非叶子节点也须要 index 属性哦">
<template slot="title">
<i class="el-icon-star-off"></i>
<span> 后端两大框架 </span>
</template>
<el-menu-item index="/springBoot">
<i class="el-icon-star-off"></i>
<span slot="title">Spring Boot 页面 </span>
</el-menu-item>
<!-- 留神看这里有子节点的无子节点的 html 标签的区别 -->
<!-- 这个是有子节点的 还有子内容,用 el-submenu 构造 -->
<el-submenu index="非叶子节点也须要 index 属性哈">
<template slot="title">
<i class="el-icon-star-off"></i>
<span>Spring 页面 </span>
</template>
<el-menu-item index="/mysql">
<i class="el-icon-star-off"></i>
<span slot="title">MySql 页面 </span>
</el-menu-item>
<el-menu-item index="/redis">
<i class="el-icon-star-off"></i>
<span slot="title">Redis 页面 </span>
</el-menu-item>
</el-submenu>
<!-- 这个是没子节点的 没有子内容,用 el-menu-item 构造 -->
<el-menu-item index="/mybatis">
<i class="el-icon-star-off"></i>
<span slot="title">Mybatis 页面 </span>
</el-menu-item>
</el-submenu>
</el-menu>
发现法则
通过上述代码,咱们发现,el-menu 代码大抵分为两类,有子集和没有子集的
- 有子集 :
用的是 el-submenu 标签包 template 标签指定名字跟很多个 el-menu-item 标签
- 没子集 :
间接用很多个 el-menu-item 标签
得出上述法则,咱们就能应用递归组件形式去封装一个动静菜单
动静菜单代码
外层菜单局部
html 局部
<el-menu
:default-active="activeIndex"
class="elMenu"
background-color="#333"
text-color="#B0B0B2"
active-text-color="#fff"
:unique-opened="true"
router
ref="elMenu"
@select="menuSelect"
>
<!-- 递归动静菜单 -->
<myitem :data="menuArr"></myitem>
</el-menu>
js 局部
import myitem from "./components/myitem.vue"; // 引入递归菜单组件
export default {
name: "Home",
components: {myitem, // 注册一下},
data() {
return {
activeIndex: this.$route.path,
menuArr: [...] // 数据是上述咱们模仿的数据,# 后端返回的 el-menu 菜单数据#
};
}
};
内层递归菜单项局部
<template>
<div>
<template v-for="(item, index) in data">
<!-- 因为有子集和无子集渲染 html 标签不一样,所以要分为两种状况
状况一:有子集的状况:-->
<el-submenu
:key="index"
:index="item.path"
v-if="item.children.length > 0"
>
<template slot="title">
<i :class="item.icon"></i>
<span>{{item.name}}</span>
</template>
<myitem :data="item.children"></myitem>
</el-submenu>
<!-- 状况二:没子集的状况:-->
<el-menu-item :key="index" v-else :index="item.path">
<i :class="item.icon"></i>
<span slot="title">{{item.name}}</span>
</el-menu-item>
</template>
</div>
</template>
<script>
export default {
name: "myitem",
props: {
data: {
type: Array,
default: [],},
},
// 留神:在 template 标签上应用 v -for,:key="index" 不能写在 template 标签上,因为其标签不会被渲染,会引起循环谬误
};
</script>
残缺代码
残缺代码我上传到 Gitee 下来了,欢送大家下载查看,这样更加不便了解。
地址:https://gitee.com/ah-shuai/dy…