Angular4總結(二)—— 路由

路由知識總結

可以把SPA(single page application)理解爲是一個視圖狀態的集合。Angular架構下的各個視圖會因爲操作的不同顯示的也會各有千秋,這些功勞全都得歸功於路由。

基礎知識

路由相關的對象總結:

  1. Routes:路由配置,表示在哪個URL中會顯示哪個組件,還有就是在哪個RouterOutlet(像是一個插排一樣)中顯示組件。

    /**
     * Tips: path 不能使用斜槓進行開頭,因爲可以讓Angular自動使用絕對路徑和相對路徑。
     * 配置好路徑以及路徑對應的需要顯示的component。
     */
    const routes: Routes = [
      {path: '', component: HomeComponent},
      {path: 'products', component: ProductsComponent}
    ];
    
  1. RouterOutlet:在HTML標記路由內的佔位符指令。

    <router-outlet></router-outlet>
    
  1. Router:在運行時指定路由的行爲,通過navigate()以及navigateByURL()指定路由到哪個路由中去。

    //html模版上寫入一個點擊事件,通過事件,觸發clickProductButton事件。通過router實現路由。
    constructor(
        private router: Router
      ) {}
    public clickProductButton() {
      this.router.navigate(['/products']);
    }
    
  1. RouterLink:在HTML中聲明路由導航用的指令。與Router相類似,只不過Router是在controller中使用的,而RouterLink在HTML中使用的。

    <!--必須加入斜槓,因爲這樣才能區分是跟路由,還是子路由-->
      <!--爲什麼 routerLink的值是一個數組呢,因爲可以通過路由傳入一些參數-->
      <a [routerLink]="['/']">主頁</a>
      <a [routerLink]="['/products']">商品詳情</a>
    
  1. ActivatedRoute:當前激活路由的相關信息,可以被這個類記錄,並且被我們使用。

如何在路由中傳遞數據

  1. 在查詢參數中傳遞數據

    多添加一個[queryParams]的屬性綁定形如:

     <a [routerLink]="['/products']" [queryParams]= "{id:1}">商品詳情</a>
    

    獲取:通過ActivatedRoute.queryParams[參數的key]

  2. 在路由路徑中傳遞數據

    • 修改Routes中的path屬性,形如:path:'product/:type'
    • routerLink中多添加一個參數,形如:[routerLink]="['/products','book']" ,這裏的book就是給我們剛剛定義type的值。

    獲取:通過 ActivatedRoute.params[參數的key]

  3. 在路由配置中傳遞數據

    通過在Routes中定義data參數 形如:

     {path: '', component: HomeComponent, data: [{key: value}]}
    

    然後通過ActivatedRoute.data[0] [key] 來獲取

Tips:參數快照與參數訂閱

首先上代碼:

    //參數訂閱
    this.activatedRoute.params.subscribe((params: Params) => {
        this.productType = params['type'];
    });
    //參數快照
    this.productType = this.activatedRoute.snapshot.params['type'];

他倆的區別就在於我們現在有兩個不同的按鈕,跳轉到的URL分別爲 [routerLink]="['/products','book']",和[routerLink]="['/products','watch']",可以看出它們只有type的參數類型不同。

如果使用了快照,點擊了第一個按鈕,在點擊第二個,那麼獲取到的參數不會發生變化,這個時候我們就應該使用參數訂閱(觀察者模式的思想,感興趣的可以查詢RXJS,進行詳細瞭解)。

重定向路由

在Routes中添加 對應參數:

{path: '', redirectTo: '/home', pathMatch: 'full'}

子路由

在正常的情況下,組件與組件之間一定是會有嵌套關係的,這種嵌套關係就會導致我們的路由插座(<router-outlet>)同樣也是嵌套的。子路由就是爲了解決路由插座父子嵌套關係的

使用子路由的步驟:

  1. 修改在Routes中,product的路由信息,主要就是添加了一個children屬性:

    {path: 'products/:type', component: ProductsComponent, children: [
        {path: '', component: ProductDescComponent},
        {path: 'seller/:id', component: SellerComponent}
      ]}
    
  2. 在需要子路由的html中,插上<router-outlet></router-outlet> 作爲插座

  3. 然後在需要跳轉的地方編寫如下代碼

    <a [routerLink] = "['./']">跳轉到商品詳情</a>
    <a [routerLink] = "['./seller', 99]">跳轉到售貨員信息</a>
    

輔助路由

剛剛的子路由如果說是父子關係的話,那麼輔助路由就是"兄弟關係了"。

這種場景出現在我們在一個界面中,兩個component分別被不同的路由機制管理着,如果只使用原來的<router-outlet>插槽,沒有辦法指定用的到底是哪一種路由策略,所以輔助路由就這麼誕生了。

