第四章 路由

点此处可以下载本章完成后的 示例代码 。运行方法为:

  1. 解压缩文件,进入heroes项目根目录。
  2. 使用npm install补上依赖包。也可以把之前备份的node_modules目录复制一份在项目根目录下。
  3. 使用npm start运行项目,打开浏览器访问http://localhost:4200/进入项目。

在前面的例子中,我们把英雄列表和英雄详情放在一个页面中展示,如果应用再复杂一些,这样的安排显然就不合适了。在传统的web应用中,我们通过点击链接的方式,跳转到不同页面,达到浏览各部分功能信息的目的。近年来,Web前端应用的趋势是设计和使用单页面应用,相应的跳转也就被称作视图切换。这里我们就需要使用到一个新概念:路由。

1. 增加路由

我们要使用 Angular 路由器进行导航。

Angular 路由器是一个可选的外部 Angular NgModule,名叫RouterModule。 路由器包含了多种服务(RouterModule)、多种指令(RouterOutlet、RouterLink、RouterLinkActive)、 和一套配置(Routes)。我们将先配置路由。

(1) 将原来的组件显示方式改为路由形式

由于我们要以路由形式显示组件,建立路由前,让我们先把src/app/app.component.html中的<app-hero-list></app-hero-list>删掉。改成<router-outlet></router-outlet>

(2) 组件

打开src/index.html,确保它的<head>区顶部有一个<base href="/">元素

<head>
  <base href="/">
</head>

(3) 引入 app-routing.module.ts

我们可以把路由信息写在src/app/app.module.ts中,但是这样做,会干扰这个文件本来的功能。所以我们引入一个专门的文件src/app/app-routing.module.ts

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

import { HeroListComponent }      from './heroes/hero-list/hero-list.component';

const routes: Routes = [
  { path: '', redirectTo: '/heroes', pathMatch: 'full' },
  { path: 'heroes',component: HeroListComponent },
];

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

(4) 修改app.module.ts文件

src/app/app.module.ts文件中,增加以下内容:

import { AppRoutingModule } from './app-routing.module';

imports: [
  BrowserModule,
  FormsModule,
  AppRoutingModule
],

好了,现在再浏览应用,就会发现地址栏中的URL被改为了http://localhost:4200/heroes,英雄列表又出来了。

2. 扩展阅读:路由的基本配置和用法

路由所要解决的核心问题是通过建立URL和页面的对应关系,使得不同的页面可用不同的URL来表示。主流前端框架围绕这个问题给出了各自的路由实现,虽然语法和工作机制不尽相同,但理念却殊途同归。在Angular中,页面由组件构成,因此URL和页面的对应关系实质上就是URL和组件的对应关系。下面简单介绍一下一些基本概念:

  • 基本配置:包括路由配置、创建根路由模块、添加router-outlet指令
  • 路由策略:决定将使用URL的哪一部分来和路由配置项path属性进行匹配。
  • 路由跳转:应用相应某个事件,从一个页面跳转到另外一个页面的行为。有两种跳转方式:使用指令跳转和使用代码跳转
  • 路由参数:Angular路由提供此功能允许通过URL向组件传递数据。

基本配置

  • 路由配置

它是一个Routes类型的数组,数组的每一个元素即为一个路由配置项。第一个配置项中path之对应的URL为网页需要跳转的地址,第二个component项对应的是需要关联的组件。

// app.routes.ts 根路由组件
import { Routes } from '@angular/router';

import { AComponent } from './a/a.component';
import { BComponent } from './b/b.component';

export const rootRouterConfig: Routes = [
    // ...
    {
        path: 'a',    // http://localhost:4200/a
        component: AComponent
    },
    {
        path: 'b',    // http://localhost:4200/b
        component: BComponent
    };
]
  • 创建根路由模块

根路由模块包含了路由所需的各项服务,是路由工作流程得以正常执行的基础。下面的代码以路由配置rootRouterConfig为参数,通过调用RouterModule.forRoot()方法来创建根路由模块,并将其导入到应用的根模块AppModule中。

// app.module.ts 根组件模块
// 注意引入相关的模块
import { ModuleWithProviders } from '@angular/core';
// 注意引入相关的模块: like RouterModule, ModuleWithProviders
import { RouterModule } from '@angular/router';
import { rootRouterConfig } from './app.routes'; // 这里引入在根路由组件里面定义的路由配置

let rootRouterModule: ModuleWithPrviders = RouterModule.forRoot(rootRouterConfig);

