vue动态路由,前端请求路由。addRoutes。

vue动态路由,前端请求路由。addRoutes。

 需求:

之前都是前端固定写好路由,然后跳来跳去,虽然做的有根据登录者类型去做左侧菜单筛选(隐藏,显示),也添加了路由守卫对路由进行拦截处理。但是并不安全,因为在初次加载时就默认已经加载了全部路由信息,而且登陆角色类型是存储在缓存中的,稍微修改就会导致菜单重新刷新获取,这样路由、权限也就乱了。具体做法请看  静态路由,分角色进行权限控制。综合考虑后,决定采用动态获取路由的方式去做。

代码 :

router文件 

首先,router/index中引入必须的路由。比如登录,像登陆这种是不需要放在后台进行获取的。其中Home路由是我左右布局的路由,这个就固定写在上面了。login登录需要,也是放在固定的路由中。

import Vue from 'vue'
import Router from 'vue-router'
const Home = () => import('@/components/Home') //主菜单 
Vue.use(Router)

export default new Router({
  routes: [
    //此路由位置,谁排在前面先加载谁
    {
      path: '/',
      redirect: '/login',
      hidden:true,
      userTypeArry:['1','2','3']
    },
    {
        path: '/login',
        name: 'login',
        leaf: true,
        component: resolve =>require(['@/components/Login'],resolve),
        userTypeArry:['1','2','3'],
        hidden:true 
    },
  ]
});

模拟请求路由

去模拟一个请求,其中post这是我封装的一个axios。其实就是返回来了一个对象数组,至于res.data.data.permissions[3]这个是我的模拟数据,模拟取一条出来。里面的child里面的path就是别名,component就是后台返回的组件路由url,name就是你给的名字,其中conponent中的路由信息不能全部放在后台,比如这样 ‘@/components/view/braceletManage/braceletList’,这样是加载不成功的,会报错‘ the request of a dependency is an expression’,所以要采用拼接的写法。

import axios from 'axios';
import {get,post} from './request' //封装axios

 function getMenuList(objdatas){
  let data = post('/eBackUser/login',objdatas).then(function(res){
    console.log(res);
    let menulist = null;
    if(res.data){
      let routerInfo = res.data.data.permissions[3];
      //routerInfo.childPermission[0].url;
      menulist= [{
          path: '',
          name: routerInfo.name,
          component: resolve =>require(['@/components/Home'],resolve),
          userTypeArry:['1','2','3'],
          iconCls: 'iconmenu iconfont icon-zhinengshouhuani',
          children: [
            { path: routerInfo.childPermission[0].permission, component:  resolve =>require(['@/components/view/'+routerInfo.childPermission[0].url],resolve), name: routerInfo.childPermission[0].name }
          ]
        }
      ];
    }
    return menulist;
  })
  return data;
};

export default  getMenuList;

登录

点击登录去调用获取动态路由的函数(getMenuList),注意获取路由时,因为要发请求,所以要搞成同步的,要使用async和awit,不然添加路由会出错。outer.options.routes.push放的是一个个对象,router.addRoutes放的是一个数组对象,添加路由后,我用一个 “l” 把添加后的路由长度进行了记录存储,在刷新页面路由丢失时用到。这个时候不出意外应该是添加成功了,可以登录进去看到正常的菜单了。

 methods: {
    login() {
      let that = this;
      that.loginicon = "el-icon-loading";
      if(that.user_name != "" && that.password!= ""){
        let obj={
          user_name:'admin_ahjd',
          password:'5a673451b6974da765d58f9845ebac2c'
        }
        that.baseFun.setSessionStorage("uandp",JSON.stringify(obj));
        that.$store.commit("setUandp",that.baseFun.getSessionStorage("uandp"));
        getInfo(obj);
      }
      async function getInfo(obj){
        let infos = await getMenuList(obj);
        if(infos!=null){
          // return false;
          router.options.routes.push(infos[0]);
          router.addRoutes(infos); 
          window.sessionStorage.setItem("l",router.options.routes.length);
          that.$router.push("/UserList");
        }else{
          that.$message({
            type: 'error',
            message: '接口异常!'
          });   
          return false;
        }
      }
    }
  },

