动态路由和tab页切换路由

动态路由和tab页切换路由

一、在当前页面监听路由的改变

应用场景:我们在需要进入这个页面前判断,上一个页面是不是我们允许的页面,不是的话不能进入;或者离开这个页面的时候判断,进入的是不是允许的页面,不是则拦截。
以下三个函数与created是同级

1、beforeRouterEnter 进入前拦截路由

beforeRouteEnter(to,from, next) {
    console.log(to)
    console.log(from)
    console.log(next)
    if (from.name !== 'A') {
      // vm 就是当前组件的实例相当于上面的 this,所以在 next 方法里你就可以把 vm 当 this 来用了。
      next(vm => vm.$router.push({ name: 'B'}))
    }
    next()
  },

2、beforeRouterUpdate 路由更新时拦截

在当前路由改变,但是该组件被复用时调用,
对于一个带有动态参数的路径 /good/:id,在/good/1和/good/2之间跳转的时候,
由于会渲染同样的good组件,因此组件实例会被复用,而这个钩子就会在这个情况下被调用
beforeRouteUpdate(to, from,next) {
    // 可以访问组件实例 `this`
    console.log(from, 'from');
    if(from.name == 'additional') {
        this.$refs.formPad.resetFields(); 
    }
    next();
},

3、beforeRouterLeave 离开该路由时调用

beforeRouteLeave(to,from, next) {
   // 可以访问组件实例 `this`
   console.log(this, 'beforeRouteLeave'); //当前组件实例
   console.log(to, '组件独享守卫beforeRouteLeave第一个参数');
   console.log(from, '组件独享守卫beforeRouteLeave第二个参数');
   next();
}

二、动态路由

动态路由配置,在系统里添加组件,保存到数据库,在前端不写死路由,动态生成,如果有一个组件位置更改了,直接在系统里进行更改,不用再从router文件中更改。

1、在系统中填入组件信息

一级路由:Layout
二级路由:AppMain
三级路由:对应组件位置
在这里插入图片描述

2、在permission.js路由拦截器中处理路由

在这里插入图片描述

3、filterAsyncRouter处理后台返回的路由数据

 这里的path我是直接取的name名,如果想要更完美,可以直接写好路由相应的属性,后期不用更改

在这里插入图片描述
在这里插入图片描述

三、tab页动态路由切换

在这里插入图片描述

思路:
1.将打开的所有路由放到一个栈里(tabRouterList:[]),tabs显示遍历tabRouterList,
2.初始状态,将首页推入栈,并设置激活状态
3.当切换路由时(监听路由变化),判断栈里是否存在这个路由
  若存在,只改变激活状态;若不存在,则推入栈,并改变激活状态
4.tabs切换,调用@tab-click="tabClick"方法,跳转路由(路有变化,走上一步“若存在,只改变激活状态”)
5.tabs移除,调用@tab-remove="tabRemove"方法,移除栈(tabRouterList)中对应的路由,若移除的路由是激活状态,那么路由跳转到栈中最后一个(路有变化),若移除的路由非激活状态,不做修改
6.tab点击展示下拉菜单功能

1、tab页

在这里插入图片描述
tabRouter页面

<template>
<div class="tabNav">
  <el-tabs
    v-model="activeIndex"
    type="card"
    closable
    v-if="tabList.length"
    @tab-click='tabClick'
    @tab-remove='tabRemove'
    @contextmenu.prevent.native="tabRightClick($event)"
    >
    <el-tab-pane
      :key="Math.random()"
      v-for="(item, index) in tabList"
      :label="item.title"
      :name="item.path"
      >
    </el-tab-pane>
  </el-tabs>
  <div v-show="dropdownShow">
    <ul :style="{left:left+'px',top:top+'px'}" class="contextmenu">
        <li><el-button type="text" @click="curTabReload()" size="mini">重新加载</el-button></li>
        <li><el-button type="text" @click="closeAllTabs()" size="mini">关闭所有</el-button></li>
        <li><el-button type="text" @click="closeOtherTabs()" size="mini">关闭其他</el-button></li>
    </ul>
