Fork me on GitHub

Angular6 breadcream 面包屑

一、前期准备

  1. 面包屑组件(最好能封装成共享组件)
  2. 一些路由信息配置
  3. Ant-Zorro 组件的环境配置(这里会套用里面的一些现成的组件库),版本: 7.0.1

二、Ant-Zorro 配置

这里请参考官方网站 https://ng.ant.design/docs/getting-started/zh ,官方网站中,找到目录 快速上手 ,在里面有 自行构建,查看 自行构建 下的内容。

如果依然不能成功,可以浏览参考博主的另一个博客:
里面讲了一些博主在配置 Ant-Zorro 的时候遇到的坑!

三、自定义面包屑组件

1. 创建一个自己的面包屑组件

1
ng g c breadcrumb --spec=false

2. 使用 Ant-Zorro 的面包屑组件

1
2
3
4
5
<nz-breadcrumb>
<nz-breadcrumb-item>Home</nz-breadcrumb-item>
<nz-breadcrumb-item><a>Application List</a></nz-breadcrumb-item>
<nz-breadcrumb-item>An Application</nz-breadcrumb-item>
</nz-breadcrumb>

将 Ant-Zorro 组件库中的面包屑组件,放到自己创建的面包屑组件的html文件中。将组件库中的面包屑做一点改动,将静态的面包屑改成动态的,使用 ngFor 循环自行加载,对应的路由信息。

1
2
3
4
5
6
<nz-breadcrumb>
<nz-breadcrumb-item>首页</nz-breadcrumb-item>
<nz-breadcrumb-item *ngFor="let breadcrumb of breadcrumbs">
<a [routerLink]="[breadcrumb.url, breadcrumb.params]">{{ breadcrumb.label }}</a>
</nz-breadcrumb-item>
</nz-breadcrumb>

3. 面包屑逻辑代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd, Params, PRIMARY_OUTLET } from '@angular/router';
import { filter } from 'rxjs/operators';

interface IBreadcrumb {
label: string;
params: Params;
url: string;
}

@Component({
selector: 'app-breadcrumb',
templateUrl: './breadcrumb.component.html',
styleUrls: ['./breadcrumb.component.scss']
})

export class BreadcrumbComponent implements OnInit {
public breadcrumbs: IBreadcrumb[];

constructor(
private activatedRoute: ActivatedRoute,
private router: Router
) {
this.breadcrumbs = [];
}

ngOnInit() {
// 订阅NavigationEnd事件
this.router.events.pipe(filter(event => event instanceof NavigationEnd))
.subscribe(event => {
// 设置面包屑
const root: ActivatedRoute = this.activatedRoute.root;
console.log('=== janine.树的的根路由', root);
this.breadcrumbs = this.getBreadcrumbs(root);
});
}

/**
* 返回表示面包屑的IBreadcrumb对象的数组
*/
private getBreadcrumbs(route: ActivatedRoute, url: string = '', breadcrumbs: IBreadcrumb[] = []): IBreadcrumb[] {
const ROUTE_DATA_BREADCRUMB = 'breadcrumb';

// 得到子路由
const children: ActivatedRoute[] = route.children;
console.log('=== janine.有多少子路由 ===', children);

// 如果没有子路由返回
if (children.length === 0) {
console.log('=== janine.没有子路由是 ===', breadcrumbs);
return breadcrumbs;
}

// 遍历每个子元素
for (const child of children) {
// 验证主路由
if (child.outlet !== PRIMARY_OUTLET) {
continue;
}

// 验证路由上指定的自定义数据属性'breadcrumb'
if (!child.snapshot.data.hasOwnProperty(ROUTE_DATA_BREADCRUMB)) {
return this.getBreadcrumbs(child, url, breadcrumbs);
}

// 获取路由的URL进行分割
const routeURL: string = child.snapshot.url.map(segment => segment.path).join('/');
// append route URL to URL 追加路由的url到url
if (routeURL) {
console.log('=== janine.routeURL ===', routeURL);
url += `/${routeURL}`;
}

// 添加面包屑
const breadcrumb: IBreadcrumb = {
label: child.snapshot.data[ROUTE_DATA_BREADCRUMB],
params: child.snapshot.params,
url: url
};
// 此处的 component 如果为 undefined,可能是因为懒加载,在查找时,没有找到 component 的值,
// 所以当 component 为 undefined 的时候,就会又往数组里再追加一次,会重复
if (child.component) {
breadcrumbs.push(breadcrumb);
}

console.log('=== janine.breadcrumbs === ', breadcrumb);

// 递归
return this.getBreadcrumbs(child, url, breadcrumbs);
}
}

}

