效果图如下:
当标签栏很多的时候效果图如下:
左侧菜单布局 ($route.path高亮显示激活路由 :default-active="$route.path"
)
<el-menu:default-active="$route.path"class="el-menu-vertical-demo"background-color="#323744"text-color="#fff"active-text-color="#409eff":collapse="iscollapse"unique-opened:collapse-transition="false"router><template v-for="(item, index) in menuList"><!-- 有下拉 --><el-submenu v-if="item.children" :index="item.id" :key="index"><template slot="title"><svg-icon :className="item.icon" :iconClass="item.icon"></svg-icon><span>{{ item.title }}</span></template><el-menu-item-groupv-for="(item, index) in item.children":key="index"><el-menu-item :index="item.path" @click="clickMenu(item)"><template slot="title"><svg-icon :className="item.icon" :iconClass="item.icon"></svg-icon><span>{{ item.subtitle1 }}</span></template></el-menu-item></el-menu-item-group></el-submenu><!-- 没有下拉 --><el-menu-item v-else :key="index" :index="item.path" @click="clickMenu(item)"><svg-icon :className="item.icon" :iconClass="item.icon"></svg-icon><span slot="title">{{ item.subtitle1 }}</span></el-menu-item></template></el-menu>
模拟数据如下:(以下路径均需在router/index.js里面进行配置)
menuList: [{id: "9",subtitle1: "首页",icon: "shangjiadianpu",path: "/welcome",},{id: "1",title: "用户管理",icon: "huangguanyonghu",children: [{id: "1-1",subtitle1: "时间-moment",icon: "huangguanyonghu",path: "/user",},{id: "1-2",subtitle1: "删除用户",icon: "huangguanyonghu",img: require("@/assets/logo.png"),path: "/user2",},{id: "1-3",subtitle1: "图片放大",icon: "huangguanyonghu",path: "/user3",},],},{id: "2",title: "表格",icon: "ershoujiaoyi",children: [{id: "2-1",subtitle1: "表格排序",icon: "ershoujiaoyi",path: "/tableSort",},{id: "2-2",subtitle1: "动画",icon: "ershoujiaoyi",path: "/animation",},{id: "2-3",subtitle1: "权限3",icon: "ershoujiaoyi",path: "/limit3",},],},{id: "6",subtitle1: "拖拽-sortablejs",icon: "shangpuchuzu",path: "/sortable",},{id: "7",title: "功能",icon: "ershoujiaoyi",children: [{id: "7-1",subtitle1: "上下滚动",icon: "ershoujiaoyi",path: "/numscroll",},{id: "7-9",subtitle1: "数字滚动",icon: "ershoujiaoyi",path: "/icountup",},{id: "7-2",subtitle1: "动画",icon: "ershoujiaoyi",path: "/animation",},{id: "7-3",subtitle1: "调用摄像头",icon: "ershoujiaoyi",path: "/opencamera",},{id: "7-4",subtitle1: "裁剪图片",icon: "ershoujiaoyi",path: "/cropperjs",},{id: "7-5",subtitle1: "裁剪图片2",icon: "ershoujiaoyi",path: "/vuecropper",},{id: "7-6",subtitle1: "打印功能",icon: "ershoujiaoyi",path: "/printjs",},{id: "7-7",subtitle1: "vue-pfd预览",icon: "ershoujiaoyi",path: "/vuepdf",},{id: "7-8",subtitle1: "内嵌iframe",icon: "ershoujiaoyi",path: "/iframepdf",},{id: "7-10",subtitle1: "放大镜功能",icon: "ershoujiaoyi",path: "/magnifier",},{id: "7-11",subtitle1: "多表头表格",icon: "ershoujiaoyi",path: "/xlsx",},{id: "7-12",subtitle1: "单表头表格",icon: "ershoujiaoyi",path: "/xlsx2",},{id: "7-13",subtitle1: "Vuecontextmenu",icon: "ershoujiaoyi",path: "/vuecontextmenu",},{id: "7-14",subtitle1: "vcontextmenu",icon: "ershoujiaoyi",path: "/vcontextmenu",},{id: "7-15",subtitle1: "表格合并",icon: "ershoujiaoyi",path: "/tablehebing",},{id: "7-16",subtitle1: "日期选择",icon: "ershoujiaoyi",path: "/datepicker",},{id: "7-17",subtitle1: "treeselect",icon: "ershoujiaoyi",path: "/treeselect",},{id: "7-19",subtitle1: "大屏数据",icon: "ershoujiaoyi",path: "/datav",},{id: "7-20",subtitle1: "左右菜单联动",icon: "ershoujiaoyi",path:'/leftrightmenu'},{id: "7-18",subtitle1: "测试页面",icon: "ershoujiaoyi",path: "/test",},],},],
主要内容区域标签栏布局如下:
<el-tabsclass="vab-tabs-content"v-model="activeIndex"type="card"@tab-click="clickTab"@tab-remove="removeTab"><el-tab-panev-for="item of openTab"v-if="openTab.length":key="item.name":label="item.name":name="item.route":closable="isNoClosable(item)"></el-tab-pane></el-tabs>
标签栏样式
/deep/.el-tabs__header .el-tabs__nav{border:none;}/deep/.el-tabs--card>.el-tabs__header{border:none;}/deep/.el-tabs__header .el-tabs__item{padding:0 30px;border:none}/deep/.el-tabs__header .el-tabs__item.is-active {color: #1890ff;background: #e8f4ff;outline: none;-webkit-mask: url(~@/assets/images/tabs-bg.png);mask: url(~@/assets/images/tabs-bg.png);-webkit-mask-size: 100% 100%;mask-size: 100% 100%;
}/deep/.el-tabs__header .el-tabs__item:hover {color: #515a6e;background: #dee1e6;-webkit-mask: url(~@/assets/images/tabs-bg.png);mask: url(~@/assets/images/tabs-bg.png);-webkit-mask-size: 100% 100%;mask-size: 100% 100%;}/deep/.el-tabs--card > .el-tabs__header .el-tabs__item.is-closable:hover {padding-left: 30px;padding-right: 30px;}/deep/.el-tabs__header .el-tabs__item.is-active.is-closable {padding-left: 30px;padding-right: 30px;
}/deep/.el-tabs__header .el-tabs__item.is-active:hover {color: #1890ff !important;background: #e8f4ff !important;// padding: 0 30px 0 30px;}.el-tabs__header .el-tabs__item.is-active:hover {color: #1890ff;background: #e8f4ff;-webkit-mask: url(~@/assets/images/tabs-bg.png);mask: url(~@/assets/images/tabs-bg.png);-webkit-mask-size: 100% 100%;mask-size: 100% 100%;}
创建一个仓库模块 @/store/Modules/tabs.js
tabs.js代码如下
export default{namespaced: true, //开启命名空间state: {openTab: JSON.parse(sessionStorage.getItem('openTab'))|| [],activeIndex: ''},mutations: {add_tabs (state, data) {//如果等于-1说明tabs不存在那么插入,否则什么都不做//findindex找角标,循环判断一下,如果等于那么就代表有相同的,就不必添加,如果找不到那就是-1.就添加let result = state.openTab.findIndex(item => item.name === data.name);result === -1 ? state.openTab.push(data) : '';// 存到本地 页面刷新不丢失sessionStorage.setItem('openTab',JSON.stringify(state.openTab))},delete_tabs (state, route) {let index = 0for (let gohh of state.openTab) {if (gohh.route === route) {break}index++}state.openTab.splice(index, 1)// 存到本地 页面刷新不丢失sessionStorage.setItem('openTab',JSON.stringify(state.openTab))},set_active_index (state, index) {console.log(index);state.activeIndex = index}}
}
将tab.js模块引入@store/index.js
import Vue from 'vue'
import Vuex from 'vuex
import tabs from './Modules/tabs'
Vue.use(Vuex)
export default new Vuex.Store({state: { },mutations: {},actions: {},modules: {tabs}
})
主要逻辑代码如下:
在主要内容区域引入如下代码获取tabs.js仓库里面的值在页面进行渲染
computed: {openTab () {return this.$store.state.tabs.openTab},activeIndex: {get () {return this.$store.state.tabs.activeIndex},set (val) {this.$store.commit('tabs/set_active_index', val)}}},
给左侧菜单导航绑定点击事件clickMenu,去触发仓库的add_tabs事件,把数组添加到openTab数组里面(添加前需要判断openTab是否有当前值,有就不添加,反之添加),把activeIndex也改变
clickMenu(val){//备注 :分模块触发事件可参考vue官网 '模块名/事件名'this.$store.commit('tabs/add_tabs',{route: val.path , name: val.subtitle1 })this.$store.commit('tabs/set_active_index', val.path)},
给标签绑定点击事件clickTab 跳转到对应路由,给标签叉叉绑定removeTab (tab-remove 点击 tab 移除按钮后触发 被删除的标签的 name)拿到对应的路由进行判断
1、如果是首页则不删除;
2、如果删除的高亮激活这一项,则跳转到最后openTab数组的最后一项并高亮;
3、如果删除的不是高亮激活这一项,则不跳转,高亮激活项不变。
clickTab (tab) {console.log(tab);this.$router.push({path: this.activeIndex})},removeTab (target) {if(target == '/'||target == '/welcome'){return}this.$store.commit('tabs/delete_tabs', target)if (this.activeIndex === target) {// 设置当前激活的路由if (this.openTab && this.openTab.length >= 1) {console.log('=============', this.openTab[this.openTab.length - 1].route)this.$store.commit('tabs/set_active_index', this.openTab[this.openTab.length - 1].route)this.$router.push({path: this.activeIndex})}}},
给el-tab-pane标签绑定属性 :closable="isNoClosable(item)
判断el-tab-pane是否显示叉叉,除了首页不显示,其他均显示
isNoClosable(item){return item.route !== '/welcome'},
刷新时以当前路由做为tab加入tabs,当前路由不是首页时,添加首页以及另一页到store里,并设置激活状态,当前路由是首页时,添加首页到store,并设置激活状态(注意:this.$route.meta.title的title值要和菜单数据里面的subtitle1名称保持一致!!!)
mounted () {console.log(this.$route);// 刷新时以当前路由做为tab加入tabs// 当前路由不是首页时,添加首页以及另一页面到store里,并设置激活状态// 当前路由是首页时,添加首页到store,并设置激活状态if (this.$route.path !== '/welcome') {this.$store.commit('tabs/add_tabs', {route: '/welcome' , name: '首页'})this.$store.commit('tabs/add_tabs', {route: this.$route.path , name: this.$route.meta.title })this.$store.commit('tabs/set_active_index', this.$route.path)} else {this.$store.commit('tabs/add_tabs', {route: '/welcome', name: '首页'})this.$store.commit('tabs/set_active_index', '/welcome')}}
实现思路大致就是这样,主要自己项目的数据稍作修改。