</div>
</div>
</template>
export default {
  computed: {
    tabList () {
      return this.$store.state.tabRouterPath.tabRouterList
    },
    activeIndex:{
      get () {
        return this.$store.state.tabRouterPath.activeIndex
      },
      set (val) {
        this.$store.commit('setActiveIndex', val);
      }
    }
  },
}

2、准备状态管理(tabRouterPath.js)

import router from '@/router'
const app = {
  state: {
    curContextTabId:'',//右键点击tab的id
    tabRouterList:[],//初始化tab路由列表
    activeIndex:'/home'//激活状态
  },
  getters: {
  },
  mutations: {
    // 添加tabs路由
    setTabRouter(state, data) {
      state.tabRouterList.push(data)
    },
    // 删除tabs路由
    delTabRouter(state, data) {
      let index = 0
      for(let option of state.tabRouterList) {
        if(option.path == data) {
          break
        }
        index++
      }
      state.tabRouterList.splice(index,1)
      // 删完路由后也要保存到session中
      sessionStorage.setItem('tabRouterList', JSON.stringify(state.tabRouterList))
    },
    // 设置当前激活的tabs
    setActiveIndex(state,index) {
      state.activeIndex = index
    },
  }
}
export default app

3、在Layout页面初始化路由状态

mounted(){
    // 设置激活状态保留所有路由,则可以在监听路由的时候把路由保存在sessinStorage里
    // 在home页初始路由状态
    // 刷新时以当前路由做为tab加入tabs
    // 当前路由不是首页时,则在session中取出路由列表渲染,并设置激活状态
    // 当前路由是首页时,判断是第一次进入页面还是后期刷新,如果session中没有数据就添加首页进去,如果有就全部渲染
    // 注意:在点击路由时要把tabRouterList保存到session中,删除也是如此
    let tabList = JSON.parse(sessionStorage.getItem('tabRouterList'))
    if(this.$route.path !== '/' && this.$route.path !== '/home') {
      tabList.forEach(item => {
        this.$store.commit('setTabRouter',{path:item.path,name:item.name,title: item.title})
      })
      this.$store.commit('setActiveIndex',this.$route.path)
    } else {
      this.$store.state.tabRouterPath.tabRouterList = []
      if(tabList){
        tabList.forEach(item => {
          this.$store.commit('setTabRouter',{path:item.path,name:item.name,title: item.title})
        })
      } else {
        this.$store.commit('setTabRouter',{path:'/home',name:'home',title: '首页'})
        sessionStorage.setItem('tabRouterList', JSON.stringify(this.$store.state.tabRouterPath.tabRouterList))
      }
      this.$store.commit('setActiveIndex','/home')
      this.$router.push('/home')
    }
  },

4、监听路由状态