解析菜单

解析菜单没什么好说的,就不写了。

刷新页面菜单丢失!

路由添加成功后,点击正常,但是刷新页面后addRoutes添加的路由就全部没了,这个时候需要在main.js中就行逻辑处理,main.js中的代码,每次页面在刷新时都会重新执行一遍,所以要在main.js中重新去获取一遍路由,注意:main.js中的代码初次进入就会执行一次,为了防止初次进入就执行跟登陆时执行 导致添加两次路由的情况出现,需要进行判断,在初次进入时判断 “l” 有无值,初次进入时 “l”肯定没有值,所以初次进入时是不会执行获取请求的操作,而有值的情况下(有值的情况就是你登录之后的情况),这个时候因为你刚登陆。“l”的长度肯定是和路由长度相等的,这个时候也不会进行重复请求路由操作。但是如果你登陆后做刷新页面操作,这个时候路由的长度就变了,就和"l"不相等了,这个时候就会重新去请求路由菜单。

// 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 'babel-polyfill'
import Vue from 'vue'
import App from './App'
import baseFun from './baseFun'// 引入公共方法函数
import {get,post} from './request' //封装axios
Vue.prototype.baseFun = baseFun
Vue.prototype.server = {get,post}
import router from './router' //路由
import ElementUI from 'element-ui'; //饿了么UI
import 'element-ui/lib/theme-chalk/index.css';  //饿了么UI
import store from './store'
import Viewer from 'v-viewer'//安装点击放大视图依赖
import 'viewerjs/dist/viewer.css'//放大视图
import getMenuList from './getMenu'
Vue.use(Viewer)
Vue.config.productionTip = false
Vue.use(ElementUI); //饿了么UI

//路由跳转后返回顶部
router.afterEach((to,from,next) => {
  window.scrollTo(0,0);
});



async function getMenu(){
  let upObj = JSON.parse(baseFun.getSessionStorage("uandp"));
  let infos = await getMenuList(upObj);
  router.options.routes.push(infos[0]);
  router.addRoutes(infos); 
}
if(baseFun.getSessionStorage("l") && typeof(baseFun.getSessionStorage("l")) != "undefined"){
  if(baseFun.getSessionStorage("l") != router.options.routes.length){
      console.log(router);
      console.log("!==="); 
      getMenu();
    }
  }


new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

退出系统,清空添加的路由。

登陆后添加成功路由后,这个时候如果点击退出,退到登陆页面。这个时候需要清空路由,不然这个时候再点击登录,就会重复添加。刷新当前页面就可以清空。window.locaton.reload();但是这个刷新操作放在什么地方呢,起初我是放在退出的vue文件里面,但是不行,执行刷新操作后后面的代码就会阻断,就不会跳往登录了。如果放在登录组件中也不行,会导致死循环刷新,后来我想到通过传参的方式解决。传参有两种方式 一种是push一种是params。通过push传递的参数在刷新页面后会丢失。所以我就用这种方式来做。在login的生命周期函数中通过判断有无参数进行刷新操作。另外退出时要删除 "l"

 退出

 signOut() {
        this.$confirm('确定要退出吗?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
          customClass: "messageBox-customClass"
        }).then(() => {
          window.sessionStorage.removeItem("l");  //退出时删除l
          this.$router.push({
            name:"login",
            params:{
              from:'goout'
            }
          }) ;
        }).catch(() => {

        });
      },

 login组件内

 mounted() {
     if(this.$route.params.from == "goout"){    //如果地址栏有from参数则进行刷新当前页面。
       console.log("执行刷新,清空路由!");
       window.location.reload();
     }   
  }

做的时候借鉴了这位大神的文章-----------链接,感谢她的分享。

发布了114 篇原创文章 · 获赞 67 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_38880700/article/details/104927782