首頁  >  文章  >  web前端  >  詳解Angular中的路由守衛

詳解Angular中的路由守衛

青灯夜游
青灯夜游轉載
2021-02-19 17:52:111845瀏覽

本篇文章跟大家介紹一下Angular路由中的路由守衛。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

詳解Angular中的路由守衛

相關推薦:《angular教學

一、路由守衛

當使用者滿足一定條件才被允許進入離開一個路由。

路由守衛場景:

只有當使用者登入並擁有某些權限的時候才能進入某些路由。

一個由多個表單組成的嚮導,例如註冊流程,使用者只有在目前路由的元件中填寫了滿足要求的資訊才可以導航到下一個路由。

當使用者未執行儲存操作而試圖離開目前導覽時提醒使用者。

Angular提供了一些鉤子幫助控制進入或離開路由。這些鉤子就是路由守衛,可以透過這些鉤子實現上面場景。

  • CanActivate: 處理導覽到某路由的情況。
  • CanDeactivate: 處理從目前路由離開的情況。
  • Resolve: 在路由啟動之前取得路由資料。

設定路由時候用到一些屬性,path, component, outlet, children, 路由守衛也是路由屬性。

二、CanActivate

實例:只讓登入使用者進入產品資訊路由。

新guard目錄。目錄下新建login.guard.ts。

LoginGuard類別實作CanActivate接口,傳回true或false,Angular根據回傳值判斷請求通過或不通過。 

import { CanActivate } from "@angular/router";

export class LoginGuard implements CanActivate{
    canActivate(){
        let loggedIn :boolean= Math.random()<0.5;
        if(!loggedIn){
            console.log("用户未登录");
        }
        return loggedIn;
    }
}

設定product路由。先把LoginGuard加入providers,在指定路由守衛。

canActivate可以指定多個守衛,值是一個陣列。

