【Vue基础】路由守卫+白名单

路由守卫+白名单

目录:
在这里插入图片描述
核心代码演示:

import router from "./index";
import store from "../store/index";

import { getToKen, removeToKen, removeUserName } from "@/utils/app";

//白名单
const whiteRouter = ['/login'];   //indexOf方法,判断数组中是否存在指定的某个对象,如果不存在,则返回-1

//全局路由守卫   beforeEach:路由改变都会触发
router.beforeEach((to, from, next) => {
    /**
     * next():执行了to里面的路由对象,进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
     *
     *     1.不带参数:指向(进入)to钩子--进入下一个页面,但是不会触发beforeEach
     *     2.带参数next('/')或者next({path:'/'}):进入指定页面,发生路由变化,有变化就会触发beforeEach ---  问题:容易造成死循环--比如next('/index'),当执行到这里的时候,触发beforeEach,又遇到里面的next('/index'),又触发next('/index')......
     *     
     *     如果要进入下一个页面,直接next()--进入to钩子,调用to里面的路径,往下一个页面跑
     * 
     *      console.log(to)  // 进入的页面(下一个页面)
     *      console.log(from) // 离开之前的页面(上一个页面)
     *      console.log(next) // next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。确保要调用 next 方法,否则钩子就不会被 resolved。
     *      
     *      to.path:进入的下一个页面的路径
     *     
     */

    //token令牌--处理权限

    //console.log(to) //index -->在login页面直接输入url跳转到index。 to.path == index
    if (getToKen()) {
        if (to.path === '/login') {
            removeToKen();
            removeUserName();
            store.commit('app/SET_TOKEN', '');
            store.commit('app/SET_USERNAME', '');
            next();
        } else {
            //获取用户角色
            //动态分配路由权限
            next();
        }

        /**
         *  1. to = /console   触发beforeEach,检测到token存在,next() --> 重定向到index
         *  2. to = /index     触发beforeEach,检测到token存在,next() --> 进入控制台首页
         */
        //路由动态添加,分配菜单,每个角色分配不同菜单
        console.log("存在");
    }else{
        // next('/login');  //发生路由指向变化的情况下,会触发beforeEach,又会检测toKen存不存在,造成死循环 --  解决方法:使用白名单!
        console.log("不存在");

        if (whiteRouter.indexOf(to.path) !== -1) {  //当to.path == '/login' 的时候,存在,执行next(),跳到login页面,不触发beforeEach
            next(); //指向(进入)to钩子--进入下一个页面,to.path == '/login'
        }else{
            next('/login'); //发生路由指向变化,触发beforeEach ---> to.path == '/login'
        }

        /**
         *  解析:
         *     1.直接进入 index 的时候,参数to被改变成了 "/index" ,触发路由指向,就会跑beforeEach(第一次)
         *     2.再一次 next 指向了login, 再次发生路由指向,再跑beforeEach (第二次), 参数的to被改变成了 "/login"
         *     3.白名单判断存在,则直接执行next(),因为没有参数,所以不会再跑beforeEach。
         */

    }
     
})

router目录下的index.js
在这里插入图片描述
核心代码演示:

import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);

//引入布局组件
import Layout from '@/views/Layout';

const routes = [
  {
    path: "/",
    redirect: "login",
    hidden:true,
    meta: { 
      name: "主页"
     }
  },
  {
    path: "/login",
    name: "Login",
    hidden:true,
    meta: { 
      name: "登录"
     },
    component:() => import("../views/Login/index.vue")
  },
  /**
   * 控制台
   */
  {
    path: "/console",
    name: "Console",
    redirect: "index",
    meta: { 
      name: "控制台",
      icon: "console"
     },
    component: Layout,
    children: [
      {
        path: "/index",
        name: "Index",
        meta: { 
          name: "首页"
         },
        component: () => import("../views/Console/index.vue")
      }
    ]
  },
  /**
   * 信息管理
   */
  {
    path: "/info",
    name: "Info",
    meta: {
      name: "信息管理",
      icon: "info"
    },
    component: Layout,
    children: [
      {
        path: "/infoIndex",
        name: "InfoIndex",
        meta: {
          name: "信息列表"
        },
        component: () => import("../views/Info/index.vue")
      },
      {
        path: "/infoCategory",
        name: "InfoCategory",
        meta: {
          name: "信息分类"
        },
        component: () => import("../views/Info/category.vue")
      }
    ]
  },
  /**
   * 用户管理
   */
  {
    path: "/user",
    name: "User",
    meta: {
      name: "用户管理",
      icon: "user"
    },
    component: Layout,
    children: [
      {
        path: "/userIndex",
        name: "UserIndex",
        meta: {
          name: "用户列表"
        },
        component: () => import("../views/User/index.vue")
      }
    ]
  }
];

