vue + addRouters 实现动态路由菜单
动态路由这个功能呢,其实说简单也简单,说难也有点难度。上代码
·
动态路由这个功能呢,其实说简单也简单,说难也有点难度。
上代码
login组件
//template和style略过
<script>
import router from '@/router' //引入路由
import Layout from '@/layout' //引入框架组件1
import Block from '@/layout/block' //引入框架组件2,框架组件的数量看各自项目实际来
const _import = require('@/router/import') //module.exports = file => () => import(`@/${file}/index.vue`) 就这一行代码。作用是将字符串转换为懒加载路由组件
export default {
data() {
return { //定义需要用到的变量
roleId: '',
menuList: [],
menu: [],
topMenus: [],
leftMenus: [],
firstUrl: ''
}
},
created() { //登录页面和404页面不属于动态路由页面,在创建页面前应添加到路由列表中
router.options.routes = [
{
path: '/view/manager/login',
component: () => import('@/view/manager/login')
},
{
path: '/view/manager/404',
component: () => import('@/view/manager/404'),
hidden: true
}
]
},
methods: {
async getRole() { //登录完成后获取到不同角色的Id,通过此Id获取对应的不同路由列表
try {
const res = await auth.privilege({
method: 'get',
roleId: this.roleId
})
console.log('role', res)
//接下来就是漫长的数据格式转换了,这里根据各自的实际情况来
if (res.status === 0) {
const _res = res.result.menus
const permissions = res.result.permissions
const o = this.menuList
this.firstUrl = _res[0].menuUrl
for (var i = 0; i < _res.length; i++) {
var index = _res[i]
o[i] = {}
o[i].path = index.menuUrl
o[i].meta = {}
o[i].meta.title = index.menuName
o[i].meta.icon = index.menuIcon
o[i].parentMenuId = index.parentMenuId
o[i].menuId = index.menuId
o[i].moduleId = index.moduleId
if (index.menuLevel === 1) {
o[i].component = 'Layout'
o[i].redirect = ''
o[i].children = []
} else if (index.menuLevel === 2) {
o[i].component = 'Block'
o[i].redirect = ''
o[i].children = []
} else if (index.menuLevel === 3) {
o[i].component = index.menuUrl
} else if (index.menuLevel === 4) {
o[i].component = index.menuUrl
o[i].hidden = true
}
if (index.moduleId === 1010 && index.parentMenuId === 0) {
o[i].hidden = true
} else if (index.moduleId === 1013 && index.parentMenuId === 0) {
o[i].hidden = true
}
}
for (var j = 0; j < o.length; j++) {
var pindex = o[j]
for (var k = 0; k < o.length; k++) {
var cindex = o[k]
if (cindex.parentMenuId === pindex.menuId) {
pindex.children.push(cindex)
pindex.redirect = pindex.children[0].path
}
}
}
o.forEach(item => {
if (item.parentMenuId === 0) {
this.menu.push(item)
}
if (item.parentMenuId === 0 && item.moduleId === 1010) {
this.topMenus.push(item)
}
if (item.parentMenuId === 0 && item.moduleId === 1013) {
this.topMenus.push(item)
}
})
//为了防止刷新后页面空白,需要将处理好的路由存储在sessionStorage中
sessionStorage.setItem('permissions', JSON.stringify(permissions))
sessionStorage.setItem('routerMenus', JSON.stringify(this.menu))
sessionStorage.setItem('routerTopMenus', JSON.stringify(this.topMenus))
var routes = filterAsyncRouter(this.menu)
routes.push({
path: '*',
redirect: '/view/manager/404',
hidden: true
})
// 添加权限路由
routes.forEach(item => {
router.options.routes.push(item)
})
// 加这一步才能渲染页面,不然页面显示为空白
router.addRoutes(routes)
//将路由同步存储到vuex中
this.$store.dispatch('user/getPermissions', permissions)
this.$store.dispatch('user/getMenus', routes)
this.$store.dispatch('user/getTopMenus', this.topMenus)
this.$router.push(this.firstUrl)
} else {
this.$message({
message: res.msg,
type: 'warning'
})
}
} catch (err) {
console.log(err)
this.buttonLoading = false
this.$message({
message: err.data.msg ? err.data.msg : '网络错误',
type: 'warning'
})
}
}
}
}
//这是对框架组件进行特殊处理的函数
function filterAsyncRouter(asyncRouterMap) {
const accessedRouters = asyncRouterMap.filter(route => {
if (route.component) {
if (route.component === 'Layout') { // Layout组件特殊处理
route.component = Layout
} else if (route.component === 'Block') { // Block组件特殊处理
route.component = Block
} else {
route.component = _import(route.path.substring(1, route.path.length))
}
}
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children)
}
return true
})
return accessedRouters
}
</script>
为了防止页面刷新后空白,还有一步操作:
App.vue
//template和style同样略过
<script>
import Layout from '@/layout'
import Block from '@/layout/block'
import router from './router'
const _import = require('@/router/import')
export default {
//将路由信息从sessionStorage中取出来
created() {
const userInfo = JSON.parse(sessionStorage.getItem('userInfo'))
const routerMenus = JSON.parse(sessionStorage.getItem('routerMenus'))
const routerTopMenus = JSON.parse(sessionStorage.getItem('routerTopMenus'))
const permissions = JSON.parse(sessionStorage.getItem('permissions'))
if (routerMenus && this.$store.state.user.menus.length === 0) {
this.$store.dispatch('user/getUserInfo', userInfo)
this.$store.dispatch('user/getMenus', routerMenus)
this.$store.dispatch('user/getTopMenus', routerTopMenus)
this.$store.dispatch('user/getPermissions', permissions)
var routes = filterAsyncRouter(routerMenus)
routes.push({
path: '*',
redirect: '/view/manager/404',
hidden: true
})
// 下面的操作同理
// 添加权限路由
routes.forEach(item => {
router.options.routes.push(item)
})
// 加这一步才能渲染页面
router.addRoutes(routes)
}
}
}
function filterAsyncRouter(asyncRouterMap) {
const accessedRouters = asyncRouterMap.filter(route => {
if (route.component) {
if (route.component === 'Layout') {
route.component = Layout
} else if (route.component === 'Block') {
route.component = Block
} else {
route.component = _import(route.path.substring(1, route.path.length))
}
}
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children)
}
return true
})
return accessedRouters
}
</script>
至此,大功告成。
处理路由格式那一块跟业务有很强的关联性,但逻辑大同小异:
1,如果后端直接返回处理好的路由列表,那皆大欢喜,直接用即可。
2,如果后端返回给前端的是各路由之间的关系,那就需要前端自己去转换为所需的路由列表。但是前端只要弄清楚了每层路由间的联系,处理起来就不会很难。
3,前端必知的各路由关系数据
- 每一级路由的id
- 每一级路由的name
- 每一级路由的path
- 每一级路由所属的level
- 每一级路由的icon
- 每一级路由的id对应的所属父级的id
更多推荐
已为社区贡献2条内容
所有评论(0)