Angular 路由的完整指南

已发表: 2022-03-10
快速总结↬在本教程中,Ahmed Bouchefra 介绍了 Angular Router 以及如何使用它来创建具有路由和导航的客户端应用程序和单页应用程序。

如果您还不太熟悉 Angular 7,我想让您更接近这个令人印象深刻的前端框架所提供的一切。 我将引导您完成一个 Angular 演示应用程序,该应用程序显示与路由器相关的不同概念,例如:

  • 路由器插座,
  • 路线和路径,
  • 导航。

我还将向您展示如何使用 Angular CLI v7 生成一个演示项目,我们将在其中使用 Angular 路由器来实现路由和导航。 但首先,请允许我向您介绍 Angular 并回顾其最新版本中的一些重要新功能。

介绍 Angular 7

Angular 是用于为移动和桌面 Web 构建客户端 Web 应用程序的最流行的前端框架之一。 它遵循基于组件的架构,其中每个组件都是独立且可重用的代码,用于控制应用程序 UI 的一部分。

Angular 中的组件是一个使用@Component装饰器装饰的 TypeScript 类。 它有一个附加的模板和构成组件视图的 CSS 样式表。

Angular 7 是 Angular 的最新版本,最近发布了新功能,特别是在 CLI 工具和性能方面,例如:

  • CLI 提示:像ng addng new这样的常用命令现在可以提示用户选择要添加到项目中的功能,如路由和样式表格式等。
  • 向 Angular Material CDK(组件 DevKit)添加滚动。
  • 向 Angular Material CDK 添加拖放支持。
  • 项目也默认使用预算包,当他们的应用程序超过大小限制时,它会警告开发人员。 默认情况下,当大小超过 2MB 并且错误为 5MB 时会引发警告。 您还可以在angular.json文件中更改这些限制。 等等。
跳跃后更多! 继续往下看↓

介绍 Angular 路由器

Angular Router 是一个强大的 JavaScript 路由器,由 Angular 核心团队构建和维护,可以从@angular/router包中安装。 它提供了一个完整的路由库,可以有多个路由器出口、不同的路径匹配策略、轻松访问路由参数和路由保护以保护组件免受未经授权的访问。

Angular 路由器是 Angular 平台的核心部分。 它使开发人员能够构建具有多个视图的单页应用程序,并允许在这些视图之间导航。

现在让我们更详细地了解基本的路由器概念。

路由器插座

Router-Outlet是一个可从路由器库中获得的指令,路由器在其中插入根据当前浏览器的 URL 匹配的组件。 您可以在 Angular 应用程序中添加多个插座,从而实现高级路由场景。

 <router-outlet></router-outlet>

任何被路由器匹配的组件都会将其渲染为路由器出口的兄弟。

路线和路径

路由是由至少一个路径和一个组件(或重定向到路径)属性组成的定义(对象)。 路径是指 URL 中决定应该显示的唯一视图的部分,组件是指需要与路径关联的 Angular 组件。 基于我们提供的路由定义(通过静态RouterModule.forRoot(routes)方法),路由器能够将用户导航到特定视图。

每个Route都将一个 URL path映射到一个组件。

路径可以为空,表示应用程序的默认路径,通常是应用程序的开始。

路径可以采用通配符字符串 ( ** )。 如果请求的 URL 与定义的路由的任何路径都不匹配,路由器将选择此路由。 这可用于显示“未找到”视图或在未找到匹配项时重定向到特定视图。

这是一个路由示例:

 { path: 'contacts', component: ContactListComponent}

如果将此路由定义提供给路由器配置,则当 Web 应用程序的浏览器 URL 变为/contacts时,路由器将呈现ContactListComponent

路由匹配策略

Angular Router 提供了不同的路由匹配策略。 默认策略只是检查当前浏览器的 URL 是否以path为前缀。

例如我们之前的路线:

 { path: 'contacts', component: ContactListComponent}

也可以写成:

 { path: 'contacts',pathMatch: 'prefix', component: ContactListComponent}

patchMath属性指定匹配策略。 在这种情况下,它的前缀是默认值。

