Angular 根据激活的路线及其 parents 设置标题
Angular setting title depending on activated route and its parents
我的目标:
我想全局监听路由器 NavigationEnd 事件,并根据路由自定义数据更改网页标题。
当前代码(在app.component.ts):
this.router.events.pipe(
filter((ev) => ev instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
while (route.firstChild) route = route.firstChild;
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data),
).subscribe((event) => this.title.setTitle(event['title']));
上面的代码可以,但是一点也不优雅,看需要的路由配置:
app-routing.module.ts
const routes: Routes = [
{
path: 'user',
loadChildren: () => import(`./user/user.module`).then(m => m.UserModule),
data: { title: "Pagina Utente" }
},
{
path: 'admin', loadChildren: () => import(`./admin/admin.module`).then(m => m.AdminModule),
data: { title: "Pannello Admin" }
},
{ path: '**', component: HomeComponent },
];
admin-routing.module.ts:
const routes: Routes = [
{
path: '', component: AdminPanelComponent,
children: [
{
path: 'users', component: UsersComponent,
data: { title: 'Pannello Admin: Utenti' }
},
{
path: 'comuni', component: ComuniComponent,
data: { title: 'Pannello Admin: Comuni' }
},
]
}
];
如您所见,我已经指定 /admin 路由应该有 "Pannello Admin" 作为标题,但我需要为它的每个 children 路由一次又一次地写它。
我试图通过将 app.component.ts 代码更改为以下内容来解决此问题:
this.router.events.pipe(
filter((ev) => ev instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
let title = route.data['title'] || '';
while (route.firstChild) {
route = route.firstChild;
title+= route.data['title'];
}
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data),
).subscribe((event) => this.title.setTitle(event['title']));
我希望这段代码能正常工作,并将我的标题设置为匹配路由的数据['title'] 属性 的串联。但是它不起作用,只是给出空标题(数据['title'] 由于某种原因总是未定义)
export class AppRouterModule {
constructor(private router: Router, private eventService: EventService) {
this.router.events.subscribe(event => {
if (event instanceof NavigationStart) {
this.eventService.StartNavigationSpinner();
}
});
}
}
我将导航事件订阅放入 AppRouterModule 本身,然后当特定事件发生时,我将它发送到一个 eventService,所有加载的组件都会监听这个列表:
this.EventService.NavigationStartEvent.subscribe(() => {
if (this.showGlobalSpinner) return;
this.showGlobalSpinner = true;
});
事件服务是一个如下所示的服务:
export class EventService {
NavigationEndEvent = new EventEmitter();
NavigationStartEvent = new EventEmitter();
...
所有解析都在 app.router 模块中完成,只是将事件发送到任何已加载标题更改的订阅?它可以是任何加载的组件。
如果重写发生得太频繁,那是因为页面正在按 angular 的 routing/render 周期重新加载。值得怀疑的是路由中的 loadChildren 配置。
我认为您想要的是主页加载一次,并且仅在单个 child 页面更改时才更改标题。我相信这意味着您需要另一个 ngRouterOutput。 Angular 文档在这个概念上令人眼花缭乱。 children 可以存在于任何页面的想法。
我最终通过在我的 app.component.ts 构造函数中使用此代码解决了我的问题:
this.router.events.pipe(
filter((ev) => ev instanceof NavigationEnd),
map(() => this.activatedRoute),
).subscribe((activatedRoute: ActivatedRoute) => this.title.setTitle(activatedRoute.snapshot.data['title'] || 'Gestionale Incarichi'));
我的目标: 我想全局监听路由器 NavigationEnd 事件,并根据路由自定义数据更改网页标题。
当前代码(在app.component.ts):
this.router.events.pipe(
filter((ev) => ev instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
while (route.firstChild) route = route.firstChild;
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data),
).subscribe((event) => this.title.setTitle(event['title']));
上面的代码可以,但是一点也不优雅,看需要的路由配置:
app-routing.module.ts
const routes: Routes = [
{
path: 'user',
loadChildren: () => import(`./user/user.module`).then(m => m.UserModule),
data: { title: "Pagina Utente" }
},
{
path: 'admin', loadChildren: () => import(`./admin/admin.module`).then(m => m.AdminModule),
data: { title: "Pannello Admin" }
},
{ path: '**', component: HomeComponent },
];
admin-routing.module.ts:
const routes: Routes = [
{
path: '', component: AdminPanelComponent,
children: [
{
path: 'users', component: UsersComponent,
data: { title: 'Pannello Admin: Utenti' }
},
{
path: 'comuni', component: ComuniComponent,
data: { title: 'Pannello Admin: Comuni' }
},
]
}
];
如您所见,我已经指定 /admin 路由应该有 "Pannello Admin" 作为标题,但我需要为它的每个 children 路由一次又一次地写它。
我试图通过将 app.component.ts 代码更改为以下内容来解决此问题:
this.router.events.pipe(
filter((ev) => ev instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
let title = route.data['title'] || '';
while (route.firstChild) {
route = route.firstChild;
title+= route.data['title'];
}
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data),
).subscribe((event) => this.title.setTitle(event['title']));
我希望这段代码能正常工作,并将我的标题设置为匹配路由的数据['title'] 属性 的串联。但是它不起作用,只是给出空标题(数据['title'] 由于某种原因总是未定义)
export class AppRouterModule {
constructor(private router: Router, private eventService: EventService) {
this.router.events.subscribe(event => {
if (event instanceof NavigationStart) {
this.eventService.StartNavigationSpinner();
}
});
}
}
我将导航事件订阅放入 AppRouterModule 本身,然后当特定事件发生时,我将它发送到一个 eventService,所有加载的组件都会监听这个列表:
this.EventService.NavigationStartEvent.subscribe(() => {
if (this.showGlobalSpinner) return;
this.showGlobalSpinner = true;
});
事件服务是一个如下所示的服务:
export class EventService {
NavigationEndEvent = new EventEmitter();
NavigationStartEvent = new EventEmitter();
...
所有解析都在 app.router 模块中完成,只是将事件发送到任何已加载标题更改的订阅?它可以是任何加载的组件。
如果重写发生得太频繁,那是因为页面正在按 angular 的 routing/render 周期重新加载。值得怀疑的是路由中的 loadChildren 配置。
我认为您想要的是主页加载一次,并且仅在单个 child 页面更改时才更改标题。我相信这意味着您需要另一个 ngRouterOutput。 Angular 文档在这个概念上令人眼花缭乱。 children 可以存在于任何页面的想法。
我最终通过在我的 app.component.ts 构造函数中使用此代码解决了我的问题:
this.router.events.pipe(
filter((ev) => ev instanceof NavigationEnd),
map(() => this.activatedRoute),
).subscribe((activatedRoute: ActivatedRoute) => this.title.setTitle(activatedRoute.snapshot.data['title'] || 'Gestionale Incarichi'));