当点击一个菜单栏时,出一个tab

实现tab页的具体思路:

①当点击左侧导航菜单时

获取菜单名,把它设为tab页 的名字,并且标记role为pass(这是作为新增tab页时的判断依据)

methods: {
    			showName(name) {
    				// 把菜单名称放进去,当成tab页的名称
    				this.$store.commit('set_showName', name)
    				this.$store.commit('set_role', "pass");
    			}
    		}

②操作上侧的tab页时

点击tab页时(切换到被点击的tab页实现路由跳转,标记role为nopass)
移除tab页时(如果删除的tab页处于被选中状态,那么当它删除时,被选中状态的下标需要转到还存在的tab页中的最后一个,如果要删除的tab页是最后一个tab页时,删除完之后,直接跳转到了AppMain.Vue组件中,标记role为nopass)

在这里插入图片描述
该tab页主要用了vuex 和element ui中的 tab来实现的

具体代码:
首先先在vuex中的 state.js 定义几个变量

  options: [], //存放tab页对象的容器(主要是路由路径以及tab页的名字)
  activeIndex: '', //激活的tab页路由路径
  showName: 'show', //tab页的标题
  role: "" //用来区分是否是因为左侧菜单被点击造成的路由路径发生改变,是:pass;不是:nopass

export default {
  resturantName: '笑傲江湖',
  jwt: '',
  options: [], //存放tab页对象的容器(主要是路由路径以及tab页的名字)
  activeIndex: '', //激活的tab页路由路径
  showName: 'show', //tab页的标题
  role: "" //用来区分是否是因为左侧菜单被点击造成的路由路径发生改变,是:pass;不是:nopass


}

定义方法 mutations.js

export default { //payload 载荷 保存参数的容器
  setResturantName: (state, payload) => {
    state.resturantName = payload.resturantName;
  },
  setJwt: (state, payload) => {
    state.jwt = payload.jwt;
  },
  // 添加tabs(data包含了路由路径跟tab页名字)
  add_tabs(state, data) {
    this.state.options.push(data);
  },
  // 删除tabs	(route是路由路径)
  delete_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的一个数
  },
  // 设置当前激活的tab
  set_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;
  }
}

获取数据的方法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;
  	}
}

LeftNav.vue
在里面写了个方法jshowname(),获取tab的名字
把菜单名称放进去,当成tab页的名称

<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>
		<el-submenu  :key="'id_'+m.treeNodeId" :index="'id_'+m.treeNodeId" v-for="m in menus">
			<template slot="title">
				<i :class="m.icon"></i>
				<span>{{m.treeNodeName}}</span>
			</template>
			<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:[]//树形菜单
			}
		},
		created() { //钩子函数 对值重新进行渲染
			//获取Bus里存的值
			this.$root.Bus.$on('collapsed-side-click', (v) => {
				this.collapsed = v;
			})

			//拿取树形菜单数据
			let url = this.axios.urls.SYSTEM_MENU_TREE;
			this.axios.post(url, this.ruleForm).then((response) => {
				console.log(response);
				this.menus = response.data.result;
			}).catch(function(error) {
				console.log(error);
			});
		},
    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>

然后在AppMain.vue中显示tab页

<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'
      }
    },
    components: {
      TopNav,
      LeftNav
    },
    created() { //钩子函数 对值重新进行渲染
      //获取Bus里存的值
      this.$root.Bus.$on('collapsed-side-click', (v) => {
        this.asideClass = v ? 'main-aside-collapsed' : 'main-aside'
      })
    },
    methods: {
                // tab切换时,动态的切换路由
                tabClick(tab) {
    							 // v-model="activeIndex"是路由路径
                    let path = this.activeIndex;
                    this.$router.push({ path: path });
    								this.$store.commit('set_role',"nopass");
                },
                tabRemove(targetName) {
    							// console.log(targetName);targetName是路由路径
    								this.$store.commit('set_role',"nopass");
    							  // let tabs = this.editableTabs;
                    this.$store.commit('delete_tabs', targetName);
    								// 如果激活tab页被关闭,那么需要激活别的tab页,最后一个tab页被关闭,那么跳转主界面
                    if (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) {
    				// 只要路由发生改变,就会触发此事件(点击左侧菜单时会触发,删除右侧tab页会触发,切换右侧已存在的tab页会触发)
    						let role=this.$store.state.role;
    						let showName=this.$store.getters.getShowName
    						let 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>

在这里面Appmain.vue中主要添加的三段代码‘

显示tab页的地方

<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>

显示tab,删除tab,添加tab的一些方法

methods: {
                // tab切换时,动态的切换路由
                tabClick(tab) {
    							 // v-model="activeIndex"是路由路径
                    let path = this.activeIndex;
                    this.$router.push({ path: path });
    								this.$store.commit('set_role',"nopass");
                },
                tabRemove(targetName) {
    							// console.log(targetName);targetName是路由路径
    								this.$store.commit('set_role',"nopass");
    							  // let tabs = this.editableTabs;
                    this.$store.commit('delete_tabs', targetName);
    								// 如果激活tab页被关闭,那么需要激活别的tab页,最后一个tab页被关闭,那么跳转主界面
                    if (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) {
    				// 只要路由发生改变,就会触发此事件(点击左侧菜单时会触发,删除右侧tab页会触发,切换右侧已存在的tab页会触发)
    						let role=this.$store.state.role;
    						let showName=this.$store.getters.getShowName
    						let 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);
    				}
    			}
    		}

点击tab页时的样式

<style type="text/css">
	.el-tabs--border-card>.el-tabs__content {
		padding: 0px;
	}

实现子tab页

先看效果
在这里插入图片描述
在密码修改的组件 VuexPage3.vue 中的代码

<template>
	<div>
		<el-tabs :tab-position="tabPosition" style="height: 200px;">
			<el-tab-pane label="密码修改1">密码修改11111</el-tab-pane>
			<el-tab-pane label="密码修改2">密码修改22222</el-tab-pane>
			<el-tab-pane label="密码修改3">密码修改33333</el-tab-pane>
			<el-tab-pane label="密码修改4">密码修改444444</el-tab-pane>
		</el-tabs>
	</div>
</template>

<script>
	export default {
		data() {
			return {
				tabPosition: '评论管理'
			};
		}
	}
</script>

<style>

</style>

相关的配置组件路径在router/index.js中去配置

Logo

前往低代码交流专区

更多推荐