在之前完成的Vue项目中,用到了动态路由。总结了一下特发这篇文章整理思路
Vue项目实现动态更新路由的方式大致分为两种:
- 前端定义好路由,登录时根据用户的权限来动态更改路由 (前端处理路由)
- 登录后获取后台返回用户对应权限的路由集合,调用接口拿到后处理 (后端处理路由)
此文章分享的是第一种类型。
先说一下使用场景和思路:
例如一个管理系统,需要根据用户登录返回的权限等级然后动态的更改routes
中的路由对象,根据用户的权限让用户看到该看到的页面。
用到的技术:
Vuex
、Router
、localStorage
,和一些关键函数(push
、addRoutes
)
这只是一个小案例,所以只是模拟的后台数据,数据如下:
src/data/data.js
export const loginByUserInfo=[
{id:1,"username":"admin",pawssord:"1234","role":"A"},
{id:2,"username":"xiaohong",pawssord:"1234","role":"B"},
{id:3,"username":"xiaoming",pawssord:"1234","role":"C"}
]
字段role
为该用户的权限等级(分为三个权限A、B、C)
现在数据有了,那么就可以实现用户登录了。
Login.vue
export default {
data() {
return {
loginForm: {
username: "admin",
password: "1234",
},
};
},
methods: {
login() { //点击登录执行此方法
this.$store
.dispatch("index/userLongin", this.loginForm) //调用Vuex中actions中userLongin方法验证
.then((res) => {
if (res) {
console.log("登录成功!");
this.$router.push({ path: "/" });
}
})
.catch((error) => {
if (!error) {
console.log("登录失败!");
}
});
},
},
};
template
中的代码块就不贴上来了(太简单了)
当用户点击登录按钮,调用Vuex
中定义的验证方法,返回一个Promise
对象,验证是否登陆成功。
src/store/login
import { loginByUserInfo } from "../../data/data" //获取data数据
const state = {
username: "", //用户名
role: "", //登录用户的权限
newrouter: [] //过滤好的路由规则
}
const mutations = {
// 保存用户名到vuex
SET_USERNAME(state, username) {
state.username = username
},
// 保存权限到vuex
SET_ROLE(state, role) {
state.role = role;
},
// 保存路由规则vuex
SET_NEWROUTER(state, newrouter) {
state.newrouter = newrouter;
}
}
const actions = {
// info:传过来的账号和密码
userLongin({ commit }, info) { //验证是否登录成功
console.log(info);
var data = null;
var count = 0;
for (let index = 0; index < loginByUserInfo.length; index++) {
if (info.username == loginByUserInfo[index].username && info.password == loginByUserInfo[index].pawssord) { // 验证登录是否成功
return new Promise((resolve) => {
commit("SET_USERNAME", loginByUserInfo[index].username); // 保存用户名到Vuex
commit("SET_ROLE", loginByUserInfo[index].role); // 保存权限到vuex
localStorage.setItem("username", loginByUserInfo[index].username); // 保存用户名到本地
localStorage.setItem("role", loginByUserInfo[index].role); // 保存权限到本地
data = { username: loginByUserInfo[index].username, role: loginByUserInfo[index].role } // 返回用户名和权限
resolve(data);
})
}
if (info.username != loginByUserInfo[index].username || info.password != loginByUserInfo[index].pawssord) {
count++;
}
}
if (count == loginByUserInfo.length) { //验证登录失败
return new Promise((resolve,reject) => {
reject(data)
})
}
},
roles({ commit }, newrouter) { //最后把过滤的路由存储路由到Vuex中
console.log(newrouter);
return new Promise((resolve, reject) => {
commit("SET_NEWROUTER", newrouter);
localStorage.getItem("quanxiang", newrouter);
resolve(newrouter);
})
}
}
export default {
namespaced: true,
state,
mutations,
actions,
}
在state
中定义好变量接收用户登录成功后接收用户名、用户权限。newrouter
在这个时候还没有赋值,是在用户登录成功后页面跳转触发router.beforeEach()
全局路由导航守卫时,使用一些判断和filter
过滤后再赋值,你可以仔细看最上面Login.vue
中的代码。(登录成功页面会跳转触发router.beforeEach()
全局路由导航)
src/store/store.js
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex);
import index from "./login/index.js"
// import getters from "./getters"
export const store=new Vuex.Store({
modules:{
index,
},
getters:{
username:state=>state.index.username,
role:state=>state.index.role,
newrouter:state=>state.index.newrouter
}
})
这里使用了vuex
中的modules
概念,src/store/login/index.js
只是一个‘小仓库’会被外面的‘大仓库’src/store/store.js
集中管理。
src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const Login=()=>import("@/components/Login")
const Blue=()=>import("@/components/pages_child/Blue")
const Main=()=>import("@/components/Main")
const Red=()=>import("@/components/pages_child/Red")
const Yellow=()=>import("@/components/pages_child/Yellow")
//不管什么权限,都可以访问的登录路由
export default new Router({
mode:"history",
routes: [
{
// 登录路由规则
path: '/login',
component: Login,
}]
})
// 定义动态路由规则
export const pwerRouter=[{
// 跟组件
path:"/",component:Main,redirect:"/red",hidden:false,
children:[
// 跟组件下面的子组件 可修改
{path:"/red",name:"red",component:Red},
{path:"/Yellow",name:"Yellow",component:Yellow,meta:{role:"B"}},
{path:"/Blue",name:"Blue",component:Blue,meta:{role:"C"}},
]
}]
src/router/index.js
中定义好路由规则并返回,pwerRouter则是需要过滤的路由集合。
那么就要对pwerRouter进行过滤了(关键代码来了)
main.js
核心代码
import Vue from 'vue'
import App from './App'
// 引用自定义动态路由
import {pwerRouter} from './router/index'
// 引用登录路由
import router from "./router/index"
// 引用vuex 包含了小仓库
import {store} from "./store/store.js"
// 定义全局导航守卫 根据权限用来动态的改变路由规则
router.beforeEach((to,from,next)=>{
// 每次跳转都会进入这个方法验证
// 判断是否有权限
if(store.getters.role){ //拿到用户权限进行判断
// 已经存储路由规则到vuex中,就响应的跳转(该去哪就去哪)
if(store.getters.newrouter.length!=0){
next();
}else{ //进行判断和过滤
let newrouter;
//这里的根据项目页面的权限进行判断和过滤
//因为我的小案例是规定A权限的用户可以看到所有页面
if(store.getters.role=="A"){
newrouter=pwerRouter;
}
// 否则就是要过滤路由规则的
else{
let newchild=pwerRouter[0].children.filter(myroute=>{
// 根据filter方法判断留下还是删除该路由
if(myroute.meta){
// 如果用户拥有该选取,并且该权限可以看到这个路由,则留下该路由,否则删除
if(myroute.meta.role==store.getters.role){
return true;
}
return false;
}
else{
return true;
}
})
console.log(newchild);
newrouter=pwerRouter;
// 接收删除后的路由规则
pwerRouter[0].children=newchild;
}
router.addRoutes(newrouter); //拼接路由到Routers
// 最后把路由存储到vuex中
store.dispatch("index/roles",newrouter).then(res=>{
// 跳转到对应的路由
next({...to});
})
}
}
// 没有权限 就先登录
else{
if(["/login"].indexOf(to.path)!=-1){ //如果在登录页跳转登录页
next(); //还是跳转到登录页
}else{
next("/login");
}
}
})
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
当用户登录成功后触发页面跳转,会触发router.beforeEach()
路由守卫进行判断和filter
过滤。
具体怎么判断就需要根据项目权限需要进行判断了,因为这只是个小案例 (只模拟了3个权限级别,A权限可以访问所有页面,B权限可以访问Red、Yellow页面,C权限可以看到Red、Blue页面),所以判断就比较简单,也比较随意。
router.addRoutes(newrouter);
方法把进行过滤的路由追加到Router对象中。
再调用actions中
定义的roles方法,把过滤的路由存储到Vuex中,并且跳转到对应的页面中。
到这里已经完成了根据用户的权限进行判断,并且已经存储到Router对象中和Vuex中
接下来就是把Vuex中的路由渲染到页面,用户点击跳转到对应的页面
src/components/Main.vue
<template>
<div id="mainbox">
<router-link
id="div"
v-for="imter in newrouter[0].children"
:to="imter.path"
:key="imter.id"
>
{{ imter.name }}
</router-link>
<br /><br />
<button v-on:click="stop">退出登录</button>
<br/><br/>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {};
},
created() {},
computed: {
newrouter() {
// 监听Vuex中的路由变化就返回当中的路由渲染到页面
return this.$store.getters.newrouter;
},
},
methods: {
stop() {
this.$router.go(0);
},
},
};
</script>
思路简单易懂,希望对大家有帮助。
最后附上效果图