const router = new VueRouter({
  routes
});

export default router;

Store下的index.js
【Vue基础】路由守卫+白名单_第1张图片
核心代码演示:

import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

import app from "./modules/app.js"
import login from "./modules/login.js"
import common from "./modules/common.js"

export default new Vuex.Store({
  modules: {
       app,
       login,
       common
  }
});

Store下的modules下的app.js(common.js和login.js省略)
【Vue基础】路由守卫+白名单_第2张图片
核心代码演示:

import { Login } from "@/api/login";
import { setToKen, removeToKen, removeUserName, setUserName, getUserName } from '@/utils/app';

const state = {  //没有做属性计算的情况下,直接用state可搞定
    isCollapse: JSON.parse(sessionStorage.getItem('isCollapse')) || false,     //JSON.parse:字符串转化为对象     1.优先去拿浏览器存储的值,如果取不到则去 ==> || false
    // isCollapse: JSON.parse(localStorage.getItem('isCollapse')) || false  
    // isCollapse: JSON.parse(Cookie.get('isCollapse')) || false  
    to_ken: '',
    username: getUserName() || ''  //调用方法后,有数据,但是在Vuex中,页面刷新,数据会丢失,所以用cookie存储到的数据为初始数据,有则用cookie存的数据,没有则为''
}

const getters = { //computed  有做属性计算的情况下,用getters
    isCollapse: state => state.isCollapse
}

const mutations = {   //必须的 同步 没有回调处理事情
    SET_COLLAPSE(state) {
        state.isCollapse = !state.isCollapse;
        //html5本地存储
        sessionStorage.setItem('isCollapse', JSON.stringify(state.isCollapse));   //JSON.stringify  转化为字符串类型
        // localStorage.setItem('isCollapse', JSON.stringify(state.isCollapse)); //JSON.stringify  转化为字符串类型

        //cookie存储
        // Cookie.set('isCollapse', JSON.stringify(state.isCollapse));
    },
    SET_TOKEN(state, value) {
        state.to_ken = value
    },
    SET_USERNAME(state, value) {
        state.username = value
    }
}

const actions = {   //可以回调处理事情

    // setMenuStatus({ state, commit }, data) {

    /**
     *  console.log(content)
     *  content.state
     *  content.getters
     *  content.commit
     *  content.rootGetters
     * 
     *  setMenuStatus(content, data) //第一种写法
     *  setMenuStatus({ state,getters,commit,rootGetters }, data)  //对象结构的写法
     */

    // commit('SET_COLLAPSE')   -->同步: 通过actions定义一个方法,然后调用mutations里面的一些东西

    // }

    login({ commit }, requestData) {
        //异步,请求接口返回数据后,接着去做别的事情
        /**
         * 接口A,接口B
         * B接口需要A接口的参数
         */
        return new Promise((resolve, reject) => {   //异步: 可以通过promise,调用一个接口,成功时返回成功状态,失败时返回失败时的状态,再去调用的地方处理相应的事情
            //接口
            Login(requestData).then((response) => {
                //toKen、username 需要存储起来
                let data = response.data.data;
                //普通的方式--login(content, requestData)
                // content.commit('SET_TOKEN',data.token);
                // content.commit('SET_USERNAME', data.username);
                //解构的方式
                commit('SET_TOKEN', data.token);
                commit('SET_USERNAME', data.username);
                setToKen(data.token);
                setUserName(data.username);
                resolve(response)
            }).catch(error => {
                reject(error)
            })
        })
    },
    exit({ commit }){
        return new Promise((resolve, reject) => {
            removeToKen();
            removeUserName();
            commit('SET_TOKEN', '');
            commit('SET_USERNAME', '');
            resolve();
        })
    }
    

}

export default {
    namespaced: true, //开启命名空间 --解决不同模块命名冲突的问题
    state,
    getters,
    mutations,
    actions
};

utils目录下的app.js
【Vue基础】路由守卫+白名单_第3张图片
核心代码演示:

import cookie from "cookie_js";

const adminToKen = "admin_toKen";
const usernameKey = "username";

export function getToKen(){
    return cookie.get(adminToKen);
}

export function setToKen(toKen){
    return cookie.set(adminToKen, toKen);
}

export function removeToKen(){
    return cookie.remove(adminToKen);
}

export function setUserName(value) {
    return cookie.set(usernameKey,value);
}

export function getUserName() {
    return cookie.get(usernameKey);
}

export function removeUserName() {
    return cookie.remove(usernameKey);
}

你可能感兴趣的:(Vue.js,vue,vue.js)