目录

效果如下


这个功能主要是靠elementUI的tab+Vuex来实现的,下面就来介绍如何实现的

思路:首先我们正常点击菜单跳转页面是靠路由实现的,然后我们需要点击菜单生成tab页和设置显示的tab页,所以我们需要用Vuex定义一个数组options,用来存放添加进去的tab页,还有一个设置显示哪个tab页的属性activeIndex,所以在点击时我们把这个页面的信息存放到options里面,点击删除就把这个tab的信息从options里面删除,然后当我们每次点击时就把点击的那个tab页的设置为激活

思路导图

这是我的项目结构目录


Vuex分成五个部分:
1.State:单一状态树
2.Getters:状态获取
3.Mutations:触发同步事件
4.Actions:提交mutation,可以包含异步操作
5.Module:将vuex进行分模块

首先在state.js定义属性值,role是用来判断是否调用方法的一个参数,其他的属性是我这个项目其他功能所需

export default {resturantName: '飞哥餐馆',jwt:null,options: [],activeIndex: '',showName:'show',role:""
}

getters.js设置获取值的方法

export default {getResturantName: (state) => {return state.resturantName;},getJwt: (state) => {return state.jwt;},getShowName:(state) => {return state.showName;},getOptions:(state) => {return state.options;},getRole:(state) =>{return state.role;}
}

mumations.js,这里删除数组里面的元素用的是splice这个函数

export default {setResturantName: (state, payload) => {state.resturantName = payload.resturantName;},setJwt: (state, payload) => {state.jwt= payload.jwt;},// 添加tabsadd_tabs(state, data) {this.state.options.push(data);},// 删除tabsdelete_tabs(state, route) {let index = 0;for (let option of state.options) {if (option.route === route) {break;}index++;}this.state.options.splice(index, 1);//删除options里面下标为Index的一个数},// 设置当前激活的tabset_active_index(state, index) {this.state.activeIndex = index;},//设置tab页显示标题set_showName(state,name){this.state.showName=name;},set_role(state,role){this.state.role=role;}
}

index.js

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import getters from './getters'
import actions from './actions'
import mutations from './mutations'//   ./就是代表同层级Vue.use(Vuex)const store = new Vuex.Store({state,getters,actions,mutations})export default store

LeftNav.vue,左侧菜单

