一、Overview
Angular 入坑記錄的筆記第五篇,因為一直在加班的緣故拖了有一個多月,主要是介紹在 Angular 中如何配置路由,完成重定向以及引數傳遞,至于路由守衛、路由懶加載等“高級”特性,并不會在本篇文章中呈現
對應官方檔案地址:
- 路由與導航
配套代碼地址:angular-practice/src/router-tutorial
二、Contents
- Angular 從入坑到棄坑 - Angular 使用入門
- Angular 從入坑到挖坑 - 組件食用指南
- Angular 從入坑到挖坑 - 表單控制元件概覽
- Angular 從入坑到挖坑 - HTTP 請求概覽
- Angular 從入坑到挖坑 - Router 路由使用入門指北
三、Knowledge Graph

四、Step by Step
4.1、基礎概念
4.1.1、base url
在 Angular 應用中,框架會自動將 index.html 檔案中的 base url 配置作為組件、模板和模塊檔案的基礎路徑地址,默認的情況下 app 檔案夾是整個應用的根目錄,所以我們直接使用 index.html 中使用默認的 <base href='https://www.cnblogs.com/'> 即可
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>RouterTutorial</title>
<base href="https://www.cnblogs.com/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="https://www.cnblogs.com/danvic712/p/favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
4.1.2、路由的配置
在 Angular 專案中,系統的路由需要我們將一個 url 地址映射到一個展示的組件,因此需要手動的去設定 url 與組件之間的映射關系
因為我們在使用 Angular CLI 創建專案時,選擇了添加路由模組,因此我們可以直接在 app-routing.module.ts 檔案中完成路由的定義,最終我們定義的路由資訊,都會在根模塊中被引入到整個專案
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { PagenotfoundComponent } from './components/pagenotfound/pagenotfound.component';
import { NewsComponent } from './components/news/news.component';
import { ProductComponent } from './components/product/product.component';
// 配置路由資訊
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'news', component: NewsComponent },
{ path: 'product', component: ProductComponent },
{ path: '**', component: PagenotfoundComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule // 引入路由配置資訊
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

當定義好路由資訊后,我們需要在頁面上使用 <router-outlet> 標簽來告訴 Angular 在何處渲染出頁面,對于路由之間的跳轉,我們可以在 a 標簽上通過使用 RouterLink 指令來系結具體的路由來完成地址的跳轉
<div >
<a [routerLink]="[ '/news' ]" routerLinkActive="active">
<span>News</span>
</a>
<a [routerLink]="[ '/product' ]" routerLinkActive="active">
<span>Product</span>
</a>
</div>
<div >
<div >
<!-- 組件渲染的出口 -->
<router-outlet></router-outlet>
</div>
</div>
</div>
當然,如果你非要自己給自己找事,就是要用 a 標簽的 href 屬性進行跳轉,當然也是可以的,不過在后面涉及到相關框架的功能時就會顯得有點不辣么聰明的樣子了
4.1.3、重定向與通配地址
在普遍情況下,對于進入系統后的默認路徑,我們會選擇重定向到一個具體的地址上,這里我們在定義路由資訊時,定義了一個空路徑用來表示系統的默認地址,當用戶請求時,重定向到 /home 路徑上,因為只有完整的 url 地址匹配空字串時才應該進行重定向操作,所以這里需要指定匹配模式是全部匹配

const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: 'home', pathMatch: 'full' }
];
Angular 在決議路由時,是按照我們定義路由時的順序依次進行的,一旦匹配就會立即終止,因此,類似于 404 錯誤的這種通配的路由配置,因為可以匹配上每個 url 地址,所以應該在定義時放到最后
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'news', component: NewsComponent },
{ path: 'product', component: ProductComponent },
{ path: '**', component: PagenotfoundComponent },
];

從截圖中可以看到,當我們打開系統時,會自動跳轉到我們指定的 home 路徑,點擊選單按鈕后,則會加載對應的組件頁面
4.1.4、激活的路由
很多情況下,對于被選中的路由,我們可能會添加一個特定的樣式來進行提示用戶,因此,在我們定義 router-link 時,可以使用 routerLinkActive 屬性系結一個 css 的樣式類,當該鏈接對應的路由處于激活狀態時,則自動添加上指定的樣式類

4.2、路由間的引數傳遞
在進行路由跳轉時,很常見的一種使用情況是我們需要將某些資料作為引數傳遞到下一個頁面中,例如從串列中選擇點擊某一行資料,跳轉到對應的詳情頁面
常見的引數傳遞有如下的兩種方式
4.2.1、query 查詢引數傳遞
最常見的一種引數傳遞的方式,在需要跳轉的路由地址后面加上引數和對應的值,在跳轉后的頁面通過獲取引數 key 從而獲取到對應的引數值
<a href="https://www.cnblogs.com/danvic712/p/www.yoursite.com/product?productId=xxxx">跳轉</a>
對于直接通過 a 標簽進行的路由跳轉,我們可以在 a 標簽上通過系結 queryParams 屬性來添加查詢引數資訊
這里通過 queryParams 屬性系結的是一個物件,Angular 會自動的幫我們將這個引數物件與 url 進行拼接,對于引數物件中的屬性(key)對應的屬性值(value),我們可以系結一個組件中的屬性進行動態的賦值,也可以通過添加單引號將引數值作為一個固定的數值,例如在下面代碼中的兩個查詢引數就是固定的值
<a [routerLink]="[ '/news' ]" routerLinkActive="active" [queryParams]="{category:'social',date:'2020-05-02'}">News</a>

