Angular 2 个动态面包屑
Angular 2 Dynamic Breadcrumbs
我需要面包屑方面的帮助
此处示例路由配置
Routes = [
{path: '', redirectTo: 'home', pathMatch: 'full'},
{path: 'home', ..., data: { breadcrumb: 'Home'}},
{path: 'about', ..., data: { breadcrumb: 'About'}},
{path: 'github', ..., data: { breadcrumb: 'GitHub'},
{
path: 'category/:id',
component: CategoryComponent
},
]
在面包屑组件中,我尝试使用它从 ActivatedRoute
中提取面包屑数据
ngOnInit() {
// subscribe to the NavigationEnd event
this.router.events.filter((event) => event instanceof NavigationEnd).subscribe(() => {
// set breadcrumbs
const root: ActivatedRoute = this.activatedRoute.root;
this.breadcrumbs = this.getBreadcrumbs(root);
});
}
之后我渲染 comonentns 模板
<ul class="breadcrumb">
<li><a routerLink="" routerLinkActive="active"><i class="fa fa-home position-left"></i> Главная</a></li>
<ng-container *ngFor="let breadcrumb of breadcrumbs">
<li routerLinkActive="active">
<a [routerLink]="[breadcrumb.url, breadcrumb.params]"> {{ breadcrumb.label }}</a>
</li>
</ng-container>
</ul>
一切都很好,但我不知道如何从另一个组件传递数据值以用于 category/:id
路线,使人类可读,如 "Mobile Phones"
我希望现在回答这个问题还不算太晚 :D,所以这里有一个有效的 CodeSandbox 示例,其中包含两个面包屑实现,它使用 router
data
选项来传递并为面包屑收集数据。
代码解释:
查看面包屑组件中的评论。
这里是面包屑组件
import { Component, OnInit } from "@angular/core";
import {
Router,
Event,
ActivationStart,
ActivatedRouteSnapshot,
ActivationEnd,
NavigationEnd,
NavigationStart
} from "@angular/router";
import { filter, map, buffer, pluck } from "rxjs/operators";
/**
* Check if an angular router 'Event' is instance of 'NavigationEnd' event
*/
const isNavigationEnd = (ev: Event) => ev instanceof NavigationEnd;
/**
* Check if an angular router 'Event' is instance of 'NavigationEnd' event
*/
const isActivationEnd = (ev: Event) => ev instanceof ActivationEnd;
@Component({
selector: "app-breadcrumb",
templateUrl: "./breadcrumb.component.html",
styleUrls: ["./breadcrumb.component.scss"]
})
export class BreadcrumbComponent implements OnInit {
bcLoadedData;
bcForDisplay;
constructor(private router: Router) {}
ngOnInit() {
/**
* navigationEnd$ is trigered once per completed routing event, in other words
* once per loading a component that is in the end of the current route
*/
const navigationEnd$ = this.router.events.pipe(filter(isNavigationEnd));
/**
* Here we subscribe to all navigation events, in order to update
* our route "data", which we will use for the breadcrumb visualization.
*
* Than we filter the events emitted from the `router` in such way, that we are only
* taking action upon a completed router event (in other words we are subscribing only for `ActivationEnd`
* events)
*
* We use pluck to get only the requried bredcrumb data
*
* The buffer operator accumulates all `data` coming from the router and emmits the accumulated data once
* when a `NavigationEnd` event passes troufh `navigationEnd$`
*
* The `map` in the end is used to reverse the collected data, in order to convert it to more logical
* sequence. Without the revers first we will get the data for the current route, after that for it's parent
* and so on (that is how the ng router works).
*/
this.router.events
.pipe(
filter(isActivationEnd),
pluck("snapshot"),
pluck("data"),
buffer(navigationEnd$),
map((bcData: any[]) => bcData.reverse())
)
.subscribe(x => {
this.bcLoadedData = x;
});
}
}
.breadcrumb {
display: flex;
&.simple {
border: 2px solid blueviolet;
border-radius: 4px;
}
.breadcrumb-separator {
margin: 10px;
}
}
<div class="breadcrumb simple">
<div *ngFor="let bcElement of bcLoadedData; let last = last">
{{bcElement.bc}}
<span class="breadcrumb-separator"
*ngIf="!last">></span>
</div>
</div>
这是路由的结构
const routes: Routes = [
{ path: '', pathMatch: 'full', component: MockComponentComponent, data: { bc: 'Looking outside' } },
{
path: 'home', component: MockComponentComponent,
data: { bc: 'I see a home' },
children: [
{
path: 'primaryHouse', component: MockComponentComponent,
data: { bc: 'I\'m going inside the home' },
children: [
{
path: 'kitchen', component: MockComponentComponent,
data: { bc: 'look inside the kitchen' }
},
{
path: 'bedroom', component: MockComponentComponent,
data: { bc: 'look inside the bedroom' }
}
]
},
{
path: 'guestHouse', component: MockComponentComponent,
data: { bc: 'I\'m going in the back yard' }
}
]
}
];
任何面包屑解决方案都必须处理
- 在路由中定义面包屑的声明式方法
- 通过不同标签更新任何路由的动态异步方式
- 在面包屑中跳过特定路线显示的方法
我创建了一个库来处理所有这些称为 xng-breadcrumbs - https://github.com/udayvunnam/xng-breadcrumb
随时查看,开发的 Angular 应用程序显示面包屑使用情况 - https://xng-breadcrumb.netlify.com
我需要面包屑方面的帮助
此处示例路由配置
Routes = [
{path: '', redirectTo: 'home', pathMatch: 'full'},
{path: 'home', ..., data: { breadcrumb: 'Home'}},
{path: 'about', ..., data: { breadcrumb: 'About'}},
{path: 'github', ..., data: { breadcrumb: 'GitHub'},
{
path: 'category/:id',
component: CategoryComponent
},
]
在面包屑组件中,我尝试使用它从 ActivatedRoute
ngOnInit() {
// subscribe to the NavigationEnd event
this.router.events.filter((event) => event instanceof NavigationEnd).subscribe(() => {
// set breadcrumbs
const root: ActivatedRoute = this.activatedRoute.root;
this.breadcrumbs = this.getBreadcrumbs(root);
});
}
之后我渲染 comonentns 模板
<ul class="breadcrumb">
<li><a routerLink="" routerLinkActive="active"><i class="fa fa-home position-left"></i> Главная</a></li>
<ng-container *ngFor="let breadcrumb of breadcrumbs">
<li routerLinkActive="active">
<a [routerLink]="[breadcrumb.url, breadcrumb.params]"> {{ breadcrumb.label }}</a>
</li>
</ng-container>
</ul>
一切都很好,但我不知道如何从另一个组件传递数据值以用于 category/:id
路线,使人类可读,如 "Mobile Phones"
我希望现在回答这个问题还不算太晚 :D,所以这里有一个有效的 CodeSandbox 示例,其中包含两个面包屑实现,它使用 router
data
选项来传递并为面包屑收集数据。
代码解释:
查看面包屑组件中的评论。
这里是面包屑组件
import { Component, OnInit } from "@angular/core";
import {
Router,
Event,
ActivationStart,
ActivatedRouteSnapshot,
ActivationEnd,
NavigationEnd,
NavigationStart
} from "@angular/router";
import { filter, map, buffer, pluck } from "rxjs/operators";
/**
* Check if an angular router 'Event' is instance of 'NavigationEnd' event
*/
const isNavigationEnd = (ev: Event) => ev instanceof NavigationEnd;
/**
* Check if an angular router 'Event' is instance of 'NavigationEnd' event
*/
const isActivationEnd = (ev: Event) => ev instanceof ActivationEnd;
@Component({
selector: "app-breadcrumb",
templateUrl: "./breadcrumb.component.html",
styleUrls: ["./breadcrumb.component.scss"]
})
export class BreadcrumbComponent implements OnInit {
bcLoadedData;
bcForDisplay;
constructor(private router: Router) {}
ngOnInit() {
/**
* navigationEnd$ is trigered once per completed routing event, in other words
* once per loading a component that is in the end of the current route
*/
const navigationEnd$ = this.router.events.pipe(filter(isNavigationEnd));
/**
* Here we subscribe to all navigation events, in order to update
* our route "data", which we will use for the breadcrumb visualization.
*
* Than we filter the events emitted from the `router` in such way, that we are only
* taking action upon a completed router event (in other words we are subscribing only for `ActivationEnd`
* events)
*
* We use pluck to get only the requried bredcrumb data
*
* The buffer operator accumulates all `data` coming from the router and emmits the accumulated data once
* when a `NavigationEnd` event passes troufh `navigationEnd$`
*
* The `map` in the end is used to reverse the collected data, in order to convert it to more logical
* sequence. Without the revers first we will get the data for the current route, after that for it's parent
* and so on (that is how the ng router works).
*/
this.router.events
.pipe(
filter(isActivationEnd),
pluck("snapshot"),
pluck("data"),
buffer(navigationEnd$),
map((bcData: any[]) => bcData.reverse())
)
.subscribe(x => {
this.bcLoadedData = x;
});
}
}
.breadcrumb {
display: flex;
&.simple {
border: 2px solid blueviolet;
border-radius: 4px;
}
.breadcrumb-separator {
margin: 10px;
}
}
<div class="breadcrumb simple">
<div *ngFor="let bcElement of bcLoadedData; let last = last">
{{bcElement.bc}}
<span class="breadcrumb-separator"
*ngIf="!last">></span>
</div>
</div>
这是路由的结构
const routes: Routes = [
{ path: '', pathMatch: 'full', component: MockComponentComponent, data: { bc: 'Looking outside' } },
{
path: 'home', component: MockComponentComponent,
data: { bc: 'I see a home' },
children: [
{
path: 'primaryHouse', component: MockComponentComponent,
data: { bc: 'I\'m going inside the home' },
children: [
{
path: 'kitchen', component: MockComponentComponent,
data: { bc: 'look inside the kitchen' }
},
{
path: 'bedroom', component: MockComponentComponent,
data: { bc: 'look inside the bedroom' }
}
]
},
{
path: 'guestHouse', component: MockComponentComponent,
data: { bc: 'I\'m going in the back yard' }
}
]
}
];
任何面包屑解决方案都必须处理
- 在路由中定义面包屑的声明式方法
- 通过不同标签更新任何路由的动态异步方式
- 在面包屑中跳过特定路线显示的方法
我创建了一个库来处理所有这些称为 xng-breadcrumbs - https://github.com/udayvunnam/xng-breadcrumb
随时查看,开发的 Angular 应用程序显示面包屑使用情况 - https://xng-breadcrumb.netlify.com