--- tags: [angular] title: Router date: 2022-05-27 00:23:21 categories: FrontEnd --- ## **Angular 路由** 建立 component 之後,去 `/src/app/app-routing.module.ts` 引進 component ```tsx import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; // CLI imports AppRoutingModule import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent // 在這裡引入 *** components ], imports: [ BrowserModule, AppRoutingModule // CLI adds AppRoutingModule to the AppModule's imports array ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } ``` 在去 `/src/app/app-routing-modules.ts` 加上 routers ```tsx import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; // CLI imports router const routes: Routes = []; // sets up routes constant where you define your routes // configures NgModule imports and exports @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } ``` ```tsx const routes: Routes = [ { path: 'first-component', component: FirstComponent }, { path: 'second-component', component: SecondComponent }, ]; // <a routerLink="/first-component"></a> // RouterLinkActive => 這個是用來作什麼的?? ``` ## 轉址 ### HTML5 URLs and the `<base href>` The guidelines that follow will refer to different parts of a URL. This diagram outlines what those parts refer to: ``` foo://example.com:8042/over/there?name=ferret#nose \_/ \______________/\_________/ \_________/ \__/ | | | | | scheme authority path query fragment ``` ### template 寫法 ```html <a [routerLink]="['products']" [queryParams]="{ id: 101 }">Prodcuts</a> <a routerLink="products" [queryParams]="{ id: 101 }">Prodcuts</a> <a [routerLink]="['market','GP11011']">Prodcuts</a> <!-- hash url: router_name#fragment_name --> <a [routerLink]="['router_name']" fragment="fragment_name"> ``` ### 用 function 轉跳網址 ```tsx import { Router } from '@angular/router' // constructor(private router: Router){} ``` ```tsx const routes: Routes = [ { path: 'group/:id/:categories', ... }]; // const routes: Routes = [ { path: 'group', ... }]; ``` ```tsx // /market/categories/group/516/led-light this.router.navigate(['group', 516, 'led-light']); // group;id=7 this.router.navigate(['group', { id:7 }]); // group?id=7 this.router.navigate(['group'], { queryParams: { id: 7 } }); // group#prodID this.router.navigate(['group'], { fragment: prodID }); ``` [Angular Router 教學 - Wayne's Talk](https://waynestalk.com/angular-router-tutorial/) [[功能介紹-15] Router進階介紹 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天](https://ithelp.ithome.com.tw/articles/10195347) [[Angular 深入淺出三十天] Day 25 - 路由總結(一) - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天](https://ithelp.ithome.com.tw/articles/10209035) ### 取得參數 ```tsx export class ProductsComponent implements OnInit { constructor(private route: ActivatedRoute) { } ngOnInit() { // 第一種方式(較推薦) this.route.queryParams.subscribe((queryParams) => { console.log(queryParams['id']); }); // 第二種方式 console.log(this.route.snapshot.queryParams['id']); } } ``` ## 延遲 Lazy Page 在網站一開始進來的時候,不把所有網站用到的資原全部載入,由 router 對應到的 module 各別載入 ### Create a feature module with routing Next, you’ll need a feature module with a component to route to. To make one, enter the following command in the terminal, where `customers` is the name of the feature module. The path for loading the `customers` feature modules is also `customers` because it is specified with the `--route` option: ```shell $ ng generate module customers --route customers --module app.module ``` This creates a `customers` folder having the new lazy-loadable feature module `CustomersModule` defined in the `customers.module.ts` file and the routing module `CustomersRoutingModule` defined in the `customers-routing.module.ts` file. The command automatically declares the `CustomersComponent` and imports `CustomersRoutingModule` inside the new feature module. Because the new module is meant to be lazy-loaded, the command does NOT add a reference to the new feature module in the application's root module file, `app.module.ts`. Instead, it adds the declared route, `customers` to the `routes` array declared in the module provided as the `--module` option. ```javascript const routes: Routes = [ { path: 'customers', loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule) } ]; ``` ## 路由守衛 ### 解決了什麼問題? 在 angular 中,路由守衛主要可以解決以下的問題 1. 對於用戶訪問頁面的權限能否進入(是否已經登錄?已經登錄的角色是否有權限?) 2. 在跳轉到組件之前獲取必須的數據 頁面時,提示用戶是否保存未提交的修改 3. 離開頁面時,提示用戶是否保存未提交的修改 Angular幾個路由模塊提供瞭如下的接口用於幫助我們解決上面的問題 1. CanActivate操作訪問處理系統跳轉到可以執行的地址:(判斷是否) 2. CanActivateChild 功能同 CanActivate,加點菜 3. CanDeactivate:使用處理從當前路由的情況(判斷是否存在未提交的信息) 4. CanLoad延遲加載的方式: 是否允許通過 在經過了路由守衛,通過添加路由守衛返回的值,從而達到路由控制的最終目的 1. true:導航繼續 2. false:導航欄,用戶跳轉停留在當前的頁面或者是到指定的頁面 3. UrlTree:取消當前的導航,並導航到路由守衛返回的這個UrlTree上(一個新的路由信息) ### 建立一個 guard 透過 `agnular CLI` 建立一個 `guard` 來實現路由守衛, ```shell $ ng g guard auth/auth ``` 在 router 建立一個路由守衛 ```javascript const routes: Routes = [ { path: 'crisis-center', component: CrisisListComponent, canActivate: [AuthGuard], // 添加针对当前路由的 canActivate 路由守卫 } ]; ``` ## matcher ```javascript export const UserRoutes: Routes = [ { path: 'users', component: UserComponent, children: [ { path: '', component: UserListComponent }, { matcher: ComplexUrlMatcher("id", /[0-9]+/), component: UserItemComponent }, ] } ]; @NgModule({ imports: [RouterModule.forChild(UserRoutes)], exports: [RouterModule] }) export class UserRoutingModule { } ``` ## directive router ### [RouterLink](https://angular.io/api/router/RouterLink) ### [RouterLinkActive](https://angular.io/api/router/RouterLinkActive) routerLinkActive則是用來設定若現在的網址與所設定的連結一致時,要加上去的Class名稱,也可以利用來判斷顯示的邏輯 ```javascript <a routerLink="/market/categories/note" #rla="routerLinkActive" routerLinkActive="active" > {{ rla.isActive ? 'isActive' : 'noActive' }} note </a> <a routerLink="/market/categories/book">book</a> ``` ### [RouterLinkWithHref](https://angular.io/api/router/RouterLinkWithHref) ### [RouterOutlet](https://angular.io/api/router/RouterOutlet) ## 你可能會遇到的問題 ------ ### *如果你重複使用 component 的話 觸發 events 的 subscribe 會經過很多的 event [Angular](https://angular.io/api/router/Event) [Angular框架中去监听路由的改变(Router中的events: Observable )](https://www.jianshu.com/p/de4479ce5b19) ```javascript this.router.events.subscribe((ev) => { // ev 是在 event 的觸發時會跑過很多的 event // 這個 if 是在判斷如果 event 是 ActivationStart 的時候 // 並且 component 同為 SupplierProductsPageComponent 時 unsubscribe if (ev instanceof ActivationStart && Object.is(ev?.snapshot?.component, SupplierProductsPageComponent)) { this.getDataSubscribe.unsubscribe(); } }); ``` ------ ### 在 parent 要拿到本頁的 component 情境說明,在 header 因為要透過頁面 router 的 data 來判斷資料顯示。但在此處的 route 是直向最外面的 `app.component` ,但真正想要拿到的東西是在 firstChild 裡面,所以透過 `while` 來取得最後一個 component ```javascript let current = this.route.firstChild; while (current.firstChild) { current = current.firstChild; } ``` > [ 注意 ] 如果是 lazy page 的話,中間會有一層 `component` 為 undefine ------ ## 參考文章 [**Router基礎介紹**](https://ithelp.ithome.com.tw/articles/10195346) [Angular Router Tutorial](https://www.codingame.com/playgrounds/8104/angular-router-tutorial) [Angular 使用Router Parameters 路由參數](https://matthung0807.blogspot.com/2019/06/angular-7-router-parameters.html) [Angular 延遲載入](https://jonny-huang.github.io/angular/training/11_angular_lazy_loading/) [Angular 从入坑到挖坑 - 路由守卫连连看](https://www.cnblogs.com/danvic712/p/getting-started-with-angular-route-guards.html) [詳解Angular中的路由守衛](https://tw511.com/a/01/26032.html)