@NgModule({
    imports: [rootRouterModule],
    // ...
})
export class AppModule {}

需要注意的是,根路由模块默认提供的路由策略为PathLocationStrategy。该策略要求应用必须设置一个base路径,用于作为前缀来生成和解析URL。最简单方式是在index.html文件中设置<base>元素的href属性。(当然,如果使用ng命令生成文件的话已经在里面帮你写好了,不过还是要强调一下)

<!-- index.html -->
<!DOCTYPE html>
<html>
    <head>
        <base href="/">
        <!-- ... -->
    </head>
    <body>
        <!-- ... -->
    </body>
</html>
  • 添加RouterOutlet指令

RouterOutlet指令的作用是在组件的模板中开辟出一块区域,用于显示URL所对应的组件。就是说不同的URL只改变routeroutlet里面的内容(当然。。。这里需要强调的是有一级路由、二级路由...的概念,N级地址渲染N级路由的outlet),还是给个例子来具体看看。

<!-- app.component.html -->
<main class="main">
    <router-outlet></router-outlet>
</main>

于是,根组件的html文档可以写成这样

<body>
    <main class="main">
        <router-outlet></router-outlet>

        <!-- ListComponent组件 -->
        <list>
             <!-- ... -->
        </list>
    </main>
</body>

当在页面输入localhost:4200/alocalhost:4200/b时,子组件AComponentBComponent分别会渲染到router-outlet标签里面去,而不影响其它的内容。

路由策略

主要分为两种:PathLocationStrategyHashLocationStrategy

  • HashLocationStrategy

主要是浏览器向服务器发送请求时不会带上hash部分的内容,以致于对于所有配置项所对应的URL,浏览器向服务器发送的请求都为同一个,服务器只需要返回应用的首页,Angular在获取首页后会根据hash的内容去匹配路由配置项并渲染相应的组件。

更改URL的hash部分不会向服务器重新发送请求,这使得在进行跳转的时候不会引发页面的刷新和应用的重新加载。

具体的使用方法是注入路由服务时使用useHash属性进行显式指定。

// app.module.ts

// ...
@NgModule({
    imports: [RouterModule.forRoot(rootRouterConfig, {useHash: true})],
    // ...
})
export class AppModule {}

使用localhost:4200/#/alocalhost:4200/#/b访问网页即可。

  • PathLocationStrategy

这个是angular的默认路由策略,其最大优点在于为服务器端渲染提供了可能。使用URL的path部分来进行路由匹配,浏览器会将配置项对应的URL原封不动地发送给服务器。

就是平时浏览器解析地址的原理哈,不要想得太复杂=_=亲·

路由跳转

对于使用Angular构建的单页应用而言,页面跳转实质上就是从一个配置项跳转到另一个配置项的行为。它有两种方式进行介绍。

  • 使用指令跳转
<a [routerlink]="['/a']">
    <i>跳转到a</i>
</a>

<a [routerlink]="['/b']">
    <i>跳转到b</i>
</a>

注意改变的都是当前路由的地址,它会根据点击的情况跳转到localhost:4200/a或者localhost:4200/b

  • 使用代码跳转
import { Router } from '@angular/core';

export class AppComponent implements OnInit {
    constructor(private _router: Router) [
        setTimeout(() => {
            _router.nabigateByUrl('/a');
            // 或者执行_router.navigate(['/a']) 两者机理一致
        }, 1000);
    }
}

所以说合理地选择如何进行路由的跳转是十分有必要的。

路由参数

Angular可以通过地址来传递参数,从而达到不同的组件之间的通讯。

首先配置路由的设置

// app.routes.ts 通过配置ts文件
export const ContactsAppRouters: RouterConfig = [
    { path: 'a/:id', component: DetailComponent }
}

// app.html 配置html
<a [routerLink]="['/detail', 1]">

// a.component.ts 配置子组件的id获取
import { ActiveRoute } from '@angular/router';

export class AComponent implements OnInit, OnDestroy {
    a_id: string;

    constructor( private activatedRoute: ActivatedRoute ) {
        console.log("创建了一个组件的实例");
    }

    ngOnInit() {
        // 通过调用snapshot方法来获取传递参数的值
        this.a_id = this.activatedRoute.snapshot.params['id'];
    }

    // ...
}

解析出来的id即为路由参数(可以任意指定参数的名称)可以直接通过 http://locahost:4200/a/1 直接访问参数的详情的页面.

results matching ""

    No results matching ""