最近因为转战到新公司前端技术部门需要使用vue,不得已从angular转型vue。搭建后台框架生成面包屑导航的时候遇到了一个问题。以下是问题记录。
众所周知,在angular中功能是分为模块化的,我们可以将路由地址指向某个模块。如下图所示
最终home路由和home/add都是在同一个路由层级,在生成面包屑导航是可以根据层级划分进行查找路由。 但是vue没有这么简单,众所周知vue的路由是扁平化的,如果你想要在当前路由内部再次嵌套一层路由,最好的方式就是写一个子路由如下图所示。
对应的我们需要在相应路由添加一个路由出口。 到现在为止看上去还都是很合理,但是我们不妨想象一下,如果我们是一个后台管理页面,所有的界面都是在page里面展示,这个时候我们有一个功能同时拥有一个list功能页,一个add功能页,并且add功能极其繁琐需要单独进入一个页面进行操作,那么这个时候问题来了,我们需要在头部生成一个面包屑导航,如果我们将list与add路径一起放在page子路径中,那么add向上查找时势必查找不到对应的list数据,如果我们单独写一个子路由,那么就要在当前页面中新增一个无用组件来设置路由出口,并不利于维护,相对也比较繁琐。于是我进行了字符匹配,进行路由检索,并且与同事约定好路由名称,根据相匹配名称来约定父子级关系,如下图所示。
子级路由前缀为约定好的命名空间,路由切换的时候进行检索,强行进行匹配,这种方法简单粗暴,只需要我们定义好路由,无需再重新指定路由出口,或者新增空页面。 但是相对应的问题随之而来,因为我是根据path进行匹配的,所以不能指定路由动态传参。 所以约定了一种新的路由数据结构,当前数据结构堪堪完成,具体操作以后更新......
const routerObj = {
pages: {
router: {
path: '/pages',
component: () => import('@/pages/pages.vue'),
meta: {
title: '后台页面'
},
},
home: {
router: {
component: () => import('@/pages/home/home.vue'),
meta: {
title: '首页'
},
}
},
newPageSetup: {
router: {
component: () => import('@/pages/newPageSetup/newPageSetup.vue'),
meta: {
title: '页面搭建',
isReuse: true
}
},
add: {
router: {
component: () => import('@/pages/newPageSetup/addNewPageSetup.vue'),
meta: {
title: '新建页面'
}
},
}
},
activity: {
router: {
component: () => import('@/pages/activity/activityList.vue'),
meta: {
title: '活动管理',
isReuse: true
}
},
detail: {
router: {
component: () => import('@/pages/activity/activityDetail.vue'),
meta: {
title: '活动详情'
}
},
},
add: {
router: {
component: () => import('@/pages/announcement/addAnnouncement.vue'),
meta: {
title: '新建公告',
}
}
}
},
activityApprove: {
router: {
component: () => import('@/pages/activity/activityApprove.vue'),
meta: {
title: '活动审批',
isReuse: true
}
}
},
announcement: {
router: {
component: () => import('@/pages/announcement/announcementList.vue'),
meta: {
title: '公告管理',
isReuse: true
}
},
add: {
router: {
component: () => import('@/pages/announcement/addAnnouncement.vue'),
meta: {
title: '新建公告',
}
}
}
},
approve: {
router: {
component: () => import('@/pages/approve/approve.vue'),
meta: {
title: '审批流管理',
isReuse: true
}
}
},
label: {
router: {
component: () => import('@/pages/label/labelManagement.vue'),
meta: {
title: '标签管理',
isReuse: true
}
}
},
accoutManageList: {
router: {
component: () => import('@/pages/accoutManage/accoutManageList.vue'),
meta: {
title: '账户管理列表',
isReuse: true
}
}
},
jurisdiction: {
router: {
component: () => import('@/pages/jurisdiction/jurisdiction.vue'),
meta: {
title: '权限管理',
isReuse: true
}
}
},
sealManage: {
router: {
component: () => import('@/pages/seal/sealManage.vue'),
meta: {
title: '印章管理',
isReuse: true
}
}
},
classRoomManage: {
router: {
component: () => import('@/pages/classRoomManage/classRoomManage.vue'),
meta: {
title: '课堂管理',
isReuse: true
}
}
},
courseware: {
router: {
component: () => import('@/pages/courseware/courseware.vue'),
meta: {
title: '课件管理',
isReuse: true
}
}
},
curriculum: {
router: {
component: () => import('@/pages/curriculum/curriculum.vue'),
meta: {
title: '课程管理',
isReuse: true
}
}
}
}
};
// 路由数组
let arrRouter: any = [];
// 设置父指针
function setObj(routerObj: any): void {
// 遍历对象
Object.keys(routerObj).forEach((item: string) => {
// 查找当前对象每一项
const pages = {...routerObj[item]};
// 如果对象存在并且不是父指针或者路由
if (pages && item !== 'router' && item !== 'parent') {
if (pages.router?.name === undefined) {
pages.router = {
...pages.router,
name: item,
path: pages.router.path !== '/pages' ? (pages.router.path || item) : '',
meta: {
...pages.router.meta,
pathIndex: item
}
}
}
// 遍历对象子集并且将自己父指针指向当前对象并且进行递归
Object.keys(pages).forEach(data => {
if (pages[data] && data !== 'router' && data !== 'parent') {
pages[data].parent = pages;
// 设置路由name
pages[data].router.name = pages.router.name + data.substring(0,1).toUpperCase() + data.substring(1);
// 设置路由路径
if (pages.router.path === '') {
pages[data].router.path = data;
} else {
pages[data].router.path = pages.router.path + '/' + (pages[data].router.path || data);
}
// 设置路由索引
pages[data].router.meta.pathIndex = pages.router.meta.pathIndex + '/' + data;
// 将组装好的路由添加至路由数组
arrRouter.push(pages[data].router);
}
})
setObj(pages)
}
});
}
// 开始递归
setObj(routerObj);
console.log(routerObj);
export default arrRouter;
console.log(arrRouter);
最终会在当前meta中生成一个pathIndex索引字段如下图所示
我们可以从索引字段中查询到当前路由对象,再根据父指针生成面包屑导航。
项目地址:gitee.com/usercxx/vue…