const routes: Routes = [
  { path: &#39;&#39;, redirectTo : &#39;home&#39;,pathMatch:&#39;full&#39; }, 
  { path: &#39;chat&#39;, component: ChatComponent, outlet: "aux"},//辅助路由
  { path: &#39;home&#39;, component: HomeComponent },
  { path: &#39;product/:id&#39;, component: ProductComponent, children:[
    { path: &#39;&#39;, component : ProductDescComponent },
    { path: &#39;seller/:id&#39;, component : SellerInfoComponent }
  ] ,canActivate: [LoginGuard]},
  { path: &#39;**&#39;, component: Code404Component }
];

效果:點商品詳情連結控制台會提醒使用者未登錄,無法進入商品詳情路由。

三、CanDeactivate

#離開時候的路由守衛。提醒使用者執行儲存操作後才能離開。 

在guard目錄下新建一個unsave.guard.ts的檔案。

CanDeactivate介面有一個範式,指定目前元件的類型。

CanDeactivate方法第一個參數是介面指定的範式類型的元件,根據這個要保護的元件的狀態,或是呼叫方法來決定使用者是否能夠離開。

import { CanDeactivate } from "@angular/router";
import { ProductComponent } from "../product/product.component";

export class UnsaveGuard implements CanDeactivate<ProductComponent>{
    //第一个参数 范型类型的组件
    //根据当前要保护组件 的状态 判断当前用户是否能够离开
    canDeactivate(component: ProductComponent){
        return window.confirm(&#39;你还没有保存,确定要离开吗?&#39;);
    }
}

設定路由,同樣先加到provider,再設定路由。

import { NgModule } from &#39;@angular/core&#39;;
import { Routes, RouterModule } from &#39;@angular/router&#39;;
import { HomeComponent } from &#39;./home/home.component&#39;;
import { ProductComponent } from &#39;./product/product.component&#39;;
import { Code404Component } from &#39;./code404/code404.component&#39;;
import { ProductDescComponent } from &#39;./product-desc/product-desc.component&#39;;
import { SellerInfoComponent } from &#39;./seller-info/seller-info.component&#39;;
import { ChatComponent } from &#39;./chat/chat.component&#39;;
import { LoginGuard } from &#39;./guard/login.guard&#39;;
import { UnsaveGuard } from &#39;./guard/unsave.guard&#39;;

const routes: Routes = [
  { path: &#39;&#39;, redirectTo : &#39;home&#39;,pathMatch:&#39;full&#39; }, 
  { path: &#39;chat&#39;, component: ChatComponent, outlet: "aux"},//辅助路由
  { path: &#39;home&#39;, component: HomeComponent },
  { path: &#39;product/:id&#39;, component: ProductComponent, children:[
    { path: &#39;&#39;, component : ProductDescComponent },
    { path: &#39;seller/:id&#39;, component : SellerInfoComponent }
  ] ,canActivate: [LoginGuard],
     canDeactivate: [UnsaveGuard]},
  { path: &#39;**&#39;, component: Code404Component }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [LoginGuard,UnsaveGuard]
})
export class AppRoutingModule { }

效果:

點ok離開目前頁面,cancel留在目前頁面。

四、Resolve守衛

#http要求資料回傳有延遲,導致模版無法立刻顯示。

資料傳回之前模版上所有需要用插值表達式顯示某個controller的值的地方都是空的。用戶體驗不好。

resolve解決方法:在進入路由之前去伺服器讀數據,把需要的數據都讀好以後,帶著這些數據進到路由裡,立刻就把數據顯示出來。

實例:

在進入商品資訊路由之前,準備好商品資訊再進入路由。 拿不到訊息,或是拿訊息出問題了,直接跳到錯誤訊息頁面,或是彈出提示,就不再進入目標路由。

先在product.component.ts中宣告商品資訊類型。

export class Product{
  constructor(public id:number, public name:string){
  }
}

在guard目錄下新建product.resolve.ts。 ProductResolve類別實作了Resolve介面。

Resolve也要宣告一個範式,範型就是resolve要解析出來的資料的型別。

import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router";

import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { Product } from "../product/product.component";

@Injectable()
export class ProductResolve implements Resolve<Product>{

    constructor(private router: Router) {
    }

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any {
        let productId: number = route.params["id"];
        if (productId == 2) { //正确id
            return new Product(1, "iPhone7");
        } else { //id不是1导航回首页
            this.router.navigate(["/home"]);
            return undefined;
        }
    }
}

路由配置:Provider裡聲明,product路由裡配置。

resolve是一個對象,對象裡參數的名字就是想傳入的參數的名字product,用ProductResolve來解析生成。

import { NgModule } from &#39;@angular/core&#39;;
import { Routes, RouterModule } from &#39;@angular/router&#39;;
import { HomeComponent } from &#39;./home/home.component&#39;;
import { ProductComponent } from &#39;./product/product.component&#39;;
import { Code404Component } from &#39;./code404/code404.component&#39;;
import { ProductDescComponent } from &#39;./product-desc/product-desc.component&#39;;
import { SellerInfoComponent } from &#39;./seller-info/seller-info.component&#39;;
import { ChatComponent } from &#39;./chat/chat.component&#39;;
import { LoginGuard } from &#39;./guard/login.guard&#39;;
import { UnsaveGuard } from &#39;./guard/unsave.guard&#39;;
import { ProductResolve } from &#39;./guard/product.resolve&#39;;

const routes: Routes = [
  { path: &#39;&#39;, redirectTo : &#39;home&#39;,pathMatch:&#39;full&#39; }, 
  { path: &#39;chat&#39;, component: ChatComponent, outlet: "aux"},//辅助路由
  { path: &#39;home&#39;, component: HomeComponent },
  { path: &#39;product/:id&#39;, component: ProductComponent, children:[
    { path: &#39;&#39;, component : ProductDescComponent },
    { path: &#39;seller/:id&#39;, component : SellerInfoComponent }
  ] ,
    //  canActivate: [LoginGuard],
    //  canDeactivate: [UnsaveGuard],
    resolve:{ //resolve是一个对象
      product : ProductResolve   //想传入product,product由ProductResolve生成
    }},
  { path: &#39;**&#39;, component: Code404Component }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [LoginGuard,UnsaveGuard,ProductResolve]
})
export class AppRoutingModule { }

修改一下product.component.ts 和模版,顯示商品id和name。

import { Component, OnInit } from &#39;@angular/core&#39;;
import { ActivatedRoute, Params } from &#39;@angular/router&#39;;

@Component({
  selector: &#39;app-product&#39;,
  templateUrl: &#39;./product.component.html&#39;,
  styleUrls: [&#39;./product.component.css&#39;]
})
export class ProductComponent implements OnInit {

  private productId: number;
  private productName: string;
  constructor(private routeInfo: ActivatedRoute) { }

  ngOnInit() {
    // this.routeInfo.params.subscribe((params: Params)=> this.productId=params["id"]);
    this.routeInfo.data.subscribe(
      (data:{product:Product})=>{
        this.productId=data.product.id;
        this.productName=data.product.name;
      }
    );
  }

}

export class Product{
  constructor(public id:number, public name:string){
  }
}
<div class="product">
  <p>
    这里是商品信息组件
  </p>
  <p>
    商品id是: {{productId}}
  </p>
  <p>
    商品名称是: {{productName}}
  </p>
  
  <a [routerLink]="[&#39;./&#39;]">商品描述</a>
  <a [routerLink]="[&#39;./seller&#39;,99]">销售员信息</a>
  <router-outlet></router-outlet>
</div>

效果:

點商品詳情鏈接,傳入商品ID為2,在resolve守衛中是正確id,會返回一條商品資料。

點商品詳情按鈕,傳入商品ID是3,是錯誤id,會直接跳到首頁。

本文轉載自:http://www.cnblogs.com/starof/p/9012193.html

#

更多程式相關知識,請造訪:程式設計影片! !

以上是詳解Angular中的路由守衛的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除