效果
后台新建行业和子模块,左侧导航栏动态添加一级导航和二级导航,登录后根据权限列表渲染相应模块。
实现
1.rouer/routers.js存放不需要权限控制的路由
2.api/user.js 添加获取路由的方法
export const getRequestRouter = () => {
return axios.request({
url: baseUri + '',
method: 'get',
headers: { }
})
}
3.lib/util.js中添加获取缓存菜单和格式化菜单的的方法
export const loadMenu = () => {
let list = []
let data = localRead('variableMenuList')
if (!data) {
return list
}
list = formatMenu(JSON.parse(data))
return list
}
export const formatMenu = (list) => {
let res = []
forEach(list, item => {
if (item.componentAddress === 'main') {
item.component = Main
} else {
item.component = () => import('@/view/' + item.componentAddress)
}
if (hasChild(item)) {
item.children = formatMenu(item.children)
}
res.push(item)
})
return res
}
export const updateVariableMenuList=(data,router,store)=>{
return new Promise(resolve => {
let res = []
data.forEach(industry => {
let route = {
path: '/industry-' + industry.value,
name: 'industry-' + industry.value,
meta: {
icon: 'ios-apps',
access:[],
title: industry.name
},
component:null,
componentAddress: 'main',
children: []
}
industry.industryModules.forEach(industryModule => {
route.meta.access.push(industryModule.permission)
let moduleRoute = {
value: industryModule.value,
path: route.path + '/modules/' + industryModule.value,
name: route.name + 'modules-' + industryModule.value,
meta: {
icon: 'md-cube',
title: industryModule.name,
notCache: true,
access:[industryModule.permission],
industryValue: industry.value,
industryModuleValue: industryModule.value
},
component:null,
componentAddress: 'industry-modules/industry_modules_index.vue'
}
route.children.push(moduleRoute)
})
res.push(route)
})
store.commit('updateMenuList', res)
resolve(res)
})
}
4.store/module/app.js,引入添加的方法,修改getters,在mutations中添加updateMenuList方法
import {
formatMenu,
loadMenu
} from '@/libs/util'
state: {
variableMenuList: loadMenu(),//添加的路由
menuRouters: routers //固定路由
},
getters: {
menuList: (state, getters, rootState) => getMenuByRouter(state.menuRouters.concat(state.variableMenuList), rootState.user.access),
errorCount: state => state.errorList.length
},
mutations: {
// 刷新菜单
updateMenuList (state, data) {
if (data) {
localSave('variableMenuList', JSON.stringify(data)) //只能存储格式化之前的路由
state.variableMenuList=[];
state.variableMenuList=formatMenu(data)
}
},
}
5.router/index.js ,引入格式化函数和获取菜单数据的函数,处理路由守卫
import {updateVariableMenuList} from '@/libs/util'
import {getRequestRouter} from '@/api/user'
router.beforeEach((to, from, next) => {
const token = getToken('token')
const access= getToken('access')
if (!token && to.name !== LOGIN_PAGE_NAME) {
// 未登录且要跳转的页面不是登录页
next({
name: LOGIN_PAGE_NAME // 跳转到登录页
})
} else if (!token && to.name === LOGIN_PAGE_NAME) {
// 未登陆且要跳转的页面是登录页
next() // 跳转
} else if (token && to.name === LOGIN_PAGE_NAME) {
// 已登录且要跳转的页面是登录页
next({
name: homeName // 跳转到homeName页
})
} else {
if(!localRead('variableMenuList')){// 如果本地不存在路由缓存
getRequestRouter().then(json=>{
if (json.status == 200) {
updateVariableMenuList(json.data,router,store).then(res=>{
router.addRoutes(res)
next({ ...to, replace: true })
})
}
})
} else if(!store.state.user.access){//用户登录后进行了刷新
store.commit('setAccess', access) //刷新后store中的数据会置空,这里重新赋值,不然权限路由出不来
getRequestRouter().then(json=>{
if (json.status == 200) {
updateVariableMenuList(json.data,router,store).then(res=>{
router.addRoutes(res)
next({ ...to, replace: true })//hack方法 确保addRoutes已完成,防止页面空白
})
}
})
}
else {
next()
}
}
})
6.在添加路由模块页面引入格式化函数,添加新建函数并更新路由
import router from '@/router'
import store from '@/store'
import {updateVariableMenuList} from '@/libs/util'
import {getRequestRouter} from '@/api/user'
methods(){
getIndustryList() {
getRequestRouter().then(json => {
if (json.status == 200) {
updateVariableMenuList(json.data,router,store)
}
})
}
}
参考:https://blog.csdn.net/weixin_41538490/article/details/93749942
关于路由页面
项目中动态添加的每个路由的页面相同,路径不同,所以在meta里添加了行业value和子模块value来区分,
在mounted中接收,但是第二次进入不触发页面渲染,这时可以监听$route的变化,相应组件也要监听value的最新值,来触发页面更新
<template>
<div>
<bannerTop v-if ="industry.moduleValue===1" :industryValue="industry.value" ></bannerTop>
<fugeWebiner v-if ="industry.moduleValue===2" :industryValue="industry.value" ></fugeWebiner>
<fugeLive v-if ="industry.moduleValue===3" :industryValue="industry.value" ></fugeLive>
</div>
</template>
<script>
export default {
name:"",
components: { },
data(){
return{
industry:{
value:0,
moduleValue:0
}
}
},
watch:{
"$route"(to,from){
this.industry.value=this.$route.meta.industryValue
this.industry.moduleValue=this.$route.meta.industryModuleValue
},
},
mounted(){
this.industry.value=this.$route.meta.industryValue
this.industry.moduleValue=this.$route.meta.industryModuleValue
}
}
</script>
//bannerTop
props:{
industryValue:{
type:Number
}
},
watch: {
"industryValue"(to,from){
this.query.category=to
this.getActivityList.bind(this)()
},
},