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 路由器將路由和導航添加到我們的應用程序中。 我們已經看到了不同的概念,例如路由器出口、路由和路徑,並且我們創建了一個演示來實際展示不同的概念。 您可以從此存儲庫訪問代碼。