vuex+element 从后台获取数据写导航栏-菜单权限

主要用到 vuexrouter.beforeEachrouter.addRoutes()。vuex 的使用方法可以看我的另一篇博客:vue笔记(四)vuex

顺便安利一个 在线视频转gif图

因为第一次用到 router.addRoutes(),在做这个需求的时候遇到了很多问题,这里给大家几个链接,如果碰到了可以点击查看:
1. import 加载组件失败import() 动态加载component组件失败

2. 路由显示结果正确,但是页面总是跳转到 404 页面vue 路由权限 页面刷新时报404问题

3. 每次进入页面时,总是报 name 重复的警告:掘金上的 “luichooy”发表的 vue-router之addRoutes使用遇到的坑,这篇文章对 addRoutes 如何产生这个问题解释挺详细的,但是代码不够详细,我是参考了“学如逆水,不进则退”写的 解决addRoutes后重新登录路由重复警告问题 解决的。


使用vuex 写导航栏

在写静态导航栏时通常会新建一个文件作为组件,数据则是由 this.$router.options.routes 获取。现在我们的路由信息不是从 router 中获取到的,而是从后台获取的,我们暂时先把获取到的这个数据 命名为 menuList,存放在 vuex 中的 state 中。具体代码如下:

思路:

  1. 在 state 中定义一个初始变量 menuList: [],在 actions 中处理请求数据,在 mutations 中将请求到的数据赋值给 state 中的 menuList。
  2. 在组件中获取 state 中处理好的数据。使用 mapGetters
  3. 由于刷新地址,vuex 中的数据会恢复成初始值,使用 router.beforeEach 进行监听,若地址刷新,重新请求数据,使用 $store.dispatch()

1. 登录成功后,发起菜单请求
login(){
  let userInfo = {
    token: "ERRR",
    userCode: "admin",
    userAccount: "管理员"
  }
  sessionStorage.setItem("userInfo", JSON.stringify(userInfo));
  //dispatch中 userInfo 数据可传可不传,因为刷新的时候,这个数据是拿不到的,总 要从 sessionStorage 中获取
  this.$store.dispatch("INIT_MENU");
  this.$router.replace("/")
}

2. 在 store 文件夹下新建 index.js、actions.js、mutations.js、state.js、getters.js。

后台返回数据:(还有一些其他的 id 字段,咱也用不到,这里就不贴了,这个是个大家做一个参考)

{
  code: "0000",
  msg: "处理成功",
  router: [
         {            
            path: '/dealCenter',
            name: 'dealCenter',
            component: "MyLayout",
            meta:{  title: "处理中心", hidden: false },
            children: []
          },          
          {
            path: '/myWorkbench',
            name: 'myWorkbench',
            component: "MyLayout",
            meta:{ title: "我的工作台", hidden: false },
            children: [
              {
                path: "workbenchOne",
                name: "workbench_one",
                meta: { title: "工作台一" },
                component: "/myWorkbench/workbenchOne"
              },
              {
                path: "workbenchTwo",
                name: "workbench_two",
                meta: { title: "工作台二" },
                component: "/myWorkbench/workbenchTwo"
              },
              {
                path: "workbenchThr",
                name: "workbench_thr",
                meta: { title: "工作台三" },
                component: "/myWorkbench/workbenchThr"
              }
            ]
          }
  ]
}

代码:

文件名代码描述
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import actions from './actions'
import mutations from './mutations'
import getters from './getters'
Vue.use(Vuex);
export default new Vuex.Store({
  state, 
  mutations,
  actions,
  getters
})
在 index.js 中引入 actions.js、state.js、mutations.js、getters等文件。
state.js
let state = {
    menuList: []
  }
export default state;
给 menuList 定义一个初始值。
actions.js
import {menu} from "@/components/commonJs/dealMenuData.js"
"INIT_MENU": ( {commit} ) => {
   //调用获取菜单的接口,将获取到的值赋值给 routerArr。
   axios().then( res => {
     if( res.code === "0000"){
     	commit("GET_MENU", menu(res.router))
     } else {
     	commit("GET_MENU", []);
     }
   }   
})
export default actions;
这里的 menu() 是处理从接口中获取到的数据的方法,将数据转换成 routes 路由格式。
mutations.js
let mutations = {
  "GET_MENU"(state, paylod){
    state.menuList = paylod;
  }
}
export default mutations;
将在 actions.js 中处理好的数据赋值给 state 中的 menuList。
getters.js
let getters = {
  menuList: (state)=>{
      return state.menuList;
  }
}
export default getters;
这里要注意,有else返回 [] 的时候和没有else的区别