4. 知识点

(1) filter

1
import { filter } from 'rxjs/operators';

rxjs 的 filter() 方法,是 Angular6的,不是其他版本,如果版本不对,会出错! 对应的使用步骤如下:

1
2
3
4
5
6
7
8
9
10
ngOnInit() {
// 订阅NavigationEnd事件
this.router.events.pipe(filter(event => event instanceof NavigationEnd))
.subscribe(event => {
// 设置面包屑
const root: ActivatedRoute = this.activatedRoute.root;
console.log('=== janine.树的的根路由', root);
this.breadcrumbs = this.getBreadcrumbs(root);
});
}

(2)NavigationEnd, Params, PRIMARY_OUTLET

Router 和 ActivatedRoute 就不说了,这是 Angular 路由最常见的。讲一下 NavigationEnd, Params, PRIMARY_OUTLET。

  • NavigationEnd:表示当导航 成功结束 时(当从一个路径到另一个导航已经完成时)触发的事件。
  • Params:用来设置 IBreadcrumb 接口的 params 的类型为 Params。params 为非必需,其他两个为必需的。

    1
    2
    3
    4
    5
    interface IBreadcrumb {
    label: string;
    params: Params;
    url: string;
    }
  • PRIMARY_OUTLET:一个常量 primary

(3) 添加面包屑

代码中,有一段是将路由追加到数组中。这里会有一个关于懒加载的问题,代码注释里已经说明了。

如果有懒加载就得加个判读 child.component 是否 为 undefined ,只有不是 undefined 时才能向数组中追加,否则会重复(这里可以去掉判断,自己 debugger 一下,关注一下 component 值的变化,和数组追加后数组值的变化情况)。

如果没有懒加载,可以不对 breadcrumbs.push(breadcrumb); 做判断!

1
2
3
4
5
6
7
8
9
10
11
// 添加面包屑
const breadcrumb: IBreadcrumb = {
label: child.snapshot.data[ROUTE_DATA_BREADCRUMB],
params: child.snapshot.params,
url: url
};
// 此处的 component 如果为 undefined,可能是因为懒加载,在查找时,没有找到 component 的值,
// 所以当 component 为 undefined 的时候,就会又往数组里再追加一次,会重复
if (child.component) {
breadcrumbs.push(breadcrumb);
}

5. 路由信息配置: data: { breadcrumb: ‘xxx’ }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export const routes = [
{
// 路由为空时,自动重定向到/home
path: '',
redirectTo: '/home/basic',
pathMatch: 'full',
},
{
path: 'home', component: HomeComponent,
children: [
{
path: 'basic', loadChildren: './basic/basic.module#BasicModule',
data: { breadcrumb: '基础' }
},
...
{
path: 'server', loadChildren: './server/server.module#ServerModule',
data: { breadcrumb: '服务' }
}
]
},
];

如果模块中,还有子路由,也是同样配置!

6. 效果图

路由面包屑

附录

源码地址:https://github.com/Janine-ZN/ng-basic (重点:breadcrumb.component.ts 和 routes.ts,还有一些模块中的路由配置)

参考的博客是针对 Angular2 的,而且不适用于路由懒加载,如果有路由懒加载的地方页面可能会出重复的路由。

博客参考地址:
https://yfblog.cn/angular2-breadcrumb-using-router.html

坚持原创技术分享,您的支持将鼓励我继续创作!
-------------    本文结束  感谢您的阅读    -------------
0%