watch: {
   // 监听路由变化
   '$route'(to,from) {
      // 判断路由是否已经打开
      // 已经打开的,将其设置为active
      // 未打开的,将其放入队列里
      let flag = false
      for(let item of this.tabList) {
        if(item.name == to.name) {
          this.$store.commit('setActiveIndex',to.path)
          flag = true
          break
        }
      }
      // 如果要跳转的路由是选择机构页面,则不存路由
      if(to.path == '/mechanism') {
        flag = true
      }
      // 如果页面是隐藏状态,也不添加到路由列表中(比如:添加 修改 详情页面)
      if(to.meta.hidden == 1) {
        flag = true
      }
      if(!flag) {
          this.$store.commit('setTabRouter',{path:to.path, name:to.name, title:to.meta.title})
          this.$store.commit('setActiveIndex',to.path)
          // 将路由保存在sessionStorage中
          sessionStorage.setItem('tabRouterList', JSON.stringify(this.$store.state.tabRouterPath.tabRouterList))
      }
    },

5、tab方法

// tab标签点击时,切换相应的路由
tabClick(tab){
  this.$router.push({path:this.activeIndex})
},
// 移除tab标签
tabRemove(targetName) {
  // 首页不删
  if(targetName == '/home') {
    return
  }
  this.$store.commit('delTabRouter',targetName)
  if(this.activeIndex == targetName) {
    // 设置当前激活的路由
    if(this.tabList && this.tabList.length >=1 ){
      this.$store.commit('setActiveIndex',this.tabList[this.tabList.length-1].path)
      this.$router.push({path: this.activeIndex})
    } else {
      this.$router.push({path: '/'})
      this.$store.state.tabRouterPath.activeIndex = '/home';
      this.$store.commit('setTabRouter',{path:'/home',name:'home',title:'首页'})
    }
  }
},

6、tab下拉菜单方法

①.tab右键单击事件
// tab右键单击事件
tabRightClick(e){
  e.preventDefault(); //防止默认菜单弹出
  if (e.srcElement.id) {
    let currentContextTabId = e.srcElement.id.split("-")[1];
    this.dropdownShow = true;
    this.left = e.clientX;
    this.top = e.clientY;
  }
},
②.关闭下拉菜单
// 关闭下拉菜单
closeDropMenu() {
  this.dropdownShow = false;
},
③.下拉菜单关闭点击事件
// 重新加载
curTabReload(){
  location.reload()
},
// 关闭所有标签页
closeAllTabs() {
  this.$store.commit("closeAllTabs");
  this.dropdownShow = false;
},
// 关闭其它标签页
closeOtherTabs() {
  this.$store.commit("closeOtherTabs");
  this.dropdownShow = false;
},
④.vuex
// 保存右键点击tab的id
saveCurContextTabId(state, curContextTabId) {
  state.curContextTabId = curContextTabId
},
// 关闭所有标签
closeAllTabs(state) {
  state.tabRouterList = [];
  this.commit('setTabRouter',{path:'/home',name:'home',title:'首页'})
  sessionStorage.setItem('tabRouterList', JSON.stringify(state.tabRouterList))
  this.commit("activeIndex", "/home")
  router.push("/home")
},
// 关闭其它标签页
closeOtherTabs(state) {
  let tabs = state.tabRouterList;
  let activeIndex = state.activeIndex
  console.log(activeIndex)
  let curId // 左键点击时的tab在整个tabs数组中的id
  tabs.forEach((tab, index) => {
    if (tab.path == activeIndex) {
      curId = index
    }
  })
  if(activeIndex == '/home') {
    state.tabRouterList = [state.tabRouterList[curId]]
  } else {
    state.tabRouterList = [{path:'/home',name:'home',title:'首页'},state.tabRouterList[curId]]
  }
  sessionStorage.setItem('tabRouterList', JSON.stringify(state.tabRouterList))
}
⑤.watch监听下拉菜单
关闭右键菜单,有时候打开右键菜单没有进行其它操作,右键菜单一直显示
dropdownShow(value) {
  if (this.dropdownShow) {
    document.body.addEventListener("click", this.closeDropMenu);
  } else {
    document.body.removeEventListener("click", this.closeDropMenu);
  }
}
⑥.右键显示的菜单样式
.contextmenu {
  width: 100px;
  margin: 0;
  border: 1px solid #ccc;
  background: #fff;
  z-index: 3000;
  position: fixed;
  list-style-type: none;
  padding: 5px 0;
  border-radius: 4px;
  font-size: 14px;
  color: #4b46a7;
  box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.2);
}
.contextmenu li {
  margin: 0;
  padding: 0px 22px;
}
.contextmenu li:hover {
  background: #ebeef5;
  button{
    color: #4b46a7;
  }
  cursor: pointer;
}
.contextmenu li button{
  color: #2c3e50;
}

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值