【问题标题】:how to change page title in angular2 router如何在angular2路由器中更改页面标题
【发布时间】:2016-04-08 18:05:18
【问题描述】:

我正在尝试从路由器更改页面标题,可以这样做吗?

import {RouteConfig} from 'angular2/router';
@RouteConfig([
  {path: '/home', component: HomeCmp, name: 'HomeCmp' }
])
class MyApp {}

【问题讨论】:

标签: typescript angular angular2-routing


【解决方案1】:

对于 Angular 4+:

如果您想使用路由自定义数据为每个路由路径定义页面标题,以下方法将适用于嵌套路由和角度版本 4+:

您可以在路由定义中传递页面标题:

  {path: 'home', component: DashboardComponent, data: {title: 'Home Pag'}},
  {path: 'about', component: AboutUsComponent, data: {title: 'About Us Page'}},
  {path: 'contact', component: ContactUsComponent, data: {title: 'Contact Us Pag'}},

现在,最重要的在您的上层组件(即AppComponent)中,您可以全局捕获每次路线更改的路线自定义数据并更新页面标题:

    import {Title} from "@angular/platform-browser";
    import { filter, map } from 'rxjs/operators';
    export class AppComponent implements OnInit {

        constructor(
            private activatedRoute: ActivatedRoute, 
            private router: Router, 
            private titleService: Title
        ) { }

  ngOnInit() {
    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( (title: any) => {
      this.titleService.setTitle(title);
  });
}

以上代码针对 Angular 版本 4+ 进行了测试。

【讨论】:

  • 太棒了!只是更多的补充。一定要在Module中添加import { BrowserModule, Title } from '@angular/platform-browser';并设置providers: [Title],并且还要在Component中添加import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/map';。否则你会得到一些错误。
【解决方案2】:

设置标题的简单通用方法:

import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  constructor(
    private activatedRoute: ActivatedRoute,
    private router: Router,
    private titleService: Title
    ) {}

  ngOnInit() {
    this.router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        const { title } = this.activatedRoute.firstChild.snapshot.data;
        this.titleService.setTitle(title);
      }
    });
  }

}

title 需要在每条路线上设置,例如:

{ path: '', component: WelcomeComponent, data: {title: 'Welcome to my app'} }

