如何在 Angular 应用程序中使用路由更改页面标题?
How to change page title with routing in Angular application?
有没有像 React-Helmet 这样的 npm 模块/其他方式允许我们在通过 Angular 应用程序路由时更改页面标题?
PS:我正在使用Angular 5.
您在 Angular 中有一个 TitleService 5. 将其注入到组件的构造函数中,并使用 setTitle()
方法。
import {Title} from "@angular/platform-browser";
....
constructor(private titleService:Title) {
this.titleService.setTitle("Some title");
}
以下是来自 Angular 的文档:https://angular.io/guide/set-document-title
我更愿意添加包装器 class 只是为了确保如果 import {Title} from "@angular/platform-browser";[=14 我不会在任何地方都改变=] 在即将发布的版本中发生了变化 :) ...也许叫做 "AppTitleService"
import { Injectable } from '@angular/core';
import { Title } from '@angular/platform-browser';
@Injectable({ providedIn: 'root' })
export class AppTitleService {
constructor(private titleService: Title) { }
getTitle() {
this.titleService.getTitle();
}
setTitle(newTitle: string) {
this.titleService.setTitle(newTitle);
}
}
这是在 Angular 8 上设置页面标题的测试方法,但您也可以在 Angular 5 上使用它。
一旦你设置了这个,你只需要在路由文件上设置标题,所有的都会自动设置。
import { Component } from '@angular/core';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { filter, map } from "rxjs/operators";
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
constructor (private router: Router, private activatedRoute: ActivatedRoute, private titleService: Title) {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
map(() => {
let child = this.activatedRoute.firstChild;
while (child) {
if (child.firstChild) {
child = child.firstChild;
} else if (child.snapshot.data && child.snapshot.data['title']) {
return child.snapshot.data['title'];
} else {
return null;
}
}
return null;
})
).subscribe( (data: any) => {
if (data) {
this.titleService.setTitle(data + ' - Website Name');
}
});
}
}
在路由文件中你可以这样做:
const routes: Routes = [
{
path: 'dashboard',
component: DefaultDashboardComponent,
data: {
title: 'Dashboard'
}
}
];
为了动态改变标题,我们可以使用 angular 模块 @angular/platform-browser
并设置标题使用函数 setTitle
函数。
更多详情请查看:platform-browser
// Component.ts
import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-component',
templateUrl: './component.html',
styleUrls: ['./component.css']
})
export class Component implements OnInit {
constructor(private router: Router, private route: ActivatedRoute) { }
path: string[] = [];
pathTitle: string;
ngOnInit() {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
this.path = event.url.substring(1).split('/'); // URL => Whosebug
this.pathTitle = this.route.root.firstChild.snapshot.data.title; // data.title => stack Overflow
});
}
// app-routing.module.ts
const routes: Routes = [
{
path: 'Whosebug',
component: Component,
data: {title: 'stack Overflow'}
}
];
这是一个 non-recursive 解决方案,它还修复了在 path-less 或 component-less 嵌套路由的情况下的标题复制问题。
确保将 Angular 的 Title
服务添加到您的应用程序:https://angular.io/guide/set-document-title.
然后在你的app.component.ts
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { NavigationEnd, Router } from '@angular/router';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
constructor(
private readonly router: Router,
private readonly titleService: Title
) { }
ngOnInit() {
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd)
).subscribe(() => {
this.titleService.setTitle(this.getNestedRouteTitles().join(' | '));
});
}
getNestedRouteTitles(): string[] {
let currentRoute = this.router.routerState.root.firstChild;
const titles: string[] = [];
while (currentRoute) {
if (currentRoute.snapshot.routeConfig.data?.title) {
titles.push(currentRoute.snapshot.routeConfig.data.title);
}
currentRoute = currentRoute.firstChild;
}
return titles;
}
getLastRouteTitle(): string {
let currentRoute = this.router.routerState.root.firstChild;
while (currentRoute.firstChild) {
currentRoute = currentRoute.firstChild;
}
return currentRoute.snapshot.data?.title;
}
}
访问特定的 routeConfig.data
可防止重复继承的 title
属性。
并且在 main-routing.module.ts
或任何其他路由文件中:
const routes: Routes = [
{
path: '',
component: MainComponent,
data: { title: 'MyApplication' },
children: [
{
path: '',
canActivateChild: [AuthGuard],
children: [
{
path: 'dashboard',
loadChildren: () => import('../dashboard/dashboard.module').then(m => m.DashboardModule),
data: { title: 'Dashboard' }
},
{
path: 'settings',
loadChildren: () => import('../settings/settings.module').then(m => m.SettingsModule),
data: { title: 'Settings' }
}
]
}
]
}
];
在Angularv14中,有一个built-in策略服务,用于根据主路由器出口从路由中收集标题,并设置浏览器的页面标题。
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,
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 { }
见here
有没有像 React-Helmet 这样的 npm 模块/其他方式允许我们在通过 Angular 应用程序路由时更改页面标题?
PS:我正在使用Angular 5.
您在 Angular 中有一个 TitleService 5. 将其注入到组件的构造函数中,并使用 setTitle()
方法。
import {Title} from "@angular/platform-browser";
....
constructor(private titleService:Title) {
this.titleService.setTitle("Some title");
}
以下是来自 Angular 的文档:https://angular.io/guide/set-document-title
我更愿意添加包装器 class 只是为了确保如果 import {Title} from "@angular/platform-browser";[=14 我不会在任何地方都改变=] 在即将发布的版本中发生了变化 :) ...也许叫做 "AppTitleService"
import { Injectable } from '@angular/core';
import { Title } from '@angular/platform-browser';
@Injectable({ providedIn: 'root' })
export class AppTitleService {
constructor(private titleService: Title) { }
getTitle() {
this.titleService.getTitle();
}
setTitle(newTitle: string) {
this.titleService.setTitle(newTitle);
}
}
这是在 Angular 8 上设置页面标题的测试方法,但您也可以在 Angular 5 上使用它。 一旦你设置了这个,你只需要在路由文件上设置标题,所有的都会自动设置。
import { Component } from '@angular/core';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { filter, map } from "rxjs/operators";
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
constructor (private router: Router, private activatedRoute: ActivatedRoute, private titleService: Title) {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
map(() => {
let child = this.activatedRoute.firstChild;
while (child) {
if (child.firstChild) {
child = child.firstChild;
} else if (child.snapshot.data && child.snapshot.data['title']) {
return child.snapshot.data['title'];
} else {
return null;
}
}
return null;
})
).subscribe( (data: any) => {
if (data) {
this.titleService.setTitle(data + ' - Website Name');
}
});
}
}
在路由文件中你可以这样做:
const routes: Routes = [
{
path: 'dashboard',
component: DefaultDashboardComponent,
data: {
title: 'Dashboard'
}
}
];
为了动态改变标题,我们可以使用 angular 模块 @angular/platform-browser
并设置标题使用函数 setTitle
函数。
更多详情请查看:platform-browser
// Component.ts
import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-component',
templateUrl: './component.html',
styleUrls: ['./component.css']
})
export class Component implements OnInit {
constructor(private router: Router, private route: ActivatedRoute) { }
path: string[] = [];
pathTitle: string;
ngOnInit() {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
this.path = event.url.substring(1).split('/'); // URL => Whosebug
this.pathTitle = this.route.root.firstChild.snapshot.data.title; // data.title => stack Overflow
});
}
// app-routing.module.ts
const routes: Routes = [
{
path: 'Whosebug',
component: Component,
data: {title: 'stack Overflow'}
}
];
这是一个 non-recursive 解决方案,它还修复了在 path-less 或 component-less 嵌套路由的情况下的标题复制问题。
确保将 Angular 的 Title
服务添加到您的应用程序:https://angular.io/guide/set-document-title.
然后在你的app.component.ts
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { NavigationEnd, Router } from '@angular/router';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
constructor(
private readonly router: Router,
private readonly titleService: Title
) { }
ngOnInit() {
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd)
).subscribe(() => {
this.titleService.setTitle(this.getNestedRouteTitles().join(' | '));
});
}
getNestedRouteTitles(): string[] {
let currentRoute = this.router.routerState.root.firstChild;
const titles: string[] = [];
while (currentRoute) {
if (currentRoute.snapshot.routeConfig.data?.title) {
titles.push(currentRoute.snapshot.routeConfig.data.title);
}
currentRoute = currentRoute.firstChild;
}
return titles;
}
getLastRouteTitle(): string {
let currentRoute = this.router.routerState.root.firstChild;
while (currentRoute.firstChild) {
currentRoute = currentRoute.firstChild;
}
return currentRoute.snapshot.data?.title;
}
}
访问特定的 routeConfig.data
可防止重复继承的 title
属性。
并且在 main-routing.module.ts
或任何其他路由文件中:
const routes: Routes = [
{
path: '',
component: MainComponent,
data: { title: 'MyApplication' },
children: [
{
path: '',
canActivateChild: [AuthGuard],
children: [
{
path: 'dashboard',
loadChildren: () => import('../dashboard/dashboard.module').then(m => m.DashboardModule),
data: { title: 'Dashboard' }
},
{
path: 'settings',
loadChildren: () => import('../settings/settings.module').then(m => m.SettingsModule),
data: { title: 'Settings' }
}
]
}
]
}
];
在Angularv14中,有一个built-in策略服务,用于根据主路由器出口从路由中收集标题,并设置浏览器的页面标题。
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,
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 { }
见here