路由守卫
只有当用户已经登录并拥有某些权限时,才能进入某些路由。
一个由多个表单组成的向导,例如注册流程,用户只有在当前路由的组件中填写了满足要求的信息才可以导航到下一个路由。
当用户未执行保存操作,而试图离开当前导航时,提醒用户。
- CanActivate:处理导航到某路由的情况。
- CanDeactivate:处理当前路由离开的情况。
- Resolve:在路由激活之前获取路由数据。
下面编写一个伪代码示例
创建登录守卫
创建目录文件guard,在其下面创建login.guard.ts
import {CanActivate} from "@angular/router";
export class LoginGuard implements CanActivate {
canActivate() {
let loggedIn: boolean = Math.random() < 0.5;
if (!loggedIn) {
console.log("用户未登录");
}
return loggedIn;
}
}
我们模拟的是产生一个随机数,当小于0.5的时候显示,否则log
app-routing.module.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";
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},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers:[LoginGuard]
})
export class AppRoutingModule {
}
添加登录守卫canActivate:[LoginGuard]
,注意:我们在这里添加了路由守卫,但是这个canActivate在什么地方被初始化呢?Angular给我们一种依赖注入的方式,在以下的文章会介绍。在这我们只要做一件事,就是在@NgModule
的中填写providers:[LoginGuard]
接下来我们创建保存守卫在guard文件下创建unSave.guard.ts
import {ProductComponent} from "../product/product.component";
/**
* Created by mac on 2018/7/24.
*/
export class UnSaveGuard implements CanDeactivate<ProductComponent>{
canDeactivate(component:ProductComponent){
return window.confirm("你还没有保存,确定要离开嘛?");
}
}
resolve守卫
在实际开发中,我们会在ngOnInit
时,进行网络请求获取数据,展示给用户。但是一般数据没有及时返回的话,页面没有及时渲染,会有不好的用户体验,所以使用resolve守卫,在进行路由跳转之前,获取数据,并由守卫把获取到的数据传递到相应的页面中。
在guard文件目录下创建product.guard.ts
import {Resolve,ActivatedRouteSnapshot, RouterStateSnapshot,Router} from "@angular/router";
import {Observable} from "rxjs";
import {Product} from "../product/product.component";
import {Injectable} from "@angular/core";
@Injectable()
export class ProductResolve implements Resolve<Product> {
constructor(private router:Router){
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Product> | Promise<Product> | Product{
let productId: number = route.params["id"];
console.log(productId);
if (productId == 1) {
return new Product(1,"iPhone7");
}else {
this.router.navigate(['/home']);
}
}
}
这里的意思是:我传一个id为1的数据时,返回一个新的Product。new Product(1,"iPhone7");
如果不是就跳转到首页
product.component.ts
import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} 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;
}
);
//参数快照
// this.productId = this.routeInfo.snapshot.params["id"];
}
}
//声明此类
export class Product{
constructor(public id:number,public name:string){
}
}
此时我们获取的定义就不是params
了,而是data
product.component.html
<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>
在页面上接收显示productName
app-routing.module.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";
import {ProductResolve} from "./guard/product.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},
],resolve:{
product:ProductResolve
}
},
{path: '**', component: Code404Component},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers:[LoginGuard,UnSaveGuard,ProductResolve]
})
export class AppRoutingModule {
}
同时把守卫添加进去路由。
app.component.html
<a [routerLink]="['/home']">主页</a>
<!--<a [routerLink]="['/product']" [queryParams]="{id:1}">商品详情</a>-->
<a [routerLink]="['/product',1]">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">
<a [routerLink]="[{outlets:{primary:'home', aux:'chat'}}]">开始聊天</a>
<a [routerLink]="[{outlets:{aux: null}}]">结束聊天</a>
<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>
记得把参数改为1
当我点击商品详情的a标签时,传递参数1,返回productName为iPhone7的Product
当我点击商品详情按钮的时候,传递参数为3,直接跳转到首页