<template> <el-menu router :default-active="$route.path" default-active="2" class="el-menu-vertical-demo" background-color="#334157" text-color="#fff"active-text-color="#ffd04b" :collapse="collapsed"><!-- <el-menu default-active="2" :collapse="collapsed" collapse-transition router :default-active="$route.path" unique-opened class="el-menu-vertical-demo" background-color="#334157" text-color="#fff" active-text-color="#ffd04b"> --><div class="logobox"><img class="logoimg" src="../assets/img/logo.png" alt=""></div><!-- 注意:index是必填的属性  1、index可以看成ID,也就是说它是唯一的2、它代表路由的跳转路径--><el-submenu :index="'id_'+m.treeNodeId" v-for="m in menus"><template slot="title"><i :class="m.icon"></i><span>{{m.treeNodeName}}</span></template><!-- :index="m2.url" --><el-menu-item :key="'id_'+m2.treeNodeId" :index="m2.url" @click="showName(m2.treeNodeName)" v-for="m2 in m.children"><template slot="title"><i :class="m2.icon"></i><span>{{m2.treeNodeName}}</span></template></el-menu-item></el-submenu></el-menu></template><script>export default {data() {return {collapsed: false,menus: [],editableTabsValue: '2',tabIndex: 2}},created() {// 监听事件this.$root.Bus.$on("collapsed-side", (v) => {this.collapsed = v;});let url = this.axios.urls.SYSTEM_MENU_TREE;this.axios.post(url, {}).then((response) => {// console.log(response)this.menus = response.data.result}).catch((response) => {console.log(response)});},methods:{showName(name){// 把菜单名称放进去,当成tab页的名称this.$store.commit('set_showName', name)this.$store.commit('set_role', "pass");}}}
</script>
<style>.el-menu-vertical-demo:not(.el-menu--collapse) {width: 240px;min-height: 400px;}.el-menu-vertical-demo:not(.el-menu--collapse) {border: none;text-align: left;}.el-menu-item-group__title {padding: 0px;}.el-menu-bg {background-color: #1f2d3d !important;}.el-menu {border: none;}.logobox {height: 40px;line-height: 40px;color: #9d9d9d;font-size: 20px;text-align: center;padding: 20px 0px;}.logoimg {height: 40px;}
</style>

主页面,也将是tab显示页,AppMain.vue,功能主要都在这个页面

<template><el-container class="main-container"><el-aside v-bind:class="asideClass"><LeftNav></LeftNav></el-aside><el-container><el-header class="main-header"><TopNav></TopNav></el-header><div class="template-tabs"><el-tabs v-model="activeIndex" type="border-card" closable @tab-click="tabClick" @tab-remove="tabRemove"><el-tab-pane :key="item.name" v-for="(item, index) in options" :label="item.name" :name="item.route"></el-tab-pane></el-tabs></div><el-main class="main-center"><router-view></router-view></el-main></el-container></el-container>
</template><script>// 导入组件import TopNav from '@/components/TopNav.vue'import LeftNav from '@/components/LeftNav.vue'// 导出模块export default {data() {return {asideClass: 'main-aside',editableTabsValue: '',editableTabs: []}},components: {TopNav,LeftNav},created() {this.$root.Bus.$on("collapsed-side", (v) => {this.asideClass = v ? 'main-aside-collapsed' : 'main-aside';})},methods: {// tab切换时,动态的切换路由tabClick(tab) {let path = this.activeIndex;this.$router.push({ path: path });this.$store.commit('set_role',"nopass");},tabRemove(targetName) {this.$store.commit('set_role',"nopass");// let tabs = this.editableTabs;this.$store.commit('delete_tabs', targetName);// 如果激活的关闭的tab就是激活的tabif (this.activeIndex === targetName) {// 设置当前激活的路由if (this.options && this.options.length >= 1) {this.$store.commit('set_active_index', this.options[this.options.length - 1].route);this.$router.push({ path: this.activeIndex });} else {this.$router.push({ path: '/AppMain' });}}}},watch: {'$route'(to) {let role=this.$store.state.role;let showName=this.$store.getters.getShowNamelet flag = false;//判断是否页面中是否已经存在该路由下的tab页//options记录当前页面中已存在的tab页for (let option of this.options) {//用名称匹配,如果存在即将对应的tab页设置为active显示桌面前端if (option.name === showName) {flag = true;this.$store.commit('set_active_index',  to.path);break;}}//如果不存在,则新增tab页,再将新增的tab页设置为active显示在桌面前端// if(role!='nopass'){}if(role=='pass'){if (!flag) {this.$store.commit('add_tabs', { route: to.path, name: showName});this.$store.commit('set_active_index',  to.path);}}}},computed: {options() {return this.$store.state.options;},//动态设置及获取当前激活的tab页activeIndex: {get() {return this.$store.state.activeIndex;},set(val) {this.$store.commit('set_active_index', val);}}}};</script>
<style type="text/css">.el-tabs--border-card>.el-tabs__content {padding: 0px;}
</style>
<style scoped>.main-container {height: 100%;width: 100%;box-sizing: border-box;}.main-aside-collapsed {/* 在CSS中,通过对某一样式声明! important ,可以更改默认的CSS样式优先级规则,使该条样式属性声明具有最高优先级 */width: 64px !important;height: 100%;background-color: #334157;margin: 0px;}.main-aside {width: 240px !important;height: 100%;background-color: #334157;margin: 0px;}.main-header,.main-center {padding: 0px;border-left: 2px solid #333;}</style>

所需路由挂载index.js

import Vue from 'vue'
import Router from 'vue-router'
import login from '@/views/login'
import reg from '@/views/reg'
import AppMain from '@/components/AppMain'
import Articles from '@/views/sys/Articles'
import VuexPage1 from '@/views/sys/VuexPage1'
import VuexPage2 from '@/views/sys/VuexPage2'Vue.use(Router) export default new Router({routes: [{path: '/',name: 'login',component: login},{path: '/login',name: 'login',component: login},{path: '/reg',name: 'reg',component: reg},{path: '/AppMain',name: 'AppMain',component: AppMain,children:[{path: '/sys/Articles',name: 'Articles',component: Articles},{  path: '/sys/VuexPage1',name: 'VuexPage1',component: VuexPage1},{path: '/sys/VuexPage2',name: 'VuexPage2',component: VuexPage2}]}]
})

组件挂载main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import 'element-ui/lib/theme-chalk/index.css'
// process.env.MOCK && require('@/mock')
import App from './App'
import router from './router'
import store from './store'
import ElementUI from 'element-ui' //引入
import VueAxios from 'vue-axios'
import axios from '@/api/http'Vue.use(VueAxios, axios)
Vue.use(ElementUI)
Vue.config.productionTip = false/* eslint-disable no-new */
window.vm = new Vue({el: '#app',data() {return {Bus: new Vue({})};},router,store,components: {App},template: '<App/>'
})

然后这个功能是基于上篇博客的代码实现的,有代码不懂的可以看一下SPA动态树和数据表格

end…

vue+elementUI点击菜单添加tab相关推荐

  1. Vue头部菜单,点击菜单新增tab页签

    Vue头部菜单,点击菜单新增tab页签 <template> <div class="wrapper"> <!-- 页面头部部分 -->< ...

  2. element-ui中点击菜单,改变当前菜单背景颜色

    需求: vue项目中,点击左侧菜单,tags页显示当前打开的菜单,并且高亮显示当前菜单 实现效果: 实现代码:在vuex里面定义tags存放所有打开的菜单,和当前打开的索引curtagsIndex:, ...

  3. vue+ElementUI的树形菜单背景颜色修改

    前言 最近开发项目遇到一个问题,就是原型图中树形菜单背景颜色是透明的但是默认的树形菜单背景颜色是白色的,用style更改不了背景颜色,最后找到了解决办法. 解决办法 根据项目路径F:\project\ ...

  4. vue+element-UI实现右键菜单

    转载请注明原文地址 大体思路类似,具体实现在于控件是否提供了右键菜单的回调方法. 右键菜单的样式也可以根据自己需求进行变更. 新版本 基于vue3 支持自动调整偏移量,防止菜单超出屏幕 封装right ...

  5. 前后端分离,基于vue+elementUI的动态菜单

    制作动态菜单的思路: 就是当前用户登陆后,保存用户的信息,通过用户的id,去查找该用户对象的菜单.后台获取的菜单数据,最终传给前台形式就是父菜单里包含了所有的子菜单:并在前台登录成功后,把菜单数据取出 ...

  6. vue 重复点击菜单,路由重复报错

    报错信息 vue-router在3.0版本以上时,重复点菜单,控制台会报错,虽然不影响使用,但是最好处理下这个问题,不然也可能会影响调试其他问题. 报错原因 vue-router在3.0版本以上时 , ...

  7. 分享一个VUE Element-UI 的多级菜单动态渲染的组件

    以下是组件代码: <template><div class="navMenu"><label v-for="navMenu in navMe ...

  8. Web前端-Vue ElementUI点击Table 索引行获取index处理

    需求:在table中row行 index = 0 ,作为区头,数据字符展示 "--" 参考组件  Element - The world's most popular Vue UI ...

  9. Vue+element-ui实现含有多个tab标签页的编辑页面,watch监听数据变更,切换tab页时提醒数据变更。

    思路: 1.监听表单绑定数据的变更 2.切换页面时判断表单绑定数据是否发生变更.如果发生变更,给出提示,由用户选择放弃变更跳转到新的tab还是留在原tab页面. <template>< ...

最新文章

  1. mysql 写入400_MySQL5.7运行CPU达百分之400处理方案
  2. 中科院王斌教授加入小米,任自然语言处理首席科学家
  3. python之路day05--字典的增删改查,嵌套
  4. SAP Spartacus page-slot.component.html
  5. 女人,向《奋斗》中的夏琳米莱们学习什么
  6. IDEA中一个工程多个模块(module)分别提交到不同的git服务器
  7. spring-boot基础知识
  8. git如何选择性合并_看小姐姐用动图展示10大Git命令
  9. java添加日志打印出sql语句_实现Mybatis在控制台和日志文件中打印SQL语句
  10. Linux基础----Makefile文件的编写
  11. 微信h5 支付,已经获得weixin://wap/pay?prepayid,但是无法调起微信客户端支付
  12. 他说,我可能以后不干安全了
  13. 回首2021,展望2022 | 观成科技步履不停,刻画安全图腾
  14. matlab兔子问题,【matlab】狼追击兔子问题的建模
  15. 树莓派搭建http服务器实现网页监控摄像头
  16. Predicting Human Mobility via Graph Convolutional Dual-attentive Networks
  17. psu 计算机 排名,PSU研究生计算机科学排名,真慎重来考察
  18. 最热门的十种编程语言,总有一种适合你
  19. adc 采样时间 采样周期数 采样频率计算(以stm32为例)
  20. 将输入的单词按首字母排序

热门文章

  1. 手机上如何制作出好看的证件照片
  2. 五、阵列信号处理(2)
  3. 《Linux操作系统-系统移植》第8章 USB-4G/LTE移植 -第3节 USB-4G移植(移远AG35开发-Gobi拨号)
  4. Linux服务器下JMeter的安装以及Xming的使用
  5. Xming 多屏选项
  6. javascript 全局作用域,函数作用域详解(配图解)
  7. Unity Open Day 北京站-黑马训练营专场:小团队运研一体走出国门
  8. 迅雷星域CDN众筹引来小米,平安WiFi众筹意欲何为
  9. 有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来。第二天之两数之和调试记录
  10. 密码破解之RADIUS-CHAP-MD5