这是一个很常见的需求,多个页面共用一个header,跳转不同的路由,header显示不同的内容,比如标题等。

React或者Vue中,我们常会使用状态管理来处理这类需求,例如vuex。在Angular中,因为有service这一概念,service是单例的,通过依赖注入到各个组件的,所以不需要状态管理。

header.service.ts

所以,我们需要创建一个service来管理header的状态。

@Injectable({
  providedIn: 'root'
})
export class HeaderService {
  private title: string;

  public getTitle() {
    return this.title ? this.title : '';
  }

  public setTitle(title: string) {
    setTimeout(() => this.title = title);
  }
}

这个service就可以用来控制header的标题,getset方法我是java的写法,当然可以按照ts的写法写。

绑定到模板

header.service注入到模板里,在模板需要的位置调用getTitle()方法即可。

<div class="title-container">
    <div class="title">
        {{ headerService.getTitle() }}
    </div>
</div>

然后在对应的页面里使用setTitle()方法改变header的标题。

this.headerService.setTitle('hellow world');

监听路由

除了在每个页面中调用setTitle()方法,还可以通过监听路由的方式。

首先在路由配置里定义好title

const routes: Routes = [
  {
    path: '',
    children: [
      {
        path: '',
        component: UserCenterComponent,
        data: {
          title: '我的'
        }
      }
];

回到header.service.ts

import { Injectable } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { filter, map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class HeaderService {

  private title: string;

  constructor(
    private router: Router
  ) {
    this.listen();
  }

  private getData(router: Router) {
    const dataArr = this.recursionData(router.routerState, router.routerState.root);
    return dataArr[dataArr.length - 1];
  }

  private recursionData(state: any, parent: any) {
    const data = [];
    if (parent && parent.snapshot.data) {
      data.push(parent.snapshot.data);
    }

    if (state && parent) {
      data.push(...this.recursionData(state, state.firstChild(parent)));
    }
    return data;
  }

  private listen() {
    this.router.events
      .pipe(
        filter(event => event instanceof NavigationEnd),
        map(() => this.router)
      )
      .subscribe(event => {
        const data = this.getData(event);
        this.title = data.title;
      });
  }


  public getTitle() {
    return this.title ? this.title : '';
  }

  public setTitle(title: string) {
    setTimeout(() => this.title = title);
  }
}

添加了listengetDatarecursionData三个方法,后两个用于获取当前路由的datalisten用于监听路由,在实例化时被调用。

用上面的方法就可以在定义路由时配置一些参数显示在header上了。