Angular 路由的完整指南
已发表: 2022-03-10如果您还不太熟悉 Angular 7,我想让您更接近这个令人印象深刻的前端框架所提供的一切。 我将引导您完成一个 Angular 演示应用程序,该应用程序显示与路由器相关的不同概念,例如:
- 路由器插座,
- 路线和路径,
- 导航。
我还将向您展示如何使用 Angular CLI v7 生成一个演示项目,我们将在其中使用 Angular 路由器来实现路由和导航。 但首先,请允许我向您介绍 Angular 并回顾其最新版本中的一些重要新功能。
介绍 Angular 7
Angular 是用于为移动和桌面 Web 构建客户端 Web 应用程序的最流行的前端框架之一。 它遵循基于组件的架构,其中每个组件都是独立且可重用的代码,用于控制应用程序 UI 的一部分。
Angular 中的组件是一个使用@Component
装饰器装饰的 TypeScript 类。 它有一个附加的模板和构成组件视图的 CSS 样式表。
Angular 7 是 Angular 的最新版本,最近发布了新功能,特别是在 CLI 工具和性能方面,例如:
- CLI 提示:像
ng add
和ng 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。
注意:您可能希望使用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
请求并将它们重定向到我们需要创建的本地内存数据存储来工作。
要创建假后端,我们需要执行以下步骤:
- 首先,我们安装
angular-in-memory-web-api
模块, - 接下来,我们创建一个返回虚假数据的服务,
- 最后,配置应用程序以使用假后端。
在您的终端中运行以下命令以从 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
这将生成两个ContactListComponent
和ContactDetailComponent
组件并将它们添加到主应用程序模块中。
设置路由
在大多数情况下,您将使用 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
包中导入RouterModule
和Routes
类。 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';
现在我们可以从/contacts
和contact/: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; }) }); } }
我们将ContactService
和ActivatedRoute
注入到组件中。 在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 路由器将路由和导航添加到我们的应用程序中。 我们已经看到了不同的概念,例如路由器出口、路由和路径,并且我们创建了一个演示来实际展示不同的概念。 您可以从此存储库访问代码。