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();
     }   
  }

做的時候借鑑了這位大神的文章-----------鏈接,感謝她的分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章