使用輔助路由的步驟:

  1. 通過name 指定具體的路由插座名稱

    <router-outlet></router-outlet>

    <router-outlet name="aux"></router-outlet>

  2. 指定當前這個aux路由可以展示哪些component。

    {path: /xxx, component: XxxComponent, outlet: aux}

    {path: /yyy, component: YyyComponent, outlet: aux}

  3. 在進行導航的地方指定我們需要的那個路由

    <a [routerLink] ="[{outlets: {aux: 'xxx'}}]"></a>

    <a [routerLink] ="[{outlets: {aux: 'xxx'}}]"></a>

路由守衛

頁面從一種頁面狀態跳轉到另一種頁面狀態,有的時候需要一些條件,檢查這些條件就是路由守衛的職責。

一共可以分爲三種:

  1. CanActivate: 處理導航到某路由的情況

    大概的使用步驟:

    首先我們先要寫一個守衛的類:

    import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router";
    
    /**
     * 這個路由守衛用於實現進入某以頁面需要滿足某些需求的情況。
     */
    export class LoginGuard implements CanActivate {
        private flag = true;
        canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    
            //這裏給了一個隨機數,如果數字大於0.5則可以進行登陸,否則會被攔截
            this.flag = Math.random() > 0.5;
            if ( this.flag ) {
                console.log('可以登陸');
    
            }
            console.log(this.flag);
            return this.flag;
        }
    }
    
    

    然後將守衛的類添加到Routes中需要守衛的規則中:

    {path: 'products/:type', component: ProductsComponent, canActivate: [LoginGuard], children: [
        {path: '', component: ProductDescComponent},
        {path: 'seller/:id', component: SellerComponent}
      ]}
    

    最後在app.module.ts中添加自己需要依賴注入的守衛類即可:

    providers: [LoginGuard]
    
  2. CanDeactive: 處理從當前路由離開的情況

    大概的使用步驟:

    首先我們先要寫一個守衛的類:

    import { CanDeactivate, ActivatedRouteSnapshot } from "@angular/router";
    import { ProductsComponent } from "../products/products.component";
    
    export class NotSaveGuard implements CanDeactivate<ProductsComponent> {
        private flag = true;
        canDeactivate(component: ProductsComponent, _currentRoute: ActivatedRouteSnapshot) {
            
            //這裏暫時給出一個提示框
            return window.confirm("還沒有保存確定離開嗎?");
        }
    
    }
    
    
    

    然後將守衛的類添加到Routes中需要守衛的規則中:

    {path: 'products/:type', component: ProductsComponent, canDeActivate: [NotSaveGuard], children: [
        {path: '', component: ProductDescComponent},
        {path: 'seller/:id', component: SellerComponent}
      ]}
    

    最後在app.module.ts中添加自己需要依賴注入的守衛類即可:

    providers: [NotSaveGuard]
    
  3. Resolve:在路由激活之前獲取數據

    在進入路由之前檢測數據是不是已經存在,以爲網絡請求具有延遲,如果出現了,已經路由到下個界面,但是信息還沒有存在的情況,我們就會讓界面路由到錯誤界面或者別的什麼界面。

    大概的使用步驟:

    1.首先我們定義一個Resolve守衛的類:

    import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router";
    import { ProductsComponent, Product } from "../products/products.component";
    import { Injectable } from "@angular/core";
    
    @Injectable()
    export class ProductGuard implements Resolve<Product> {
    
    
        constructor(private router: Router) {
        }
    
        resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
            if (route.params['type'] === 'book') {
                return new Product(1, 'iphone X');
            } else {
                this.router.navigate(['/home']);
                return undefined;
            }
        }
    
    }
    
    

    2.然後將resolve屬性添加到守衛的規則中

    {path: 'products/:type', component: ProductsComponent, resolve: {product: ProductGuard}, children: [
        {path: '', component: ProductDescComponent},
        {path: 'seller/:id', component: SellerComponent}
      ]}
    

    3.依賴注入 ProductGuard

    providers: [ProductGuard]
    

    4.resolve 其實相當於對返回值的一種增強,接受返回值的地方我們應該這麼寫

    this.activatedRoute.data.subscribe((data: {product: Product}) => {
               //注意:這裏之所以可以使用data.product,是因爲我們在Routes路由中配置的 resolve: {product: ProductGuard}所致。這裏的product就是返回值的名字,如果變化了,兩個名字都要一起變化。
            this.productId = data.product.id;
            this.productName = data.product.name;
        });
    

最後附加上本文提及到的代碼,我已經放在github上,可供參考

https://github.com/luckypoison/Augular4Route

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章