同樣的,我們也可以在 js 中完成路由的跳轉,對于這種使用場景,我們需要在進行 js 跳轉的組件類中通過建構式依賴注入 Router 類,之后通過 Router 類的 navigate 方法完成路由的跳轉;對于可能存在的查詢引數,我們需要定義一個 NavigationExtras 型別的變數來進行設定
import { Component, OnInit } from '@angular/core';
// 引入路由模塊
import { Router, NavigationExtras } from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit(): void {}
/**
* 使用 js 的方式通過 query 查詢字串的形式傳遞引數
*/
queryNavigate() {
// 查詢引數
let query: NavigationExtras = {
queryParams: {
category: 'social',
date: '2020-05-04'
}
};
this.router.navigate(['/news' ], query);
}
}
既然在進行跳轉時附加了引數資訊,在跳轉后的頁面我們肯定需要獲取到傳遞的引數值,在 Angular 中,需要在組件類中依賴注入 ActivatedRoute 來獲取傳遞的引數資訊
這里的 queryParamMap 是一個 Observable 物件,所以這里需要使用 subscribe 方法來獲取傳遞的引數值
import { Component, OnInit } from '@angular/core';
// 引入路由模塊
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
this.route.queryParamMap.subscribe((data: any) => {
console.log(data.params);
});
}
}

4.2.2、動態路由傳遞
與使用查詢引數不同,使用動態路由進行引數傳值時,需要我們在定義路由時就提供引數的占位符資訊,例如在下面定義路由的代碼里,對于組件所需的引數 newsId,我們需要在定義路由時就指明
const routes: Routes = [
{ path: 'news/detail/:newsId', component: NewsDetailComponent },
];
對于采用動態路由進行的路由跳轉,在 a 標簽系結的 routerLink 屬性陣列的第二個資料中,需要指定我們傳遞的引數值,例如這里的 item.newsId 變數就是我們需要傳遞的引數值
<ul>
<li *ngFor="let item of newsList; let i = index">
<a [routerLink]="['/news/detail', item.newsId]" routerLinkActive="active" >
{{item.title}}
</a>
</li>
</ul>
而采用 js 的方式進行跳轉時,我們同樣需要使用依賴注入的方式注入 Router 類,然后呼叫 navigate 方法進行跳轉,與使用 query 查詢引數傳遞資料不同,此時需要將跳轉的鏈接與對應的引數值組合成為一個陣列引數進行傳遞
import { Component, OnInit } from '@angular/core';
// 引入路由模塊
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit {
newsList: any;
constructor(private route: ActivatedRoute, private router: Router) {
this.newsList = [{
newsId: 1111,
title: 'lalalalalallaaa'
}, {
newsId: 2222,
title: 'lalalalalallaaa'
}, {
newsId: 3333,
title: 'lalalalalallaaa'
}];
}
ngOnInit(): void {
this.route.queryParamMap.subscribe((data: any) => {
console.log(data.params);
});
}
routerNavigate() {
this.router.navigate(['/news/detail', 11111]);
}
}
在獲取引數資料的組件類中,需要依賴注入 ActivatedRoute 類,因為是采用的動態路由的方式進行的引數傳遞,這里需要通過 paramMap 屬性獲取到對應的引數值
import { Component, OnInit } from '@angular/core';
// 引入路由模塊
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-news-detail',
templateUrl: './news-detail.component.html',
styleUrls: ['./news-detail.component.scss']
})
export class NewsDetailComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
this.route.paramMap.subscribe((data: any) => {
console.log(data.params);
});
}
}

4.3、嵌套路由
在一些情況下,路由是存在嵌套關系的,例如下面這個頁面,只有當我們點擊資源這個頂部的選單后,它才會顯示出左側的這些選單,也就是說這個頁面左側的選單的父級選單是頂部的資源選單

針對這種具有嵌套關系的路由,在定義路由時,我們需要通過配置 children 屬性來指定路由之間的嵌套關系,例如這里我定義 ProductDetailComponent 這個組件和 ProductComponent 組件形成的路由之間具有嵌套關系
// 配置路由資訊
const routes: Routes = [
{
path: 'product', component: ProductComponent, children: [{
path: 'detail', component: ProductDetailComponent
}, {
path: '', redirectTo: 'detail', pathMatch: 'full'
}]
}
];
因為子路由的渲染出口是在父路由的頁面上,因此當嵌套路由配置完成之后,在嵌套的父級頁面上,我們需要定義一個 <router-outlet> 標簽用來指定子路由的渲染出口,最終的效果如下圖所示
<h3>我是父路由頁面顯示的內容</h3>
<p>product works!</p>
<!-- 加載子路由的資料 -->
<h3>子路由組件渲染的出口</h3>
<router-outlet></router-outlet>

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/93735.html
標籤:JavaScript
上一篇:作用域