3. 处理从后台获取的数据,我在 components 下面新建了一个 commonJs 文件夹,commonJs 下面是 dealMenuData.js 。

这里根据你自己定义的 routes 路由格式进行改写。要注意的是:404页面要在 router.addRoutes() 中拼接,具体原因在 步骤5 中会提到。

import Vue from 'vue'
import MyLayout from "@/components/MyLayout"
import NotFound from '@/components/404'
import router from "@/router"
import {createRouter} from "@/router"

function _import(str) { // views文件夹下的Home组件,传入的格式为 'Home'
  return function (resolve) {
    require([`@/views${str}.vue`], resolve);
  };
}

const menu = function (arr) { 
  let result = [];
  
  //将数据进行处理
  if(arr.length!=0){

    for( let i=0; i<arr.length; i++){
      if( arr[i].children.length == 0 ){ //只有一个子菜单
        let oneSonArr = {
          path: "list",
          name: arr[i].name,
          meta: arr[i].meta,
          component: _import(arr[i].path +"/list")
        }
        Vue.set(arr[i].children, 0, oneSonArr);

      } else { //有多个子菜单
        for(let j=0; j<arr[i].children.length; j++){
          let sonArrs = {};
          sonArrs = Object.assign({}, sonArrs, {
            path: arr[i].children[j].path,
            name: arr[i].children[j].name,
            meta: arr[i].children[j].meta,
            component: _import(arr[i].children[j].component)
          });
          Vue.set(arr[i].children, j, sonArrs);  
        }
      }

      result.push({
        path: arr[i].path,
        name: arr[i].name,
        component:  MyLayout,
        redirect: arr[i].children.length == 1 ? arr[i].path+"/list" : arr[i].path +"/"+ arr[i].children[0].path,
        meta: arr[i].meta,
        children: arr[i].children
      })
    }

  }
  
  result.push({ 
    path: "*",
    name: "notFound",
    meta: { hidden: true },
    component: NotFound
  })
  console.log("在处理函数dealMenuData.js中", router)

  router.matcher = createRouter().matcher; //清空addRoutes中之前存下的路由信息
  router.addRoutes(result)
  return result;
}

export {menu};

这一部分可以看一下“前端大虾”的【VUE管理菜单权限】使用router.addRoutes


4. 导航栏组件中使用:

<template>
	<div>{{menuList}}</div>
</template>

<script>
  import { mapGetters } from "vuex";
  export default {
    computed: mapGetters(["menuList"])
  }
</script>

5. 在 router/index.js 中解决页面刷新 menuList 数据被清空的问题:

这里需要注意一下:404 不能写到路由,要在 addroutes 里进行拼接404这个路由。原因是在路由中写 404 ,刷新时因为要调用菜单接口,当前路由下的页面还没有被加载进来,先读取到了写在 router 中的路由,所以会先找到 404页。

import Vue from 'vue'
import VueRouter from 'vue-router'

import MyLayout from '@/components/MyLayout'
import Login from '@/components/login/login.vue'
import notFound from '@/components/404'

import Store from "@/store"
Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    meta: { hidden: true },
    redirect: "/dealCenter"
  },
  {
    path: '/login',
    name: 'login',
    meta: { hidden: true },
    component: Login
  }
]

// const router = new VueRouter({
//   mode: 'history',
//   base: process.env.BASE_URL,
//   routes
// })

const createRouter  = () => new VueRouter({
  mode: 'hash',
  base: process.env.BASE_URL, //根
  routes
});
const router = createRouter();
export { createRouter };

//重复点击导航栏报错
const routerPush = VueRouter.prototype.push;
VueRouter.prototype.push = function (location) {
  return routerPush.call(this, location).catch(error => error)
}

router.beforeEach((to,from,next) => { //全局前置守卫
  //to: 将要进入目标的路由对象
  //form: 即将离开的目标路由对象
  //执行跳转的下一步钩子
  if(!to.name && !from.name){ Store.dispatch("INIT_MENU") } //刷新时,to.name和from.name都为null

  if(!sessionStorage.getItem("userInfo")){ //判断是否存在session值,若不存在表示没有登录
    if(to.name != "login"){ //判断当前页面是不是登录页
      next({name:"login"})
    } else {
      next();
    }
  } else {
    next();
  }
})



export default router

在router中写404页面后,刷新时的状况如下图:
在这里插入图片描述
用慢速将情景还原一下”:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值