从零开始配置vue权限控制

权限控制方式

路由彻底由后端返回css

确认控制逻辑

约定后端返回数据格式

children: [ // 子路由放入children属性中
    {
        children: []
        component: "views/index/content/index"
        id: 5
        meta: {isLogin: 1, icon: "el-icon-postcard", title: "项目概览", isShow: 1}
        name: "/home/index/content"
        path: "/home/index/content"
    }
]
component: "views/index" // 对应页面的文件地址
id: 3 // 惟一属性
// isLogin判断是否须要登陆访问,isShow判断是否显示在导航栏上,title展现导航栏名字
meta: {isLogin: 1, icon: "el-icon-date", title: "整体概况", isShow: 1} 
name: "index" // 组件名
path: "index" // 路由地址
复制代码

vue页面配置

1. APP.vue 配置

<template>
  <div id="app">
    <router-view />
  </div>
</template>

复制代码

2.首页设置

根据父子路由的配置,子路由必需要在有rout-view状况下才能切换,因此须要在首页设置导航栏,还有导航栏路由对应的页面vue

相似这种布局ios

<template>
    <div class="main">
        <div class="main-left">
            <!-- 放置导航栏菜单组件 -->
        </div>
        <div class="main-right">
            
            <!-- 右边内容 -->
            <div class="main-right-container">
                <router-view></router-view>
            </div> 
        </div>   
    </div>    
</template>

复制代码

登陆页设置

引入vuex数据vuex

computed: {
    ...mapGetters([
      'menuList'
    ])
},
methods: {
    ...mapActions([
      'getMenuList',
    ]),
}
复制代码
// 登陆后触发的函数
 login() {
     let url='/你的api地址';
     let reqData={};
    
     let res = await Http.axiosPost(url, reqData); // 这里使用axios,晚点出一篇axios配置到原型链的文章
     if (res.code === 200) {
        // 存登陆状态
        localStorage.setItem('Flag','isLogin'); 
        // 存登陆token
        localStorage.setItem('TOKEN',res.obj);
        
        // 调用mapGetters,查看vuex中是否有路由数据
         let code = await this.getMenuList();
        if(code === 200){ // 存在路由
          // 跳转导航栏首页
          let Path= this.menuList[0].children[0].children[0].path
          
          this.$router.push({path: Path})
        }else{ // 不存在路由,说明配置问题了
          console.log('路由获取失败', code)
          MessageBox({
            title: '警告',
            message: '导航配置问题,请联系管理员',
            callback: action => { // 回调函数
              localStorage.clear(); // 清除缓存数据
              next({path: '/login', replace: true }) // 跳转登陆
            }
          })
        }
     } 
 }

复制代码

配置vuex

import Vue from 'vue'
import Vuex from 'vuex'
import { normalRouter } from '../router'
import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)

// 设置只有在开发环境的时候才打印日志
const debug = process.env.NODE_ENV !== 'production'

const state = {
    menuList: '1'
}
const getters = {
    menuList: state => state.menuList
}
const mutations = {
   setMenuList (state, value) {
        // 存入数据
        state.menuList = menus;
        
        // 加入登陆页面等一级路由
        menus = menus.concat(normalRouter)
    
        // matcher是用来解决 Duplicate named routes definition 报错解决路由重复
        VueRouter.matcher = new Router().matcher
        // 错误页面要最后添加,否则访问动态的路由会先出现404
        menus.push({
           path: '*', // 页面不存在的状况下会跳到404页面
           redirect: '/error',
        })
        VueRouter.addRoutes(menus)
   }
}
const actions = {
  // 获取动态路由
  async getMenuList({commit}) {
    // 经过接口获取路由数据
    let url='/你的api地址';
    let reqData={};
    
    let res = await Http.axiosPost(url, reqData); // 这里使用axios,晚点出一篇axios配置到原型链的文章
    if(res.code === 200){ // 成功
      // res.obj[0].component = "views/homepage"
      let menus = needRoutes(res.obj) // 生成路由信息
      
      // 确认路由层级,一级路由只有一个,往下的页面都是子路由
      commit('setMenuList',  [{
        path: "/home",
        component:(resolve) =>{
          require(['@/views/homepage'],resolve)
        },
        meta: { isLogin: true // 添加该字段,表示进入这个路由是须要登陆的
        },
        children:menus
      }])
      return res.code
    } else { // 失败
      return res.code
    }
  }
}

