vue + element-ui 制作下拉菜单(可配置路由、可根据路由高亮list、可刷新自动展开定位路由)
本篇文章分享一篇关于 vue制作可路由切换组件、可刷新根据路由定位导航(自动展开)、可根据路由高亮对应导航选项
一、实现的功能如下:
1、可折叠导航面板
2、点击导航路由不同组件
3、在当前页f5刷新,或者在url输入对应的路由地址,会根据路由打开左侧导航对应的位置并且展开、高亮
二、代码详情
1、main.js
import Vue from 'vue' import App from './App' import router from './router' //引入element-ui import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' // 注册elementUi组件 Vue.use(ElementUI) Vue.config.productionTip = false /* eslint-disable no-new */ let gvm = new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
2、navSlideBar.vue
<template> <div class="navslidebar"> <div class="navHeaderbar"></div> <el-menu :default-active="$route.path" router class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" background-color="#2aaae4" :unique-opened="uniqueOpened" text-color="#fff" active-text-color="#ffd04b"> <el-menu-item class="oneLi" v-for="(item, i) in navList" :key="i" :index="item.name" @click="haha"> <i style="font-size:14px; color:#fff" class="el-icon-document"></i> <span slot="title">{{$t(item.navItem)}}</span> </el-menu-item> <el-submenu v-for="(item,index) in subNavList" :key="index+1" :index="item.name"> <template slot="title"> <i style="font-size:14px; color:#fff" class="el-icon-document"></i> <span @click="haha">{{$t(item.navItem)}}</span> </template> <el-menu-item class="SubLi" v-for="(subItem, subIndex) in item.children" :key="subIndex" :index="subItem.name"> <p><span></span><span></span></p> {{$t(subItem.navItem)}} </el-menu-item> </el-submenu> <el-menu-item class="oneLi" key="-1" index="/download"> <i style="font-size:14px; color:#fff" class="el-icon-document"></i> <span slot="title">{{$t("slideBar.download")}}</span> </el-menu-item> </el-menu> </div> </template>
<script> export default { name: "NavSlidebar", data() { return { uniqueOpened: true, //只打开一个二级导航 navList: [{ name: "/overall", navItem: "slideBar.overall" }], subNavList: [{ name: "/servicevolume", navItem: "slideBar.servicevolume", children: [{ name: "/visitvolume", navItem: "slideBar.visitvolume" }, { name: "/users", navItem: "slideBar.users" }, // { // name: "/multimediausage", // navItem: "slideBar.multimediausage" // } ] }, { name: "/servicefficiency", navItem: "slideBar.servicefficiency", children: [{ name: "/solvedstatus", navItem: "slideBar.solvedstatus" }, { name: "/transferredrate", navItem: "slideBar.transferredrate" }, // { // name: "/cast", // navItem: "slideBar.cast" // } ] }, { name: "/kgperformance", navItem: "slideBar.kgperformance", children: [{ name: "/question", navItem: "slideBar.question" }, // { // name: "/outofscopeanalysis", // navItem: "slideBar.outofscopeanalysis" // } ] }, { name: "/sessionflow", navItem: "slideBar.sessionflow", children: [{ name: "/handingtime", navItem: "slideBar.handingtime" }, { name: "/handingturns", navItem: "slideBar.handingturns" }, { name: "/leavingstatus", navItem: "slideBar.leavingstatus" }, { name: "/customerjourney", navItem: "slideBar.customerjourney" } ] } ] }; }, methods: { haha() {}, handleOpen(key, keyPath) { //console.log(key, keyPath); }, handleClose(key, keyPath) { //console.log(key, keyPath); } }, computed: {} }; </script>
<style> div.navHeaderbar { height: 48px; /* background: url("~@/assets/navHead.jpg") center no-repeat; */ background: url("./../../../../static/image/navHead.jpg") center no-repeat; background-size: auto 48px; } .el-menu { border-right: none !important; } /* 一级导航划入颜色 */ .oneLi:focus, .oneLi:hover { background-color: #2bace580 !important; } .el-submenu__title:hover { background-color: #2bace580 !important; } .SubLi { position: relative; background-color: #239ACA !important; font-size: 13px; } .el-menu-item, .el-submenu__title { height: 40px !important; line-height: 40px !important; /* padding-left: 15px !important; */ } .el-submenu .el-menu-item { height: 40px !important; line-height: 40px !important; } .el-submenu__title i { color: #fff !important; font-size: 14px; } .SubLi>p { width: 15px; height: 40px; position: absolute; left: 20px; top: 0; } .SubLi>p>span { display: block; width: 15px; height: 50%; opacity: .2; border-left: 1px solid #fff; } .SubLi>p>span:first-child { border-bottom: 1px solid #fff; } .SubLi:hover { background-color: rgba(8, 15, 39, 0.3) !important } </style>
3、AppMain.vue
1 <template> 2 <div class="appmain"> 3 <router-view></router-view> 4 </div> 5 </template> 6 7 <script> 8 export default { 9 name: 'AppMain', 10 } 11 </script> 12 13 <style scoped> 14 div.appmain{ 15 flex-grow: 1; 16 display: flex; 17 flex-direction: column; 18 padding: 15px; 19 padding-top: 0; 20 overflow: hidden; 21 } 22 </style>
4、router/index.js
import Vue from 'vue' import Router from 'vue-router' import index from '@/views/layout/index' //一级路由组件引入 import Overall from '@/views/Overall/Overall' //ServiceVolume import VisitVolume from '@/views/ServiceVolume/VisitVolume' import Users from '@/views/ServiceVolume/Users' import MultimediaUsage from '@/views/ServiceVolume/MultimediaUsage' //ServicEfficiency import CASTs from '@/views/ServicEfficiency/CAST' import SolvedStatus from '@/views/ServicEfficiency/SolvedStatus' import TransferredRate from '@/views/ServicEfficiency/TransferredRate' //KgPerformance import Question from '@/views/KgPerformance/Question' //SessionFlow import CustomerJourney from '@/views/SessionFlow/CustomerJourney' import HandingTime from '@/views/SessionFlow/HandingTime' import HandingTurns from '@/views/SessionFlow/HandingTurns' import LeavingStatus from '@/views/SessionFlow/LeavingStatus' //DownLoad import DownLoad from '@/views/DownLoad/DownLoad' Vue.use(Router) export default new Router({ // mode: 'history', routes: [ { path: '*', redirect: '/overall' }, { path: '/index', name: 'index', component: Overall }, { path: '/overall', name: 'overall', component: Overall }, { path: '/visitvolume', name: 'visitvolume', component: VisitVolume }, { path: '/users', name: 'users', component: Users }, { path: '/multimediausage', name: 'multimediausage', component: MultimediaUsage }, { path: '/cast', name: 'cast', component: CASTs }, { path: '/solvedstatus', name: 'solvedstatus', component: SolvedStatus }, { path: '/transferredrate', name: 'transferredrate', component: TransferredRate }, { path: '/question', name: 'question', component: Question }, { path: '/handingtime', name: 'handingtime', component: HandingTime }, { path: '/handingturns', name: 'handingturns', component: HandingTurns }, { path: '/leavingstatus', name: 'leavingstatus', component: LeavingStatus }, { path: '/customerjourney', name: 'customerjourney', component: CustomerJourney }, { path: '/download', name: 'download', component: DownLoad }, ] })
三、模板重点参数解释:
1、整个导航外层包裹的组件名称
1 <el-menu :default-active="$route.path" router @open="handleOpen" @close="handleClose"><el-menu>
default-active:指的是默认选中导航的哪一项,当前指定的是,当前route的path属性。这里的path和模板中的:index的绑定是一 一对应的(后面会介绍)。
router:是否使用vue-router进行路由跳转,写上此参数便启用。启用此模式后,会在激活导航时以 index 作为路由的 path 进行路由跳转。
2、这一组是不可展开的,也就是一级导航的标记,直接就是el-menu-item,下面是重点参数解释:
<el-menu-item class="oneLi" v-for="(item, i) in navList" :key="i" :index="item.name" @click="haha"> <i style="font-size:14px; color:#fff" class="el-icon-document"></i> <span slot="title">{{$t(item.navItem)}}</span> </el-menu-item>
index:指的是每一个导航的唯一标志,用来和上面:default-acitve的值对应,然后自动操作高亮选中。
3、二级导航的组件:slot="title"的这个标记是显示二级导航名称的标记。 el-menu-item这个标记是真正点击路由不同组件的标记。
<el-submenu v-for="(item,index) in subNavList" :key="index+1" :index="item.name"> <template slot="title"> <i style="font-size:14px; color:#fff" class="el-icon-document"></i> <span @click="haha">{{$t(item.navItem)}}</span> </template> <el-menu-item class="SubLi" v-for="(subItem, subIndex) in item.children" :key="subIndex" :index="subItem.name"> <p><span></span><span></span></p> {{$t(subItem.navItem)}} </el-menu-item> </el-submenu>
el-submenu 的 index: 指的是每一个导航的唯一标志,用来和上面:default-acitve的值对应,然后自动操作高亮选中。
el-menu-item的index:指的是每一个导航的唯一标志,用来和上面:default-acitve的值对应,然后自动操作高亮选中。
注意:
本篇文章请忽略模板中类似 {{$t("slideBar.download")}} 表达式。 调用的是国际化i18n插件,个人在项目中用了国际化插件。这部分在对应的script中可以改成自己想显示的信息,如有不懂的地方,欢迎交流,留言。
四、element官方的详细API
Menu Attribute : 外层包裹元素的属性(el-menu)
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
mode | 模式 | string | horizontal / vertical | vertical |
collapse | 是否水平折叠收起菜单(仅在 mode 为 vertical 时可用) | boolean | — | false |
background-color | 菜单的背景色(仅支持 hex 格式) | string | — | #ffffff |
text-color | 菜单的文字颜色(仅支持 hex 格式) | string | — | #303133 |
active-text-color | 当前激活菜单的文字颜色(仅支持 hex 格式) | string | — | #409EFF |
default-active | 当前激活菜单的 index | string | — | — |
default-openeds | 当前打开的 sub-menu 的 index 的数组 | Array | — | — |
unique-opened | 是否只保持一个子菜单的展开 | boolean | — | false |
menu-trigger | 子菜单打开的触发方式(只在 mode 为 horizontal 时有效) | string | hover / click | hover |
router | 是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转 | boolean | — | false |
collapse-transition | 是否开启折叠动画 | boolean | — | true |
Menu Methods:外层包裹元素的方法(el-menu)
方法名称 | 说明 | 参数 |
---|---|---|
open | 展开指定的 sub-menu | index: 需要打开的 sub-menu 的 index |
close | 收起指定的 sub-menu | index: 需要收起的 sub-menu 的 index |
Menu Events:外层包裹元素的事件(el-menu)
事件名称 | 说明 | 回调参数 |
---|---|---|
select | 菜单激活回调 | index: 选中菜单项的 index, indexPath: 选中菜单项的 index path |
open | sub-menu 展开的回调 | index: 打开的 sub-menu 的 index, indexPath: 打开的 sub-menu 的 index path |
close | sub-menu 收起的回调 | index: 收起的 sub-menu 的 index, indexPath: 收起的 sub-menu 的 index path |
SubMenu Attribute:二级导航的包裹元素的属性(el-submenu)
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
index | 唯一标志 | string | — | — |
popper-class | 弹出菜单的自定义类名 | string | — | — |
show-timeout | 展开 sub-menu 的延时 | number | — | 300 |
hide-timeout | 收起 sub-menu 的延时 | number | — | 300 |
disabled | 是否禁用 | boolean | — | false |
popper-append-to-body | 是否将弹出菜单插入至 body 元素。在菜单的定位出现问题时,可尝试修改该属性 | boolean | — | 一级子菜单:true / 非一级子菜单:false |
Menu-Item Attribute:每一个可点击跳转的选项元素的属性(el-menu-item)
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
index | 唯一标志 | string | — | — |
route | Vue Router 路径对象 | Object | — | — |
disabled | 是否禁用 | boolean | — | false |
最后:
本文档意在与帮助初学者快速构建vue项目,虽没什么技术含量。但不要随意转载,如需转载保存,请署上 转载地址。谢谢配合。
有问题随时交流,不怕打扰。