vue 自定义侧边栏 递归无限子级菜单
- 2019 年 10 月 29 日
- 筆記
有很多网站会涉及到导航栏,我自己在开发中用的是element导航组件,并且自定义事件,给大家分享一下。
1.使用递归方法,无限循环子级菜单。
2.使用组件封装,维护方便。
3.使用index作为路由跳转。
4.结合后台动态渲染。
5.自定义样式,修改默认icon。
6.根据后台返回数据,动态设置默认选中。
1.封装组件。
首先创建好vue之后,在a_module里创建一个存放组件的文件夹,因为a_module是存放公共资源以及静态文件的,当然也可以根据喜好来创建。
2.调用组件。
在要使用到的页面中使用 import 引入封装好的组件,components初始化一下,在页面中使用。
注意:这里需要注意的是,在引用的页面中一定要el-menu包裹起来,可以在el-menu标签里来配置侧边栏的各种状态。
3.组件传值
我是后台拿到的数据,当然也可以自定义数据,在引用组建的页面内创建,在子组件标签上边自定义事件,在子组件用props接收参数。
4.el-menu配置
这里呢,需要在父组件内配置侧边栏的各种状态,选中状态啦,index路由跳转啦,等等。
这里呢,我主要配置了,router:开启index跳转路由,default-active:默认选中,这里呢我做了很多判断,大家可以根据实际情况来做处理,我主要是拿到当前地址,来做选中状态。active-text-color:配置字体颜色,等等
5.子组件递归,无限循环子级
我呢用的是递归的方法,他的原理呢就是自己调用自己。
注意看红色框中的内容,
(1).大家可以看到,我在跟标签里边写了一个:class,主要原因就是,但你循环自己的时候,设置css样式只会生效一次,这个可以解决这个问题。
(2).然后呢,根据数据结构,循环父组件传递过来的参数,如果没有children的话,循环下边的代码,不调用子级,如果有children的话证明有子级菜单,那么调用上边代码。
(3).大家可以看到在label标签里我又调用了自己,然后传递参数,这里就是递归,如果满足条件就无线调用自己。
(4).这里呢我用了自定义图标,大家可以观察我的布局。
(5).到这里已经差不多了,但是要注意的是,:index,接受的是字符串形式的值,所以这里比较坑,需要的话可以用String()转化一下。
(6).至于图片里getImgUrl()方法,是解决图片异步的一种方法。
6.默认样式
很多框架的默认样式是很难修改的,大家可以在页面中去找的class类名去修改,我用的是 /deep/ 这个是一个深度修饰符 或者是 >>> ,当然也可以在跟文件里去修改样式,但是我不建议这样去做,因为会他是全局修改,容易影响其他页面的样式。
差不多就是这些了,样式的以及源码我在下边给大家附上。
父组件:
html:
<el-menu :router="true" :default-active="(this.$route.meta[0].meta&&this.$route.meta[0].meta[0].path&&!this.$route.meta[0].meta[0].ispath)?this.$route.meta[0].meta[0].path:this.$route.meta[0].path" active-text-color="#ffffff" :unique-opened="true" background-color="#00bfb8" > <menutree :data="navigation" class="hr_one"></menutree> <!-- 侧边导航组件 --> </el-menu> css:
.el-aside::-webkit-scrollbar { width: 4px; background: #00d2ca; } .el-aside::-webkit-scrollbar-thumb { background: #009d97; border-top-right-radius: 10px; border-top-left-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; } .el-main::-webkit-scrollbar { display: none; } .el-aside { text-align: center; position: absolute; top: 80px; bottom: 0; left: 0; background-color: #00bfb8 !important; min-height: 800px; .el-menu-item-group /deep/.el-menu-item-group__title { padding: 0 !important; } .el-menu-item:hover { background-color: #00d2ca; } .child_li { color: #ffff; display: flex; align-items: center; padding: 0; span:first-child { margin-left: 23px; } span:last-child { margin-left: 23px; } } }
navigation: [ { id:0, name: "首页", path: "/Hr-index/home", icon: "icon_hrIndex.png" }, { id:1, name: "教职工档案", path: "/Hr-index/staffFiles", icon: "icon_staffFiles.png" }, { id:2, name: "招聘信息", path: "", icon: "icon_hrJion.png", children: [ { id: 122, name: "招聘申请", path: "/Hr-index/zpApply" }, { id: 123, name: "招聘审核", path: "/Hr-index/zpCheck" }, { id: 124, name: "结果统计", path: "/Hr-index/resultInfo" } ] }, { id: 10, name: "解聘信息", path: "", icon: "icon_hrunBind.png", children: [ { id: 119, name: "解聘信息", path: "/Hr-index/decruitment" }, { id: 121, name: "解聘教师端", path: "/Hr-index/jpteacher" } ] }, { id: 3, name: "劳资管理", path: "", icon: "icon_hrLabour.png", children: [ { id: 117, name: "劳资详情", path: "/Hr-index/labour/details" }, { id: 118, name: "岗位劳资设定", path: "/Hr-index/labour/setting" } ] }, { id: 4, name: "考勤管理", path: "/Hr-index/check/manage", icon: "icon_manage.png" }, { id: "5", name: "培训管理", path: "/Hr-index/modlifyift", icon: "icon_modifyift.png" }, { id: "6", name: "离岗创业管理", path: "/Hr-index/Quit", icon: "icon_dimission.png" }, { id: "7", name: "护照管理", icon: "icon_Passport.png", path: "/Hr-index/Passport" }, { id: "8", name: "权限管理", icon: "icon_jurisdiction_li.png", path: "", children: [ { id: "115", name: "人员管理", path: "/Hr-index/Jurisdiction_set" }, { id: "116", name: "角色管理", path: "/Hr-index/Jurisdiction_role" } ] }, { id: "11", name: "院系专业管理", path: "/Hr-index/yxhome", icon: "icon_yxhome.png" }, { id: "", name: "课程管理", path: "/Hr-index/KcAdministration", icon: "icon_KcAdministration.png" }, { id: "9", name: "个人信息", icon: "icon_Personal_li.png", path: "", children: [ { id: "111", name: "个人档案rerwerwerwerwerwerwerwerwerwerwerwerwerwerwerwer", path: "/Hr-index/Personal_file" }, { id: "112", name: "个人考勤", path: "/Hr-index/Personal_check" }, { id: "113", name: "劳资详情", path: "/Hr-index/Personal_labour" }, { id: "114", name: "培训详情", path: "/Hr-index/Personal_train" } ] } ], //导航数组
子组件:
html:
<div class="menutree" :class="[calssName]"> <div class> <label v-for="menu in data" :key="menu.index"> <el-submenu :index="String(menu.id)" v-if="menu.children!=''"> <!-- <el-submenu :index="String(menu.id)" v-if="menu.children"> --> <template slot="title"> <img :src="getImgUrl(menu.icon)" alt v-if="menu.icon" /> <span>{{menu.name}}</span> </template> <label> <menutree :data="menu.children" :calssName="calssName"></menutree> </label> </el-submenu> <el-menu-item :index="menu.path" v-else> <img :src="getImgUrl(menu.icon)" alt v-if="menu.icon" /> <span style="display:block;width:4px;height:4px;background:#ffffff;margin-top:28px;margin-left:30px; border-radius:100%;" :style="{backgroundColor:calssName=='listtxt'?'#a6160a':'#ffffff',}" v-else ></span> <span slot="title" style="display:block;overflow: hidden;text-overflow:ellipsis;white-space: nowrap;white-space : nowrap;" >{{menu.name}}</span> </el-menu-item> </label> </div> </div>
import menutree from "./boss"; export default { name: "menutree", data() { return { menu_data: {}, name: "one" }; }, components: { menutree: menutree }, props: ["data","calssName"], mounted() { // console.log(this.$route); }, methods: { getImgUrl(icon) { return require("@/assets/" + icon); } } };
.menutree /deep/ .el-menu-item, .menutree /deep/ .el-submenu__title { color: #ffffff !important; height: 60px; line-height: 60px; display: flex; text-align: left; padding: 0; img { width: 16px; height: 16px; float: left; margin-top: 21px; margin-left: 39px; } span { float: left; margin-left: 12px; } } .one /deep/ .el-menu { background: none; } .listtxt.menutree /deep/ .el-menu-item,.listtxt.menutree /deep/ .el-submenu__title { color: #a6160a !important; }