Angular 如何根据路线更改导航菜单 header

Angular How to change navmenu header based on route

我正在使用 Angular 4+.

在当前项目中设计仪表板布局

当用户在应用程序的不同部分之间导航时,我需要更新导航菜单 header 标题以反映应用程序的当前部分。

例如,当用户访问设置时 "Page Title" 应更改为 "Settings"

项目基于.net core 2 Angular模板 下面是我必须编写应用程序路由以及仪表板路由的代码。

navigation.service

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class NavigationService {
    private titleSource = new BehaviorSubject<string>("Page Title");
    currentTitle = this.titleSource.asObservable();

    constructor() {
    }

    changeTitle(title: string) {
        this.titleSource.next(title);
    }
}

app-routing.module

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { HomeComponent } from "./components/home/home.component";

const appRoutes: Routes = [
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { path: '**', redirectTo: 'home' }
]

@NgModule({
    imports: [
        RouterModule.forRoot(appRoutes)],
    exports: [RouterModule]
})
export class AppRoutingModule { }

app.module.shared

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppRoutingModule } from './app-routing.module';
import { DashboardModule } from "./components/dashboard/dashboard.module";

import { UtilsModule } from "./components/shared/shared.module";
//app components
import { AppComponent } from './components/app/app.component';

import { NavigationService } from "./services/navigation.service";

@NgModule({
    declarations: [
        AppComponent,

    ],
    imports: [
        SharedModule,
        DashboardModule,
        AppRoutingModule,
        DevExtremeModule,
        CommonModule,
        HttpModule,
        FormsModule
    ],
    providers: [NavigationService]
})
export class AppModuleShared {
}

dashboard-routing.module

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { DashboardComponent } from "./dashboard.component";
import { SettingsProfileComponent } from "./settings/settingsProfile/settings.profile.component";
import { SettingsEmailComponent } from "./settings/settingsEmail/settings.email.component";
import { UsersListComponent } from "./users/users.list.component";

export const dashboardRoutes: Routes = [
    {
        path: 'dashboard',
        component: DashboardComponent,
        children: [{
            path: 'settings',
            data: { title: 'Settings' },

            children: [{
                path: 'profile',
                component: SettingsProfileComponent
            },
            {
                path: 'email',
                component: SettingsEmailComponent
            }]
        }, {
                path: 'users',
                data: { title: 'Users' },
                children: [{
                    path: '',
                    component: UsersListComponent
                }]
        }]
    }
];

@NgModule({
    imports: [
        RouterModule.forChild(dashboardRoutes)
    ],
    exports: [RouterModule]
})
export class DashboardRoutingModule { }

dashboard.module

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UtilsModule } from "../shared/shared.module";

import { DashboardRoutingModule } from "./dashboard-routing.module";

import { DashboardComponent } from './dashboard.component';
import { SettingsProfileComponent } from "./settings/settingsProfile/settings.profile.component";
import { SettingsEmailComponent } from "./settings/settingsEmail/settings.email.component";
import { UsersListComponent } from "./users/users.list.component";

@NgModule({
    imports: [
        CommonModule,
        UtilsModule,
        DashboardRoutingModule
    ],
    declarations: [
        DashboardComponent,
        SettingsProfileComponent,
        SettingsEmailComponent,
        UsersListComponent,
    ],
    providers: []
})
export class DashboardModule {
}

我试图避免在每个组件中都有一个 OnInit。是否可以仅在路由中执行此操作?该项目还处于早期阶段,因此如果有关于如何实现这一目标的任何其他建议,我们愿意进行更改。

有很多方法可以解决这个问题。一种可能的解决方案是监听路由器事件,并根据它们决定应该显示什么内容。

这种方法需要首先导入导航状态,例如,当路线更改结束时。像这样:

import { Router, NavigationEnd } from '@angular/router';

那么你需要订阅那个,例如像这样。

constructor ( private router:  Router ) {
router.events.subscribe( (event) => ( event instanceof NavigationEnd ) && this.handleRouteChange() )

}

一旦您能够检测到导航的变化,您就可以看到它是什么路线,并根据该路线做出进一步的决定。例如像这样:

  handleRouteChange = () => {
    if (this.router.url.includes('some_key_part_of_url') {
     do what ever you want to do with your content...
    }
  };

你不一定要分析url的实际内容,你可以根据路由器的其他属性来决定。请阅读 the docs on router

另一个选项可能是路由 guard/route 解析器。您可以向每条路线添加一个 guard/resolver 并让它读取您的数据 属性.

这是一个解析器示例:

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

import { Observable } from 'rxjs/Observable';

import { IMovie } from './movie';
import { MovieService } from './movie.service';

@Injectable()
export class MovieResolver implements Resolve<IMovie> {

    constructor(private movieService: MovieService,
                private navigationService: NavigationService) { }

    resolve(route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot): boolean {
        const title = route.data['title'];
        this.navigationService.changeTitle(title);
        return true;
    }
}

类似于上面的内容。