详解Angular路由之路由守卫


Posted in Javascript onMay 10, 2018

一、路由守卫

当用户满足一定条件才被允许进入或者离开一个路由。

路由守卫场景:

只有当用户登录并拥有某些权限的时候才能进入某些路由。

一个由多个表单组成的向导,例如注册流程,用户只有在当前路由的组件中填写了满足要求的信息才可以导航到下一个路由。

当用户未执行保存操作而试图离开当前导航时提醒用户。

Angular提供了一些钩子帮助控制进入或离开路由。这些钩子就是路由守卫,可以通过这些钩子实现上面场景。

  1. CanActivate: 处理导航到某路由的情况。
  2. CanDeactivate: 处理从当前路由离开的情况。
  3. 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: '', redirectTo : 'home',pathMatch:'full' }, 
 { path: 'chat', component: ChatComponent, outlet: "aux"},//辅助路由
 { path: 'home', component: HomeComponent },
 { path: 'product/:id', component: ProductComponent, children:[
  { path: '', component : ProductDescComponent },
  { path: 'seller/:id', component : SellerInfoComponent }
 ] ,canActivate: [LoginGuard]},
 { path: '**', component: Code404Component }
];

效果:点商品详情链接控制台会提醒用户未登录,不能进入商品详情路由。

详解Angular路由之路由守卫

三、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('你还没有保存,确定要离开吗?');
  }
}

配置路由,同样先加到provider,再配置路由。

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

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

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

效果:

点ok离开当前页面,cancel留在当前页面。

详解Angular路由之路由守卫

四、Resolve守卫

http请求数据返回有延迟,导致模版无法立刻显示。

数据返回之前模版上所有需要用插值表达式显示某个controller的值的地方都是空的。用户体验不好。

resolve解决办法:在进入路由之前去服务器读数据,把需要的数据都读好以后,带着这些数据进到路由里,立刻就把数据显示出来。

实例:

在进入商品信息路由之前,准备好商品信息再进入路由。 拿不到信息,或者拿信息出问题了,直接跳到错误信息页面,或者弹出提示,就不再进入目标路由。

先在product.component.ts中声明商品信息类型。

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

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

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

在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 '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { ProductComponent } from './product/product.component';
import { Code404Component } from './code404/code404.component';
import { ProductDescComponent } from './product-desc/product-desc.component';
import { SellerInfoComponent } from './seller-info/seller-info.component';
import { ChatComponent } from './chat/chat.component';
import { LoginGuard } from './guard/login.guard';
import { UnsaveGuard } from './guard/unsave.guard';
import { ProductResolve } from './guard/product.resolve';