// 生成路由数据
let needRoutes = (data) => {
  // 判断是不是数组
  if (!Array.isArray(data)) {
    return new TypeError('arr must be an array.');
  }
  let arr = formatComponent(data)
  
  return arr;
}

// 递归函数,用来对组件进行异步渲染
let formatComponent = (data) => {
  for (let obj of data) {
    const component = obj.component
    // 把后台返回的路由参数,拼接路径
    obj.component = resolve => { require(['@/' + component], resolve) }
    if (obj.children.length > 0) { // children有长度,说明有子路由
      formatComponent(obj.children)
    }
  }
  return data
}

const store = new Vuex.Store({
    state,
    getters,
    mutations,
    actions,
    strict: debug,
    plugins: debug ? [createLogger()] : []
})
export default store
复制代码

在router页面构建导航守卫

1. 确认默认路由

// 配置一级路由配置和重定向
// login页面和error页面是不须要登陆判断的,能够放在默认路由内
export const normalRouter = [
  {
    path: "/",
    redirect: '/login',
    // meta: {
    //   isLogin: false,  // 添加该字段,表示进入这个路由是须要登陆的
    //   title:'登陆'
    // }
  },
  {
    path: "/login",
    name: "Login",
    // components:require('./views/login'),
    component: resolve => require (['@/views/login'], resolve),
    meta: {
      isLogin: false,  // 添加该字段,表示进入这个路由是须要登陆的
      title:'登陆'
    }
  },
  {
    path: "/home",
    redirect: '/home/index',
  },
  {
    path: "/error",
    name: "error",
    component: error,
    meta: {
      isLogin: false,  // 添加该字段,表示进入这个路由是须要登陆的
      title:'错误'
    }
  },
  ]
复制代码

2. 导入路由中

let router = new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes:normalRouter
});
复制代码

3. 配置全局路由导航守卫

// 由于用到了element ui,因此要引入一下
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)

router.beforeEach( async (to, from, next) => {
  console.log('before路由', to);
  // 获取缓存的登陆状态
  let hasLogin = localStorage.getItem("Flag")
  
  // 有登陆状态
  if (hasLogin) {
    console.log('state', store.state.menuList.length, to, from)
    // 判断vuex中是否有存入路由数据
    if (store.state.menuList.length === 0) {
      
      // 进入到这一步用户已经登陆过,可是又刷新了浏览器,致使路由清空了,因此要在vuex中从新请求路由
      let res = await store.dispatch('getMenuList')
      // code 不为200 时候,说明路由接口报错,须要从新登陆
      if (res !== 200) {
        // element 提示框
        MessageBox({
          title: '警告',
          message: '导航配置问题,请联系管理员',
          callback: action => { // 回调函数
            // 清除登陆缓存数据 
            localStorage.clear();
            // 跳转登陆页
            next({path: '/login', replace: true })
          }
        })
      } else { // 有路由数据
        // router.addRoutes是异步的,因此把全局的跳转 *也动态添加了,同时使用 next({ ...to, replace: true })从新载入
        next({...to, replace: true })
      }
    }
    
    if (to.name === 'Login') { // 已经登陆过,可是访问的是login,强制跳转至首页
      // 这里设置的是vuex中首个导航栏的path地址
      next({
        path: store.state.menuList[0].children[0].children[0].path,
      })
    } else { // 正常跳转
      next()
    }
  } else { // 没有登陆,则强制跳转登陆页
    console.log('to', to)
    // 没有登陆想访问其余页面,跳转至
    if (to.name !== 'Login') {
      next({
        path: '/login',
      })
    } else {
      next()
    }
  }
})
复制代码

参考资料

vue权限路由实现方式总结element-ui

关于addRoutes、axios动态添加路由axios

相关文章
相关标签/搜索