如何改变页面标题与路由在角度应用?

是否有任何 npm 模块/其他方式,如 反应-头盔,让我们改变页面标题,因为我们路由通过我们的角度应用程序?

附注: 我正在使用角度5。

91579 次浏览

You have a TitleService in Angular 5. Inject it in your component's constructor, and use the setTitle() method.

import {Title} from "@angular/platform-browser";


....


constructor(private titleService:Title) {
this.titleService.setTitle("Some title");
}

Here are the docs from Angular: https://angular.io/guide/set-document-title

I would prefer to add a wrapper class just to make sure that i will not change everywhere if import {Title} from "@angular/platform-browser"; changed in the upcoming release :) ... Maybe Something called "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);
}
}

Here is tested way to set page title on Angular 8 but you can use it on Angular 5 as well. Once you set this you have to just set title on route file and all will set automatically.

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');
}
});
}


}

And on route file you can do something like this:

const routes: Routes = [
{
path: 'dashboard',
component: DefaultDashboardComponent,
data: {
title: 'Dashboard'
}
}
];

For make dynamic changing title we can used angular module @angular/platform-browser and set title used function setTitle function.

For more details please check : 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 => stackOverflow
this.pathTitle = this.route.root.firstChild.snapshot.data.title; // data.title => stack Overflow
});
}
    

// app-routing.module.ts
const routes: Routes = [
{
path: 'stackOverflow',
component: Component,
data: {title: 'stack Overflow'}
}
];

Here's a non-recursive solution that also fixes the replication of titles in case of path-less or component-less nested routes.

Make sure to add Angular's Title service to your application: https://angular.io/guide/set-document-title.

Then in your 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;
}
}


Accessing the specific routeConfig.data prevents the repetition of the inherited title attribute.

And in main-routing.module.ts or any of your other routing files:

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' }
}
]
}
]
}
];

In Angular v14, there is a built-in strategy service for collecting the title from the route based on the primary router outlet, and setting the browser's page 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,
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 { }

See here

Today is 2022-10-14. Answers above including Angular's own doc are very good, but not the easiest/lightest, and sometimes tedious.

We have hundreds of components/pages, Angular 12+, title and <meta name="description" ...> are typically static, so the best way is hardcode without adding any packages:

<head>
<title...>
<meta ...>
...
</head>

While Chrome and Edge, including META SEO inspector show all title and meta from index.html and components, browsers display only the first title in the order of discovery.

Solution:

  1. Move <title> and <meta> of index.html to bottom
  2. Every component/page to have its own else default to index’s

Reasons:

  • <head> is no longer mandatory in HTML5 whom was released in 2014
  • <title> and <meta> can be placed anywhere
  • They are allowed to have multiple entries even for the same duplicated name
  • <title>, first discovered will be used for display so component/page’s shows
  • <meta>, all are used.
  • See this SO for details.

With one simple adjustment inside of index.html, Wa-La, all pages display the corresponding title. No need to introduce any new component/package and update hundreds of files, and SEO 100!

BTW, this is not just for Angular, apply to all others including .NET, Vue and React.