第二个匹配策略是的。 当为路由指定时,路由器将检查该路径是否与当前浏览器 URL 的路径完全相同:

 { path: 'contacts',pathMatch: 'full', component: ContactListComponent}

路由参数

使用参数创建路由是 Web 应用程序中的常见功能。 Angular Router 允许您以不同的方式访问参数:

  • 使用 ActivatedRoute 服务,
  • 使用从 v4 开始可用的 ParamMap observable。

您可以使用冒号语法创建路由参数。 这是一个带有id参数的示例路由:

 { path: 'contacts/:id', component: ContactDetailComponent}

路线守卫

路由保护是 Angular 路由器的一项功能,它允许开发人员在请求路由时运行一些逻辑,并基于该逻辑,它允许或拒绝用户访问该路由。 它通常用于检查用户是否已登录并获得授权,然后才能访问页面。

您可以通过实现@angular/router包中可用的CanActivate接口来添加路由保护,并扩展canActivate()方法,该方法包含允许或拒绝访问路由的逻辑。 例如,以下守卫将始终允许访问路由:

 class MyGuard implements CanActivate { canActivate() { return true; } }

然后,您可以使用canActivate属性使用警卫保护路由:

 { path: 'contacts/:id, canActivate:[MyGuard], component: ContactDetailComponent}

导航指令

Angular 路由器提供了routerLink指令来创建导航链接。 该指令采用与要导航到的组件关联的路径。 例如:

 <a [routerLink]="'/contacts'">Contacts</a>

多个网点和辅助路线

Angular Router 在同一个应用程序中支持多个出口。

一个组件有一个关联的主路由,并且可以有辅助路由。 辅助路线使开发人员能够同时导航多条路线。

要创建辅助路由,您需要一个命名的路由器出口,其中将显示与辅助路由关联的组件。

 <router-outlet></router-outlet> <router-outlet name="outlet1"></router-outlet>
  • 没有名字的出口是主要出口。
  • 除主要出口外,所有出口都应有名称。

然后,您可以使用 outlet 属性指定要在其中呈现组件的出口:

 { path: "contacts", component: ContactListComponent, outlet: "outlet1" }

创建一个 Angular 7 演示项目

在本节中,我们将看到一个如何设置和使用 Angular 路由器的实际示例。 您可以看到我们将要创建的现场演示以及该项目的 GitHub 存储库。

安装 Angular CLI v7

Angular CLI 需要Node 8.9+NPM 5.5.1+ 。 您需要确保在系统上安装了这些要求,然后运行以下命令来安装最新版本的 Angular CLI:

 $ npm install -g @angular/cli

这将全局安装 Angular CLI。

安装 Angular CLI v7
安装 Angular CLI v7(大预览)

注意您可能希望使用sudo全局安装软件包,具体取决于您的 npm 配置。

创建一个 Angular 7 项目

创建一个新项目是一个命令,您只需要运行以下命令:

 $ ng new angular7-router-demo

CLI 将询问您是否要添加路由(输入N表示否,因为我们将看到如何手动添加路由)以及您要使用哪种样式表格式,选择 CSS,第一个选项然后Enter 。 CLI 将创建一个包含必要文件的文件夹结构并安装项目所需的依赖项。

创建虚假的后端服务

由于我们没有真正的后端进行交互,我们将使用angular-in-memory-web-api库创建一个假后端,该库是一个用于 Angular 演示和测试的内存中 Web API通过 REST API 模拟 CRUD 操作。

它通过拦截发送到远程服务器的HttpClient请求并将它们重定向到我们需要创建的本地内存数据存储来工作。

要创建假后端,我们需要执行以下步骤:

  1. 首先,我们安装angular-in-memory-web-api模块,
  2. 接下来,我们创建一个返回虚假数据的服务,
  3. 最后,配置应用程序以使用假后端。

在您的终端中运行以下命令以从 npm 安装angular-in-memory-web-api模块:

 $ npm install --save angular-in-memory-web-api

接下来,使用以下命令生成后端服务:

 $ ng gs backend

打开src/app/backend.service.ts文件并从angular-in-memory-web-api模块导入InMemoryDbService

 import {InMemoryDbService} from 'angular-in-memory-web-api'

服务类需要实现InMemoryDbService然后重写createDb()方法:

 @Injectable({ providedIn: 'root' }) export class BackendService implements InMemoryDbService{ constructor() { } createDb(){ let contacts = [ { id: 1, name: 'Contact 1', email: '[email protected]' }, { id: 2, name: 'Contact 2', email: '[email protected]' }, { id: 3, name: 'Contact 3', email: '[email protected]' }, { id: 4, name: 'Contact 4', email: '[email protected]' } ]; return {contacts}; } }

我们只需创建一个联系人数组并返回它们。 每个联系人都应该有一个 id。

最后,我们只需要将InMemoryWebApiModule导入app.module.ts文件,并提供我们的假后端服务。

 import { InMemoryWebApiModule } from “angular-in-memory-web-api”; import { BackendService } from “./backend.service”; /* ... */ @NgModule({ declarations: [ /*...*/ ], imports: [ /*...*/ InMemoryWebApiModule.forRoot(BackendService) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

接下来创建一个ContactService ,它封装了用于处理联系人的代码:

 $ ng gs contact

打开src/app/contact.service.ts文件并将其更新为类似于以下代码:

 import { Injectable } from '@angular/core'; import { HttpClient } from “@angular/common/http”; @Injectable({ providedIn: 'root' }) export class ContactService { API_URL: string = "/api/"; constructor(private http: HttpClient) { } getContacts(){ return this.http.get(this.API_URL + 'contacts') } getContact(contactId){ return this.http.get(`${this.API_URL + 'contacts'}/${contactId}`) } }

我们添加了两种方法:

  • getContacts()
    用于获取所有联系人。
  • getContact()
    通过 id 获取联系人。

您可以将API_URL设置为任何 URL,因为我们不会使用真正的后端。 所有请求都将被拦截并发送到内存后端。

创建我们的 Angular 组件

在我们了解如何使用不同的路由器功能之前,让我们首先在我们的项目中创建一堆组件。

前往您的终端并运行以下命令:

 $ ng gc contact-list $ ng gc contact-detail

这将生成两个ContactListComponentContactDetailComponent组件并将它们添加到主应用程序模块中。

设置路由

在大多数情况下,您将使用 Angular CLI 创建带有路由设置的项目,但在这种情况下,我们将手动添加它,以便更好地了解路由在 Angular 中是如何工作的。

添加路由模块

我们需要添加AppRoutingModule ,它将包含我们的应用程序路由和一个路由器出口,Angular 将根据浏览器当前 URL 插入当前匹配的组件。

走着瞧:

  • 如何创建一个用于路由的 Angular 模块并导入它;
  • 如何为不同的组件添加路由;
  • 如何添加路由器插座。

首先,让我们首先在app-routing.module.ts文件中创建一个路由模块。 在src/app中使用以下命令创建文件:

 $ cd angular7-router-demo/src/app $ touch app-routing.module.ts

打开文件并添加以下代码:

 import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = []; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }

我们首先从@angular/core包中导入NgModule ,这是一个用于创建 Angular 模块的 TypeScript 装饰器。

我们还从@angular/router包中导入RouterModuleRoutes类。 RouterModule提供了像RouterModule.forRoot()这样的静态方法,用于将配置对象传递给路由器。

接下来,我们定义一个Routes类型的常量routes数组,用于保存每条路由的信息。

最后,我们创建并导出一个名为AppRoutingModule的模块(你可以随意调用它),它只是一个使用@NgModule装饰器装饰的 TypeScript 类,它接受一些元信息对象。 在这个对象的imports属性中,我们以 routes 数组作为参数调用静态RouterModule.forRoot(routes)方法。 在RouterModule exports

导入路由模块

接下来,我们需要将此模块路由导入到位于src/app/app.module.ts文件中的主应用程序模块中:

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

我们从./app-routing.module导入AppRoutingModule并将其添加到主模块的imports数组中。

添加路由器插座

最后,我们需要添加路由器插座。 打开包含主应用模板的src/app/app.component.html文件并添加<router-outlet>组件:

 <router-outlet></router-outlet>

这是 Angular 路由器渲染与当前浏览器路径对应的组件的地方。

这就是我们需要遵循的所有步骤,以便在 Angular 项目中手动设置路由。

创建路由

现在,让我们为我们的两个组件添加路由。 打开src/app/app-routing.module.ts文件并将以下路由添加到routes数组:

 const routes: Routes = [ {path: 'contacts' , component: ContactListComponent}, {path: 'contact/:id' , component: ContactDetailComponent} ];

确保在路由模块中导入这两个组件:

 import { ContactListComponent } from './contact-list/contact-list.component'; import { ContactDetailComponent } from './contact-detail/contact-detail.component';

现在我们可以从/contactscontact/:id路径访问这两个组件。

添加导航链接

接下来让我们使用routerLink指令将导航链接添加到我们的应用模板。 打开src/app/app.component.html并在路由器插座顶部添加以下代码:

 <h2><a [routerLink] = "'/contacts'">Contacts</a></h2>

接下来我们需要在ContactListComponent中显示联系人列表。 打开src/app/contact-list.component.ts然后添加以下代码:

 import { Component, OnInit } from '@angular/core'; import { ContactService } from '../contact.service'; @Component({ selector: 'app-contact-list', templateUrl: './contact-list.component.html', styleUrls: ['./contact-list.component.css'] }) export class ContactListComponent implements OnInit { contacts: any[] = []; constructor(private contactService: ContactService) { } ngOnInit() { this.contactService.getContacts().subscribe((data : any[])=>{ console.log(data); this.contacts = data; }) } }

我们创建一个contacts数组来保存联系人。 接下来,我们注入ContactService并调用实例的getContacts()方法(在ngOnInit生命周期事件上)来获取联系人并将它们分配给contacts数组。

接下来打开src/app/contact-list/contact-list.component.html文件并添加:

 <table> <tr> <th>Name</th> <th>Email</th> <th>Actions</th> </tr> <tr *ngFor="let contact of contacts" > <td>{{ contact.name }}</td> <td>{{ contact.email }}</td> <td> <a [routerLink]="['/contact', contact.id]">Go to details</a> </td> </tr> </table>

我们遍历联系人并显示每个联系人的姓名和电子邮件。 我们还使用routerLink指令创建到每个联系人详细信息组件的链接。

这是组件的屏幕截图:

联系人列表
联系人列表(大预览)

当我们点击Go to details链接时,它会将我们带到ContactDetailsComponent 。 路由有一个id参数,让我们看看如何从我们的组件中访问它。

打开src/app/contact-detail/contact-detail.component.ts文件并将代码更改为类似于以下代码:

 import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ContactService } from '../contact.service'; @Component({ selector: 'app-contact-detail', templateUrl: './contact-detail.component.html', styleUrls: ['./contact-detail.component.css'] }) export class ContactDetailComponent implements OnInit { contact: any; constructor(private contactService: ContactService, private route: ActivatedRoute) { } ngOnInit() { this.route.paramMap.subscribe(params => { console.log(params.get('id')) this.contactService.getContact(params.get('id')).subscribe(c =>{ console.log(c); this.contact = c; }) }); } }

我们将ContactServiceActivatedRoute注入到组件中。 在ngOnInit()生命周期事件中,我们检索将从路由传递的id参数,并使用它来获取我们分配给contact对象的联系人详细信息。

打开src/app/contact-detail/contact-detail.component.html文件并添加:

 <h1> Contact # {{contact.id}}</h1> <p> Name: {{contact.name}} </p> <p> Email: {{contact.email}} </p> 
联系方式
联系方式(大预览)

当我们第一次从127.0.0.1:4200/访问我们的应用程序时,outlet 不会渲染任何组件,所以让我们通过将以下路由添加到 routes 数组来将空路径重定向到contacts路径:

 {path: '', pathMatch: 'full', redirectTo: 'contacts'}

我们想要匹配确切的空路径,这就是我们指定完整匹配策略的原因。

结论

在本教程中,我们了解了如何使用 Angular 路由器将路由和导航添加到我们的应用程序中。 我们已经看到了不同的概念,例如路由器出口、路由和路径,并且我们创建了一个演示来实际展示不同的概念。 您可以从此存储库访问代码。