【讨论】:

    【解决方案3】:

    在 Angular 6 和 6+ 中使用 Pipe 和 map 方法而不是使用过滤器可以正常工作

    Step1:路由设置

    {path: 'dashboard', component: DashboardComponent, data: {title: 'My Dashboard'}},
    {path: 'aboutUs', component: AboutUsComponent, data: {title: 'About Us'}},
    {path: 'contactUs', component: ContactUsComponent, data: {title: 'Contact Us Page'}},
    

    第 2 步: 在您的 app.module.ts 导入模块中

    import { BrowserModule, Title } from '@angular/platform-browser';
    

    然后在提供者中添加提供者:[title]

    第 3 步 在您的主要组件导入中

    import { Title } from "@angular/platform-browser";
    import { RouterModule, ActivatedRoute, Router, NavigationEnd } from "@angular/router";
    import { filter, map } from 'rxjs/operators';
    
    constructor(private titleService: Title, private router: Router, private activatedRoute: ActivatedRoute) {
    
        }
    
    ngOnInit() {
    
        this.router.events.pipe(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(title => {
            this.titleService.setTitle(title);
        });
    
    }
    

    【讨论】:

      【解决方案4】:

      Angular 6+

      如果路由配置如下:-

      Routes = [
           {  path: 'dashboard',
             component: DashboardComponent,
             data: {title: 'Dashboard'}
         }]
      

      **那么在组件构造函数中的title可以设置如下:- **

       constructor( private _titleService: Title, public activatedRoute: ActivatedRoute) {
          activatedRoute.data.pipe(map(data => data.title)).subscribe(x => this._titleService.setTitle(x));
         }
      

      【讨论】:

        【解决方案5】:

        Angular 6+ 我已经使用 new Pipe() 修改了旧代码并且它工作正常。

        import { Title } from '@angular/platform-browser';
        import { filter, map, mergeMap } from 'rxjs/operators';
        

        ...

        constructor(
            private router: Router,
            public activatedRoute: ActivatedRoute,
            public titleService: Title,
          ) {
            this.setTitle();
          }
        

        ....

        setTitle() {
          this.router.events.pipe(
            filter((event) => event instanceof NavigationEnd),
            map(() => this.activatedRoute),
            map((route: any) => {
              while (route.firstChild) route = route.firstChild;
              return route;
            }),
            filter((route) => route.outlet === 'primary'),
            mergeMap((route: any) => route.data)).subscribe((event) => {
              this.titleService.setTitle(event['title']);
              console.log('Page Title', event['title']);
            })
          }
        

        【讨论】:

          【解决方案6】:

          在下面的例子中:

          -我们向任何路由对象添加了数据对象:{ title: 'NAME' }。

          -我们为上传时间设置了一个基本名称(“CTM”)(点击F5进行刷新时):<title>CTM</title>

          -我们添加了“TitleService”类。

          -我们通过从 app.component.ts 过滤 Routher 事件来处理它们。

          index.html:

          <!DOCTYPE html>
          <html>
            <head>
              <base href="/">
              <title>CTM</title>
            </head>
          

          ...

          app.module.ts:

          import { NgModule, enableProdMode } from '@angular/core';
          import { BrowserModule  } from '@angular/platform-browser';
          import { TitleService }   from './shared/title.service';
          ...
          
          
          @NgModule({
            imports: [
              BrowserModule,
          ..
            ],
            declarations: [
                AppComponent,
          ...
            ],
            providers: [
                TitleService,
          ...
            ],
            bootstrap: [AppComponent],
          })
          export class AppModule { }
          
          enableProdMode();
          

          title.service.ts:

          import { Injectable } from '@angular/core';
          import { Title }  from '@angular/platform-browser';
          import { ActivatedRouteSnapshot } from '@angular/router';
          
          
          @Injectable()
          export class TitleService extends Title {
          
              constructor() {
                  super();
              }
          
          
              private recursivelyGenerateTitle(snapshot: ActivatedRouteSnapshot) {
                  var titleParts = <string[]>[];
                  if (snapshot) {
                      if (snapshot.firstChild) {
                          titleParts = this.recursivelyGenerateTitle(snapshot.firstChild);
                      }
          
                      if (snapshot.data['title']) {
                          titleParts.push(snapshot.data['title']);
                      }
                  }
          
                  return titleParts;
              }
          
              public CTMGenerateTitle(snapshot: ActivatedRouteSnapshot) {
                  this.setTitle("CTM | " + this.recursivelyGenerateTitle(snapshot).join(' - '));
              }
          
          }
          

          app-routing.module.ts:

          import { Injectable } from '@angular/core';
          import { NgModule } from '@angular/core';
          import { Routes, RouterModule } from '@angular/router';
          
          import { MainComponent } from './components/main.component';
          
          import { Router, CanActivate } from '@angular/router';
          import { AuthGuard }          from './shared/auth/auth-guard.service';
          import { AuthService }    from './shared/auth/auth.service';
          
          
          export const routes: Routes = [
            { path: 'dashboard', component: MainComponent, canActivate: [AuthGuard], data: { title: 'Main' } },
          ];
          
          @NgModule({
              imports: [
                  RouterModule.forRoot(routes, { useHash: true })  // .../#/crisis-center/
              ],
              exports: [RouterModule],
              providers: [
          ..
              ]
          })
          
          export class AppRoutingModule { }
          
          export const componentsOfAppRoutingModule = [MainComponent];
          

          app.component.ts:

          import { Component } from '@angular/core';
          import { Router, NavigationEnd, ActivatedRouteSnapshot } from '@angular/router';
          import { TitleService } from './shared/title.service';
          
          @Component({
            selector: 'ctm-app',
            template: `
              <!--<a [routerLink]="['/dashboard']">Dashboard</a>
              <a [routerLink]="['/login']">Login</a>
              <a [routerLink]="['/']">Rooting</a>-->
              <router-outlet></router-outlet>
              `
          })
          export class AppComponent {
          
              constructor(private router: Router, private titleService: TitleService) {
          
                  this.router.events.filter((event) => event instanceof NavigationEnd).subscribe((event) => {
                      console.log("AppComponent.constructor: Setting HTML document's Title");
                      this.titleService.CTMGenerateTitle(this.router.routerState.snapshot.root);
                  });
          
              }
          
          
          }
          

          【讨论】:

            【解决方案7】:

            Title service @EricMartinez points out 有一个 setTitle() 方法 - 这就是设置标题所需的全部内容。

            就路由更改自动执行此操作而言,截至目前除了订阅Router 并在您的回调中调用setTitle() 之外,没有内置的方法可以做到这一点: p>

            import {RouteConfig} from 'angular2/router';
            import {Title} from 'angular2/platform/browser';
            
            @RouteConfig([
              {path: '/home', component: HomeCmp, name: 'HomeCmp' }
            ])
            class MyApp {
                constructor(router:Router, title:Title) {
                   router.events.subscribe((event)=>{ //fires on every URL change
                      title.setTitle(getTitleFor(router.url));
                   });
                }
             }
            

            也就是说,我强调到目前为止,因为路由器仍在大力开发中,我希望(或至少希望)我们能够通过RouteConfig 做到这一点最终版本。

            编辑:

            随着 Angular 2 (2.0.0) 的发布,一些事情发生了变化:

            【讨论】:

            • 在Angular2中router.subscribe现在也是router.events.subscribe
            • getTitleFor(url) 这个方法返回什么?即路由器配置中name 的值?
            • 如果我正确阅读了文档,getTitleFor() 就不再是问题了。
            • 我发现this answer 更详细一点
            【解决方案8】:

            这是我的方法,特别适用于嵌套路由:

            我使用递归辅助方法在路线更改后获取最深的可用标题:

            @Component({
              selector: 'app',
              template: `
                <h1>{{title | async}}</h1>
                <router-outlet></router-outlet>
              `
            })
            export class AppComponent {
              constructor(private router: Router) {
                this.title = this.router.events
                  .filter((event) => event instanceof NavigationEnd)
                  .map(() => this.getDeepestTitle(this.router.routerState.snapshot.root));
              }
            
              title: Observable<string>;
            
              private getDeepestTitle(routeSnapshot: ActivatedRouteSnapshot) {
                var title = routeSnapshot.data ? routeSnapshot.data['title'] : '';
                if (routeSnapshot.firstChild) {
                  title = this.getDeepestTitle(routeSnapshot.firstChild) || title;
                }
                return title;
              }
            }
            

            这是假设您在路由的数据属性中分配了页面标题,如下所示:

            {
              path: 'example',
              component: ExampleComponent,
              data: {
                title: 'Some Page'
              }
            }
            

            【讨论】:

            • 我在router.routeSnapshot.root.data 寻找数据属性,但它似乎可以根据路由的设置方式进行嵌套。这个答案对我有用。
            • 我必须添加 this.title = this.getDeepestTitle(this.activatedRoute.snapshot.root); 才能在第一次访问时使用。
            【解决方案9】:

            这是在导航页面/视图时更改页面标题的最简单方法(从 Angular @2.3.1 开始测试)。只需将以下解决方案应用于您拥有的所有视图,您就可以开始了:

            关于我们页面/视图中的示例代码:

            import {Title} from "@angular/platform-browser";
            
            export class AboutUsComponent implements OnInit {
            
              constructor(private _titleService: Title) {
              }
            
              ngOnInit() {
                //Set page Title when this view is initialized
                this._titleService.setTitle('About Us');
              }
            
            }
            

            联系我们页面/视图中的示例代码:

            import {Title} from "@angular/platform-browser";
            
            export class ContactusComponent implements OnInit {
            
              constructor(private _titleService: Title) {
              }
            
              ngOnInit() {
                //Set page Title
                this._titleService.setTitle('Contact Us');
              }
            
            }
            

            【讨论】:

            • 我强烈推荐这个答案
            【解决方案10】:

            我还可以推荐我刚刚发布的@ngx-meta/core 插件插件,以防您正在寻找一种动态设置页面标题和元标记的方法。

            【讨论】:

              【解决方案11】:

              Angular 2 提供了一个 Title Service 参见 Shailesh 的答案只是该代码的副本。

              我是我们的 app.module.ts

              import { BrowserModule, Title } from '@angular/platform-browser';
              ........
              providers: [..., Title],
              bootstrap: [AppComponent]
              

              现在转到我们的 app.component.ts

              import { Title }     from '@angular/platform-browser';
              ......
              export class AppComponent {
              
                  public constructor(private titleService: Title ) { }
              
                  public setTitle( newTitle: string) {
                    this.titleService.setTitle( newTitle );
                  }
              }
              

              将标题标签放在你的组件 html 上,它会为你读取和设置。

              如果你想知道如何动态设置它和further detail see this article

              【讨论】:

                【解决方案12】:

                这就是我的选择:

                constructor(private router: Router, private title: Title) { }
                
                ngOnInit() {
                    this.router.events.subscribe(event => {
                        if (event instanceof NavigationEnd) {
                            this.title.setTitle(this.recursivelyGenerateTitle(this.router.routerState.snapshot.root).join(' - '));
                        }
                    });
                }
                
                recursivelyGenerateTitle(snapshot: ActivatedRouteSnapshot) {
                    var titleParts = <string[]>[];
                    if (snapshot) {
                        if (snapshot.firstChild) {
                            titleParts = titleParts.concat(this.recursivelyGenerateTitle(snapshot.firstChild));
                        }
                
                        if (snapshot.data['title']) {
                            titleParts.push(snapshot.data['title']);
                        }
                    }
                
                    return titleParts;
                }
                

                【讨论】:

                • 太棒了,我所做的唯一调整是确保 HTML 文档上的标题并调整了这行代码(注意 reverse())、this.title.setTitle(this.title.getTitle().split(' - ')[0] + ' - ' + this.recursivelyGenerateTitle(this.router.routerState.snapshot.root).reverse().join(' - '));
                • 或者,您可以使用unshift() 代替push(),然后使用reverse()
                【解决方案13】:
                import {Title} from "@angular/platform-browser"; 
                @Component({
                  selector: 'app',
                  templateUrl: './app.component.html',
                  providers : [Title]
                })
                
                export class AppComponent implements {
                   constructor( private title: Title) { 
                     this.title.setTitle('page title changed');
                   }
                }
                

                【讨论】:

                  【解决方案14】:

                  这真的很简单,你可以按照下面的步骤来看看效果:

                  我们在 bootstrap 中提供 Title 服务:

                  import { NgModule } from '@angular/core';
                  import { BrowserModule, Title }  from '@angular/platform-browser';
                  
                  import { AppComponent } from './app.component';
                  
                  @NgModule({
                    imports: [
                      BrowserModule
                    ],
                    declarations: [
                      AppComponent
                    ],
                    providers: [
                      Title
                    ],
                    bootstrap: [ AppComponent ]
                  })
                  export class AppModule { }
                  

                  然后在你想要的组件中导入这个服务:

                  import { Component } from '@angular/core';
                  import { Title }     from '@angular/platform-browser';
                  
                  @Component({
                  selector: 'my-app',
                  template:
                    `<p>
                      Select a title to set on the current HTML document:
                    </p>
                  
                    <ul>
                      <li><a (click)="setTitle( 'Good morning!' )">Good morning</a>.</li>
                      <li><a (click)="setTitle( 'Good afternoon!' )">Good afternoon</a>.</li>
                      <li><a (click)="setTitle( 'Good evening!' )">Good evening</a>.</li>
                    </ul>
                    `
                  })
                  export class AppComponent {
                    public constructor(private titleService: Title ) { }
                  
                    public setTitle( newTitle: string) {
                      this.titleService.setTitle( newTitle );
                    }
                  }
                  

                  现在点击这些链接查看标题的变化。

                  你也可以使用 ng2-meta 来改变页面标题和描述,你可以参考这个链接:

                  https://github.com/vinaygopinath/ng2-meta

                  【讨论】:

                  • 是的,很棒的答案,使用它我们也可以更改标题和描述,无需在您的代码中额外使用Title angular2 服务,感谢您的回答。
                  • @PardeepJain 即使我的应用程序需要 4 秒才能加载,此解决方案是否有效?我使用了 ng2-meta,但由于我的应用程序加载时间,它不起作用。 (我已尽一切努力减少加载时间)
                  • 如果用户输入页面网址并按回车键或刷新页面,它会起作用吗?我可以看到你从文档中复制了相同的代码 :) angular.io/docs/ts/latest/cookbook/set-document-title.html
                  猜你喜欢
                  • 2020-03-27
                  • 2018-01-09
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-08-17
                  • 2016-09-01
                  • 2017-03-29
                  • 2021-03-31
                  相关资源
                  最近更新 更多