const routes: Routes = [
 { path: '', redirectTo : 'home',pathMatch:'full' }, 
 { path: 'chat', component: ChatComponent, outlet: "aux"},//辅助路由
 { path: 'home', component: HomeComponent },
 { path: 'product/:id', component: ProductComponent, children:[
  { path: '', component : ProductDescComponent },
  { path: 'seller/:id', component : SellerInfoComponent }
 ] ,
  // canActivate: [LoginGuard],
  // canDeactivate: [UnsaveGuard],
  resolve:{ //resolve是一个对象
   product : ProductResolve  //想传入product,product由ProductResolve生成
  }},
 { path: '**', 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 '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';

@Component({
 selector: 'app-product',
 templateUrl: './product.component.html',
 styleUrls: ['./product.component.css']
})
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]="['./']">商品描述</a>
 <a [routerLink]="['./seller',99]">销售员信息</a>
 <router-outlet></router-outlet>
</div>

效果:

点商品详情链接,传入商品ID为2,在resolve守卫中是正确id,会返回一条商品数据。

点商品详情按钮,传入商品ID是3,是错误id,会直接跳转到主页。

详解Angular路由之路由守卫

详解Angular路由之路由守卫

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 字符编码规则
May 04 Javascript
jQuery设置div一直在页面顶部显示的方法
Oct 24 Javascript
JS获取图片高度宽度的方法分享
Apr 17 Javascript
javascript字符串与数组转换汇总
May 26 Javascript
js实现数组转换成json
Jun 26 Javascript
大型JavaScript应用程序架构设计模式
Jun 29 Javascript
AngularJS基础 ng-mouseover 指令简单示例
Aug 02 Javascript
基于js实现checkbox批量选中操作
Nov 22 Javascript
JavaScript编程设计模式之观察者模式(Observer Pattern)实例详解
Oct 25 Javascript
async/await优雅的错误处理方法总结
Jan 30 Javascript
详解JS实现简单的时分秒倒计时代码
Apr 25 Javascript
JS端基于download.js实现图片、视频时直接下载而不是打开预览
May 09 Javascript
JavaScript实现一个简易的计算器实例代码
May 10 #Javascript
浅谈node.js 命令行工具(cli)
May 10 #Javascript
Js经典案例的实例代码
May 10 #Javascript
Vue使用vux-ui自定义表单验证遇到的问题及解决方法
May 10 #Javascript
vuex与组件联合使用的方法
May 10 #Javascript
vue项目中公用footer组件底部位置的适配问题
May 10 #Javascript
解决vue 按钮多次点击重复提交数据问题
May 10 #Javascript
You might like
简单介绍下 PHP5 中引入的 MYSQLI的用途
2007/03/19 PHP
Yii2框架实现数据库常用操作总结
2017/02/08 PHP
Laravel中9个不经常用的小技巧汇总
2019/04/16 PHP
ie 处理 gif动画 的onload 事件的一个 bug
2007/04/12 Javascript
Highslide.js是一款基于js实现的网页中图片展示插件
2020/03/30 Javascript
jquery实现的超出屏幕时把固定层变为定位层的代码
2010/02/23 Javascript
jquery中dom操作和事件的实例学习 仿yahoo邮箱登录框的提示效果
2011/11/30 Javascript
div浮层,滚动条移动,位置保持不变的4种方法汇总
2013/12/11 Javascript
JS实现网页上随机产生超链接地址的方法
2015/11/09 Javascript
Bootstrap每天必学之按钮
2015/11/26 Javascript
js实现遍历含有input的table实例
2015/12/07 Javascript
基于JS实现的笛卡尔乘积之商品发布
2016/05/13 Javascript
关于angularJs指令的Scope(作用域)介绍
2016/10/25 Javascript
轻松理解JavaScript之AJAX
2017/03/15 Javascript
vue.js移动数组位置,同时更新视图的方法
2018/03/08 Javascript
node.js中TCP Socket多进程间的消息推送示例详解
2018/07/10 Javascript
微信小程序 函数防抖 解决重复点击消耗性能问题实现代码
2019/09/12 Javascript
Javascript执行流程细节原理解析
2020/05/14 Javascript
原生js实现九宫格拖拽换位
2021/01/26 Javascript
python中将字典形式的数据循环插入Excel
2018/01/16 Python
Python删除n行后的其他行方法
2019/01/28 Python
Python 内置变量和函数的查看及说明介绍
2019/12/25 Python
python基于celery实现异步任务周期任务定时任务
2019/12/30 Python
Python读取文件内容为字符串的方法(多种方法详解)
2020/03/04 Python
python数据类型可变不可变知识点总结
2020/03/06 Python
python框架flask入门之路由及简单实现方法
2020/06/07 Python
python包的导入方式总结
2021/03/02 Python
西班牙拥有最佳品牌的动物商店:Animalear.com
2018/01/05 全球购物
香港现代设计家具品牌:Ziinlife Furniture
2018/11/13 全球购物
继承公证书
2014/04/09 职场文书
执法作风整顿剖析材料
2014/10/11 职场文书
领导干部作风建设总结
2014/10/23 职场文书
2015年秋学期教研工作总结
2015/10/14 职场文书
python flappy bird小游戏分步实现流程
2022/02/15 Python
面试中老生常谈的MySQL问答集锦夯实基础
2022/03/13 MySQL
python读取mat文件生成h5文件的实现
2022/07/15 Python