使用 Angular 构建应用程序时,您应该做的一件常见事情是在每次成功导航后更新页面标题。这有助于可访问性并改善导航体验。这是您过去必须手动执行的操作,但最近添加到版本 14 中的 Angular 路由器的一项功能可以本地处理此问题,同时允许您自定义其行为。这篇文章向您展示了如何在每次成功导航后使用 Angular 路由器的新内置功能来设置页面标题。
使用路由器事件设置页面标题 ♻️
以前,在每次成功导航后使用 Angular 路由器设置页面标题是您必须添加到每个项目的代码,或者使用 Angular 库(如果提供)。下面的示例显示了一些示例代码,您将如何执行此操作:
首先,您将使用带有键 data
的对象中的属性来设置页面的标题。Route``title
import { NgModule } from '@angular /core';
import { RouterModule, Routes } from '@angular /router';
import { AboutComponent } from './about.component';
import { HomeComponent } from './home.component';
const routes: Routes = [
{
path: 'home',
component: HomeComponent,
data: { title: 'Home' }
},
{
path: 'about',
component: AboutComponent,
data: { title: 'About Me' }
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
接下来,您将向您的 AppComponent
或其他一些根级服务添加代码,该服务侦听来自 Angular 路由器的事件,查找 title
路由上的属性,并使用它来设置页面标题。
import { Component } from '@angular /core';
import { Title } from '@angular /platform-browser';
import { Router, NavigationEnd, ActivatedRoute } from '@angular /router';
import { filter, map } from 'rxjs';
@Com ponent({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
constructor(
private router: Router,
private titleService: Title
) {}
ngOnInit() {
this.router.events
.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => {
let route: ActivatedRoute = this.router.routerState.root;
let routeTitle = '';
while (route!.firstChild) {
route = route.firstChild;
}
if (route.snapshot.data['title']) {
routeTitle = route!.snapshot.data['title'];
}
return routeTitle;
})
)
.subscribe((title: string) => {
if (title) {
this.titleService.setTitle(`My App - ${title}`);
}
});
}
}
必须将相同的代码复制到您从事的每个项目中。现在,让我们看看新的页面标题与 Angular 路由器一起工作的方式。
使用内置的 TitleStrategy ?
在 Angular v14 中,有一个内置的策略服务,用于从基于主路由器出口的路由中收集标题,并设置浏览器的页面标题。
路由对象本身有一个新属性供您设置页面标题,而不是使用 data
带有键的对象。title``title
import { NgModule } from '@angular /core';
import { RouterModule, Routes } from '@angular /router';
import { AboutComponent } from './about.component';
import { HomeComponent } from './home.component';
const routes: Routes = [
{
path: 'home',
component: AboutComponent,
title: "'My App - Home' // <-- Page title"
},
{
path: 'about',
component: AboutComponent,
title: "'My App - About Me' // <-- Page title"
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
AppComponent
现在您可以从侦听路由器事件的所有自定义代码中删除。?
import { Component } from '@angular /core';
@Com ponent({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {}
就是这样!现在,当您成功导航到每条路线时,页面标题将更新为每条路线中定义的标题。
需要注意的一点是,没有办法为每个路由定义前缀,例如 My App
. 在较大的应用程序中,这可能会导致设置页面标题的重复和不一致。
这就是您将使用自定义标题策略的地方。
覆盖全球标题策略 ✍️
Angular 路由器还提供了一个抽象 TitleStrategy
类,您可以使用它来扩展所提供的默认服务的功能。
TitleStrategy
首先,从 @angular /router
包中导入类。
import { Injectable, NgModule } from '@angular /core';
import { Title } from '@angular /platform-browser';
import { RouterModule, RouterStateSnapshot, Routes, TitleStrategy } from '@angular /router';
const routes: Routes = [
{
path: 'home',
component: AboutComponent,
title: 'Home'
},
{
path: 'about',
component: AboutComponent,
title: 'About Me'
}
];
接下来,您扩展该类以实现自定义页面标题策略,该策略采用从 构建的标题 routerState
并在其前面加上应用程序名称。
@Injectable()
ex port class TemplatePageTitleStrategy extends TitleStrategy {
constructor(private readonly title: Title) {
super();
}
override updateTitle(routerState: RouterStateSnapshot) {
const title = this.buildTitle(routerState);
if (title !== undefined) {
this.title.setTitle(`My App - ${title}`);
}
}
}
接下来,将 提供 TemplatePageTitleStrategy
作为对默认值的覆盖 TitleStrategy
。
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [
{
provide: TitleStrategy,
useClass: TemplatePageTitleStrategy
}
]
})
export class AppRoutingModule {}
现在每条路由只提供页面标题本身,整个应用的前缀只用在一个地方。
使用解析器设置页面标题 ?
解析器是 Angular 路由器的一个熟悉的概念。您通常在加载路线之前使用它们来获取数据。您还可以使用解析器动态获取单个路由的页面标题。
下面的示例使用 a CustomTitleResolver
来定义 /about
路线的标题。
import { Injectable, NgModule } from '@angular /core';
import { Title } from '@angular /platform-browser';
import { RouterModule, RouterStateSnapshot, Routes, TitleStrategy } from '@angular /router';
@Injectable({ providedIn: 'root' })
export class CustomTitleResolver {
resolve() {
return Promise.resolve('Custom About Me');
}
}
const routes: Routes = [
{
path: 'home',
component: AboutComponent,
title: 'Home'
},
{
path: 'about',
component: AboutComponent,
title: CustomTitleResolver
}
];
标题解析器可以像任何其他解析器一样使用,允许您注入依赖项、执行一些逻辑或返回 Observable 或 Promise 以返回页面标题字符串。
总结 ?
新的标题策略为 Angular 路由器提供了更多开箱即用的功能,这是长期以来一直要求的,并为开发人员以自定义方式处理页面标题提供了更大的灵活性。