概述
常用vue 开发路由都是二级管理,面包屑常规是按照路由的 this.$route.matched获取到的路由列表匹配,无法实现每个面包屑节点都能点。经过本文改造得以优化。初到掘金,请指教。
最终效果
路由改造
重点思路
- parentBreadcrumb: '['父级路由path']' 如果设置了会在面包屑中作为父级路由,添加到面包屑中间。
- noredirect: true 如果设置了true,择控制面包屑点击路由不跳转。
- 路由构造LEVELONE、A1、A2、A3 ,LEVELONE、B1、B2、B3 分别行程两条三级路由,并且每一级路由都能跳转。
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'
/**
* hidden: true 如果设置为true则不会显示在侧边菜单
* alwaysShow: true 设置为true一直显示根路由
* redirect: noRedirect 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
* name:'router-name' 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
* meta : {
roles: ['admin','editor'] 设置该路由进入的权限,支持多个权限叠加
title: 'title' 设置该路由在侧边栏和面包屑中展示的名字
icon: 'svg-name' 设置该路由的图标
breadcrumb: false 如果设置为false,则不会在breadcrumb面包屑中显示
activeMenu: '/example/list' 如果设置了激活菜单,则侧边菜单会默认选中
parentBreadcrumb: '['父级路由path']' 如果设置了会在面包屑中作为父级路由,添加到面包屑中间
noredirect: true 如果设置了true,择控制面包屑点击路由不跳转
}
*/
// 固定路由,所有的人都可以访问
export const constantRoutes = [
{
path: '/LEVELONE',
component: Layout,
noredirect: true,
redirect: 'bloodClinical/aggregateAnalysis',
alwaysShow: true,
meta: { title: 'LEVELONE', icon: 'dashboard', noredirect: true },
// component: () =>
// import('@/views/aggregateAnalysis'),
children: [{
path: 'A1',
name: 'A1',
component: () =>
import('@/views/A/A1.vue'),
meta: {
title: 'A1', icon: 'dashboard', keepAlive: true, parentBreadcrumb: [
]
}
},
{
path: 'A2',
name: 'A2',
// hidden: true,
component: () =>
import('@/views/A/A2.vue'),
meta: {
title: 'A2', icon: 'dashboard', parentBreadcrumb: [
'A1'
]
}, hidden: true
},
{
path: 'A3',
name: 'A3',
// hidden: true,
component: () =>
import('@/views/A/A3.vue'),
meta: {
title: '患者分析', icon: 'dashboard', parentBreadcrumb: [
'A1',
'A2'
]
}, hidden: true
},
{
path: 'B1',
name: 'B1',
component: () =>
import('@/views/B/B1.vue'),
meta: {
title: 'B1', icon: 'dashboard', keepAlive: true, parentBreadcrumb: [
]
}
},
{
path: 'B2',
name: 'B2',
// hidden: true,
component: () =>
import('@/views/B/B2.vue'),
meta: {
title: 'B2', icon: 'dashboard', parentBreadcrumb: [
'B1'
]
}, hidden: true
},
{
path: 'B3',
name: 'B3',
// hidden: true,
component: () =>
import('@/views/B/B3.vue'),
meta: {
title: '患者分析', icon: 'dashboard', parentBreadcrumb: [
'B1',
'B2'
]
}, hidden: true
},
]
},
]
const createRouter = () =>
new Router({
// mode: 'history', // 上线前可以设置为history,但是需要后台支持配置
// 切换路由回到顶部 (默认)
scrollBehavior: (to, from, savedPosition) => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
// 重置路由
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
面包屑组件
重点代码
- 根据findRoute() 找到路由中的parentBreadcrumb配置,返回路由数据。添加到面包屑数组中, this.levelList.splice(1, 0, ...pushlist);
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1"
class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script>
import pathToRegexp from 'path-to-regexp';
export default {
data() {
return {
levelList: null,
};
},
computed: {
routes() {
return this.$router.options.routes;
},
},
watch: {
$route() {
this.getBreadcrumb();
},
},
created() {
this.getBreadcrumb();
},
methods: {
getBreadcrumb() {
// debugger;
// only show routes with meta.title
let matched = this.$route.matched.filter(
(item) => item.meta && item.meta.title
);
const first = matched[0];
const last = matched[matched.length - 1];
if (!this.isDashboard(first)) {
matched = [
// { path: '/dashboard', meta: { title: '临床用血' } }
].concat(matched);
}
this.levelList = matched.filter(
(item) => item.meta && item.meta.title && item.meta.breadcrumb !== false
);
const pushlist = [];
if (last.meta.parentBreadcrumb && last.meta.parentBreadcrumb.length > 0) {
last.meta.parentBreadcrumb.forEach((element) => {
const selectroute = this.findRoute(element);
if (selectroute != null) {
pushlist.push(selectroute);
}
});
}
this.levelList.splice(1, 0, ...pushlist);
},
isDashboard(route) {
const name = route && route.name;
if (!name) {
return false;
}
return (
name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
);
},
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route;
var toPath = pathToRegexp.compile(path);
return toPath(params);
},
handleLink(item) {
const { redirect, path } = item;
if (item.meta.noredirect || item.meta.noredirect != undefined) {
return;
}
if (redirect) {
this.$router.push(redirect);
return;
}
this.$router.push(this.pathCompile(path));
},
findRoute(name) {
let routes = null;
for (var i = 0; i < this.routes.length - 1; i++) {
if (this.routes[i].children) {
routes = this.routes[i].children.find((e) => e.name == name);
}
}
return routes;
},
},
};
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>