详解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的变量作用域深入理解
Oct 25 Javascript
DIY jquery plugin - tabs标签切换实现代码
Dec 11 Javascript
JavaScript获取图片的原始尺寸以宽度为例
May 04 Javascript
javascript写的异步加载js文件函数(支持数组传参)
Jun 07 Javascript
浅析Javascript中“==”与“===”的区别
Dec 23 Javascript
jQuery实现类似老虎机滚动抽奖效果
Aug 06 Javascript
jQuery ajax请求struts action实现异步刷新
Apr 19 jQuery
zTree 树插件实现全国五级地区点击后加载的示例
Feb 05 Javascript
vue-cli项目优化方法- 缩短首屏加载时间
Apr 01 Javascript
微信小程序模板template简单用法示例
Dec 04 Javascript
关于layui 弹出层一闪而过就消失的解决方法
Sep 09 Javascript
解决vue组件销毁之后计时器继续执行的问题
Jul 21 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
PHP爆绝对路径方法收集整理
2012/09/17 PHP
php中json_encode处理gbk与gb2312中文乱码问题的解决方法
2014/07/10 PHP
php使用Jpgraph绘制饼状图的方法
2015/06/10 PHP
手把手编写PHP框架 深入了解MVC运行流程
2016/09/19 PHP
PHP回调函数概念与用法实例分析
2017/11/03 PHP
PHP+jQuery实现即点即改功能示例
2019/02/21 PHP
laravel 实现上传图片到本地和前台访问示例
2019/10/21 PHP
Bootstrap 布局组件(全)
2016/07/18 Javascript
js图片加载效果实例代码(延迟加载+瀑布流加载)
2017/05/12 Javascript
jQuery实现页码跳转式动态数据分页
2017/12/31 jQuery
解决Mac下安装nmp的淘宝镜像失败问题
2018/05/16 Javascript
JS中‘hello’与new String(‘hello’)引出的问题详解
2018/08/14 Javascript
JavaScript惰性求值的一种实现方法示例
2019/01/11 Javascript
vue实现多组关键词对应高亮显示功能
2019/07/25 Javascript
5分钟快速看懂ES6中的反射与代理
2019/12/19 Javascript
用Python的urllib库提交WEB表单
2009/02/24 Python
qpython3 读取安卓lastpass Cookies
2016/06/19 Python
python3读取csv和xlsx文件的实例
2018/06/22 Python
python sort、sort_index方法代码实例
2019/03/28 Python
Django实现auth模块下的登录注册与注销功能
2019/10/10 Python
python matplotlib折线图样式实现过程
2019/11/04 Python
记一次pyinstaller打包pygame项目为exe的过程(带图片)
2020/03/02 Python
python+opencv实现移动侦测(帧差法)
2020/03/20 Python
Anaconda和ipython环境适配的实现
2020/04/22 Python
解决Python3.8运行tornado项目报NotImplementedError错误
2020/09/02 Python
Europcar葡萄牙:葡萄牙汽车和货车租赁
2017/10/13 全球购物
奇怪的鱼:Weird Fish
2018/03/18 全球购物
卡骆驰新加坡官网:Crocs新加坡
2018/06/12 全球购物
Paradox London官方网站:英国新娘鞋婚礼鞋品牌
2019/08/29 全球购物
机电专业个人求职信范文
2013/12/30 职场文书
政治表现评语
2014/05/04 职场文书
儿童生日会策划方案
2014/05/15 职场文书
科技工作者先进事迹
2014/08/16 职场文书
2014乡镇班子个人对照检查材料思想汇报
2014/09/26 职场文书
酒桌上的开场白
2015/06/01 职场文书
基于redis+lua进行限流的方法
2022/07/23 Redis