动态路由(addRoutes) +路由持久化 + 解决路由重复添加(高级权限退出后 低级权限可使用高级权限路由)等问题 + 动态路由权限 + 自定义权限指令

1.首先确认使用哪一种方式进行动态路由添加:我选择的是addRoutes API
2.选用这种方式的坑:1.重复添加路由,每次退出登录(权限不变),会每次重复添加之前添加过得路由,导致警告;权限改变时,不会清除之前的权限路由,由高级降到低级时,只要知道地址,低级权限也可进入高级权限的页面;2.路由持久化,每次刷新都要重新添加一次路由,否者直接跳转404页面

首先看看router文件夹的结构
addRouter.js : 添加路由
index.js : 路由主文件
routerList.js : 初始路由配置文件
setRouter.js : 动态路由匹配组件页面方法

addRouter.js

import router from "@/router";
//传入整合好的真实路由,添加到vue路由
export function addR(routerMap) {
  router.addRoutes(routerMap);
}

index.js

import Vue from "vue";
import Router from "vue-router";
// 引入初始路由配置表
import { routers } from "@/router/routerList";

Vue.use(Router);


const createRouter = () => new Router({
  mode: "history",
  scrollBehavior: () => ({ y: 0 }),
  routes: routers
})
const router = createRouter()
//解决重复登录时重复添加路由 或者 高级权限改低级权限时 某些路由已经注入的问题
export function resetRouter () {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher 
}

export default router

routerList.js

export const routers = [
  {
    path: "/",
    name: "login",
    component: resolve => require(["@/views/basics/login.vue"], resolve) //登录
  },
  {
    path: "*",
    component: resolve => require(["@/views/basics/404.vue"], resolve) // 404页面
  }
];

setRouter.js

import router from '@/router';

export function getList(routerMap, parent){
	// 返回一个map对象
	return routerMap.map((item,i) => {
		
		const currentRouter = {
			// 路由地址 动态拼接生成如 /dashboard/workplace
			path: `${parent && parent.path || ''}/${item.path}`,
			// 路由名称
			name: item.name || item.key || '',
			// 该路由对应页面的组件
			component: resolve => require(["@/views/" + item.component], resolve),
			//标题
			title:item.meta.title,
			//源信息
			meta: item.meta,
			//
			key:item.key,
		}
		// 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
		currentRouter.path = currentRouter.path.replace('//', '/')
		// 路由重定向
		item.redirect && (currentRouter.redirect = item.redirect)
		// 子菜单递归循环
		if (item.children && item.children.length > 0) {
			currentRouter.children = getList(item.children, currentRouter)
		}
		// 返回路由数组
		return currentRouter
	})
};

到这里为止 基本准备工作已经完成,接下来就是使用了!

我的登录页面方法

//处理前路由数据结构展示

// 处理后路由数据结构展示

首先引入 文件 结构出上下文中的方法
import router from "@/router";
import { getList } from "@/router/setRouter.js";
import { resetRouter } from '@/router/index.js';
this.$api.Login(
	{ 
		password: values.psd, 
		username: values.name 
	}
).then(res => {
	if(res.code == 0){
		//存储token
		localStorage.setItem("token", res.data.accessToken);
        this.savetoken(res.data.accessToken);
        //获取后端返回的路由对象
        this.$api.Menu().then(res2 => {
			if(res2.code == 0){
					//自定义Loading组件
					this.$Loading.show();
					//调用setRouter.js 中抛出的getList方法
					//返回一个匹配好的路由表对象
                    let routerList = getList(res2.data);
                    //index.js 中抛出的resetRouter方法
                    // 清空路由防止重复添加 或者清除之前添加的权限路由
					resetRouter();
					//使用addRoutes API添加路由
                    router.addRoutes(routerList);
					//跳转
			}
		})
	}
})

到此动态路由添加完成,接下来就是对动态路由进行数据持久化

main.js 路由拦截器

router.beforeEach((to, form, next) => {
	  //如果进入到的路由是登录页或者注册页面,则正常展示
	  let flag = localStorage.getItem("token");
	  //判断是否有token
	  if (to.path == "/") {
		    if (flag == "" || flag == null) {
		    	//没有token 又访问根路由  就去登录
		      	next();
		    } else {
		    	  //有token 又访问根路由  首页
		    	  //获取首页path
			      let path = localStorage.getItem("sPath");
			      //获取侧边栏需要的key
				  let code = localStorage.getItem("sCode");
				  //设置侧边栏选中高亮
				  localStorage.setItem("leftCode", code);
				  //跳转首页
			      next(path);
		    }
	  } else {
	  		//访问非根路由
	  		//判断store.state.rList.length 是否为0
	  		//如果为0  则证明页面刷新过 
		    if (store.state.rList.length === 0) {
			      let list = [];
			      axios.get('xxxxx').then(res =>{
						if(res.code == 0 ){
							list = res.data;
						}
				  })
			      
			      let routerList = getList(list);
			      //设置侧边栏渲染所需的数据
			      store.state.leftVal = routerList;
			      //上方引入 addR方法  调用方法添加路由
			      addR(routerList);
			      //跳转 replace: true 不添加到历史记录
			      next({ ...to, replace: true });
		    } else {
		    	 // 否则直接跳转
		     	 next();
		    }
	  }
});

至此动态路由持久化完成

接下来就是把页面按钮权限加入到页面
首先 我们在路由源信息里面加入了 permission 这个参数
我们现在要做的就是从路由中取出它 并与页面权限作对比 有则显示 无则隐藏

在这里 我们使用自定义指令的方式来实现

在src目录下新建一个 power文件夹 在里面新建一个 index.js

//首先引入Vue
import Vue from "vue";

const own = Vue.directive("own", {
  //绑定元素插入到DOM中  要做的事
  // 参数: 绑定的元素, 信息 , 虚拟节点对象
  //binding
    //binding:一个对象,包含以下 property:
	//name:指令名,不包括 v- 前缀。
	//value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
	//oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
	//expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
	//arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
	//modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
	//vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
	//oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。 
	
  inserted: function(el, binding, vnode) {
    let btn = "";
    //获取单个按钮权限指令所绑定的值
    let btnAdmin = binding.value;
    //判断是否有绑定值  没有就直接return
    if (btnAdmin) {
      btn = btnAdmin;
    } else {
      //无权限直接返回
      return;
    }
	//从虚拟节点中获取路由元信息
	//判断是否为空对象 如果是直接return
    if (JSON.stringify(vnode.context.$route.meta) == "{}") {
      return;
    }
    //从传入的虚拟节点中获取按钮权限列表
    let list = vnode.context.$route.meta.permission;
	// 判断列表中是否含有 这个指令绑定的值 没有就隐藏这个按钮
    if (list.indexOf(btn) == -1) {
      el.style.display = "none"; //隐藏元素
    }
  }
});

在main.js中引入own

//自定义权限指令has 必须引入
import own from "./power/index.js";
Vue.use(own)

权限使用

<button @click='goPage' v-own="'edit'">GO cs3</button>

好的 完结撒花
写在最后,第一次写长篇大论,如有写的不好的请多包含,也可以加入QQ群一起交流:742189737

最后会上传一个已经实现动态路由和权限按钮的demo 里面用了 vuex 模块化 mock数据写在vue.config.js中 可以自行修改,自行参考这篇博客 实现持久化路由 请求写在vuex login模块里 可自行修改使用
下载资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值