说明:
近期编写vue项目从数据库中获取导航栏,记录下。
项目
vue-element-admin vue项目是根据 大佬 上传结构的这个简单修改的,搜索
vue-element-admin 第一个就是,附上地址:
vue-element-admin
可以仔细研究下这个项目,很强。
所有修改文件说明
一,需要改写的js(整理):
根据项目结构需要修改:
【api】包下的 user.js:获取后台传的树形结构 json 方法。
【router】包下 index.js 就是我们的加载的路由设置为空数组就好啦。
【store】包下 【modules】包下 permission.js: 这里面有获取后台json
处理,还有原来的项目匹配权限等等。
开始修改
1,修改user.js:
加上一个方法getAuthMenu,向后台获取请求 ,在premission.js会调用这个方法匹配。
【代码】:
export function getAuthMenu(token) {
return request({
url: 'menu/getMenus',
method: 'post',
params: { token }
})
}
【图片说明】
到此 user.js 修改完毕。。。。。。-----------手动分割----------。。。。。
二,修改 router 包下 index.js
修改index只需把以前配置的路由清除就ok啦,保留404(或者写一个)其他都不需要动。
【代码】
/**
* asyncRoutes
* 需要通过角色判断是否显示的菜单
*/
export const asyncRoutes = [
{ path: '*', redirect: '/404', hidden: true }
]
【图片说明】
-----------手动分割---------------修改完毕。
三,前两步修改完毕剩下最后一步啦,就是修改store下modules下的permission.js啦
这里只需要修改二个地方即可。
需要修改的地方:const actions = {}
【代码】
修改的地方,调用user.js里写的getAuthMenu方法 获取后台传入的json字符串。然后获取 index.js 的asuncRoutes(也就是我们修改的地方) 把数据放进去(注意:404是放在最后的)
代码中也有注释:
const actions = {
generateRoutes({ state, commit, rootState }, { authList, name }) {
return new Promise(resolve => {
// 先查询后台并返回左侧菜单数据并把数据添加到路由(user.js)
getAuthMenu(state.token).then(response => {
// 获取router下index.js中的asyncRoutes
const tempAsyncRoutes = Object.assign([], asyncRoutes)
// 动态循环路由信息 (此方法下面有说明)
generaMenu(tempAsyncRoutes, response.menus)
let allRoutes = deepClone(state.allRoutes) // 深拷贝一份 asyncRoutes,不影响vuex中保存的 asyncRoutes
// 如果 allRoutes 长度为0 说明是刷新了页面,导致 vuex 被清空
if (allRoutes.length === 0) {
// 直接使用 asyncRoutes
allRoutes = tempAsyncRoutes
}
// 先在vuex里存放一份完整的路由信息,深拷贝,vuex里保存的asyncRoutes 与此处的asyncRoutes无关,此处的asyncRoutes会改变
commit('SET_allRoutes', deepClone(allRoutes))
let accessedRoutes = []
if (name === 'admin') {
accessedRoutes = allRoutes || [] // 全部显示 管理员
} else {
//如果不是管理员 匹配权限信息,filterAsyncRoutes 方法是vue-element-admin写好 的,不需要修改
accessedRoutes = filterAsyncRoutes(allRoutes, authList)
}
commit('SET_ROUTES', accessedRoutes)
commit('SET_AUTH', authList)
resolve(accessedRoutes)
}).catch(error => {
console.log(error)
})
})
},
clearRoutes({ commit }) {
commit('CLEAR_ROUTES')
},
setAllRoutes({ commit }, allRoutes) {
commit('SET_allRoutes', allRoutes)
}
}
** getAuthMenu(state.token).then(response =>方法,说明:**
该方法是查询后台数据 返回json,tempAsyncRoutes是在index.js修改的asyncRoutes方法,response.menus 是后台返回的字符串。
generateRoutes({ state, commit, rootState }, { authList, name }) 说明:
这里面的自行修改,原来的是generateRoutes({ commit }, roles) ,因为根据业务需求修改的,可以认为roles是authList,name就是登录时获取的登录人。
generaMenu(tempAsyncRoutes, response.menus)
此处是根据后台传回来的数据 递归分配一些参数等等(因为后台返回时只确认啦子父级关系。)代码如下:
export function generaMenu(routes, menuList) {
let temp = []
for (let i = 0; i < menuList.length; i++) {
if (menuList[i].childNodes && menuList[i].childNodes.length >= 1) {
temp = temp.concat(menuList[i].childNodes)
} else {
temp = []
}
if (menuList[i].menuPath && /\S/.test(menuList[i].menuPath)) {
const menu = {
id: menuList[i].menuId,
path: menuList[i].menuPath === '#' ? menuList[i].menuId + '_key' : menuList[i].menuPath,
component: menuList[i].component === '#' ? Layout : () => import(`@/views${menuList[i].component}`),
name: 'menu_' + menuList[i].menuName,
meta: {
title: menuList[i].title,
icon: menuList[i].menuIcon,
auth: menuList[i].permission === '#' ? null : ['' + menuList[i].permission + '']
}
}
if (temp.length >= 1) {
menu.alwaysShow = true
const child = []
generaMenu(child, temp)
menu.children = child
temp = []
}
routes.push(menu)
}
}
}
component: menuList[i].component === ‘#’ ? Layout : () => import(@/views${menuList[i].component}
),
这一行代码是懒加载,动态引入的。所有的业务页面在
views下面,数据库存的试试路径,如:/comment/materList。
加载时先加载views下,等点击左侧导航时在加载相应页面路径。
也就等于:
component: menuList[i].component === ‘#’ ? Layout : () => import(‘@/views/comment/materList’),
---------------------------手动分割-------------------------------
到此结束------------------------------------------------------。
附上 permission.js 所有代码
import { asyncRoutes, constantRoutes } from '@/router'
import { getAuthMenu } from '@/api/user'
import Layout from '@/layout'
import { deepClone } from '@/utils' // 深拷贝
/**
* 后台查询的菜单数据拼装成路由格式的数据
* @param routes
* @param menuList 后台得到集合
*/
export function generaMenu(routes, menuList) {
let temp = []
for (let i = 0; i < menuList.length; i++) {
if (menuList[i].childNodes && menuList[i].childNodes.length >= 1) {
temp = temp.concat(menuList[i].childNodes)
} else {
temp = []
}
if (menuList[i].menuPath && /\S/.test(menuList[i].menuPath)) {
const menu = {
id: menuList[i].menuId,
path: menuList[i].menuPath === '#' ? menuList[i].menuId + '_key' : menuList[i].menuPath,
component: menuList[i].component === '#' ? Layout : () => import(`@/views${menuList[i].component}`),
name: 'menu_' + menuList[i].menuName,
meta: {
title: menuList[i].title,
icon: menuList[i].menuIcon,
auth: menuList[i].permission === '#' ? null : ['' + menuList[i].permission + '']
}
}
if (temp.length >= 1) {
menu.alwaysShow = true
const child = []
generaMenu(child, temp)
menu.children = child
temp = []
}
routes.push(menu)
}
}
}
/**
* 判断权限
* @param authList
* @param route
*/
function hasAuthorization(authList, route) {
console.log(route)
if (route.meta && route.meta.auth) { // 当前路由有meta 并且 meta下有auth
return authList.some(auth => { // .some :数组中的元素是否满足指定条件
return route.meta.auth.some(routeAuth => {
return routeAuth === auth
})
})
} else { // 当前路由无meta 或 auth(1:无需鉴权;2:有children)
return true
}
}
// 路由与用户权限集合匹配的方法
export function filterAsyncRoutes(routes, authList) {
const res = []
routes.forEach(route => {
const tmp = route
if (hasAuthorization(authList, tmp)) { // 先判断当前路由是否有权限
if (tmp.children) { // tmp下有children时,用children递归
tmp.children = filterAsyncRoutes(tmp.children, authList)
}
// children等于undefined:当前路由没有下级路由,且有访问权限
// children.length > 0:当前路由有下级路由,且下级路由有访问权限,则把当前路由添加到返回值
if (typeof (tmp.children) === 'undefined' || tmp.children.length > 0) {
res.push(tmp)
}
}
})
return res
}
const state = {
allRoutes: [], // 侧边栏生成前,保存一份完整的路由信息
routes: [],
addRoutes: [],
authList: []
}
const getters = {
hasAuthorizations: (state, getters, rootState) => authorization => {
// 如果用户名为superadmin,显示所有按钮
if (rootState.user.name === 'superadmin') {
return true
}
return state.authList.some(auth => {
return auth === authorization
})
}
}
const mutations = {
SET_allRoutes: (state, allRoutes) => {
state.allRoutes = allRoutes
},
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
},
SET_AUTH: (state, authList) => {
state.authList = authList
},
CLEAR_ROUTES: (state) => {
state.routes = []
state.addRoutes = []
state.authList = []
}
}
const actions = {
generateRoutes({ state, commit, rootState }, { authList, name }) {
return new Promise(resolve => {
// 先查询后台并返回左侧菜单数据并把数据添加到路由
getAuthMenu(state.token).then(response => {
// 获取router下index.js中的asyncRoutes
const tempAsyncRoutes = Object.assign([], asyncRoutes)
// 动态循环路由信息
generaMenu(tempAsyncRoutes, response.menus)
let allRoutes = deepClone(state.allRoutes) // 深拷贝一份 asyncRoutes,不影响vuex中保存的 asyncRoutes
// 如果 allRoutes 长度为0 说明是刷新了页面,导致 vuex 被清空
if (allRoutes.length === 0) {
// 直接使用 asyncRoutes
allRoutes = tempAsyncRoutes
}
// 先在vuex里存放一份完整的路由信息,深拷贝,vuex里保存的asyncRoutes 与此处的asyncRoutes无关,此处的asyncRoutes会改变
commit('SET_allRoutes', deepClone(allRoutes))
let accessedRoutes = []
if (name === 'superadmin') {
accessedRoutes = allRoutes || [] // 全部显示
} else {
accessedRoutes = filterAsyncRoutes(allRoutes, authList)
}
commit('SET_ROUTES', accessedRoutes)
commit('SET_AUTH', authList)
resolve(accessedRoutes)
}).catch(error => {
console.log(error)
})
})
},
clearRoutes({ commit }) {
commit('CLEAR_ROUTES')
},
setAllRoutes({ commit }, allRoutes) {
commit('SET_allRoutes', allRoutes)
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
其他说明
这边获取的路由信息,{authList,name} 也可以改成 roles 。这个看需求啦。
后台代码
这里在说下后台吧
bean
controller:
Service
Menu menu = get(“1”)是因为在数据库中写一个【功能菜单】作为第一级,后面匹配其他子级。
Utils
mapper
测试demo算是写完啦。
有不正确的地方欢迎指正。感谢。。。