啥时候会用到路由守卫?
- 该用户可能无权导航到目标组件。
- 可能用户得先登录(认证)。
- 在显示目标组件前,你可能得先获取某些数据。
- 在离开组件前,你可能要先保存修改。
- 你可能要询问用户:你是否要放弃本次更改,而不用保存它们?
路由守卫相关的接口
- 用CanActivate来处理导航到某路由的情况。 =》 进入路由的时候触发
- 用CanActivateChild来处理导航到某子路由的情况。 =》 进入路由的时候触发
- 用CanDeactivate来处理从当前路由离开的情况。 =》 离开路由的时候触发
- 用Resolve在路由激活之前获取路由数据。
- 用CanLoad来处理异步导航到某特性模块的情况。
接下来通过具体的实例介绍如何使用CanActivate,CanActivateChild,CanDeactivate😺
CanActivate与CanActivateChild
守卫可以用同步的方式返回一个布尔值。但在很多情况下,守卫无法用同步的方式给出答案。 守卫可能会向用户问一个问题、把更改保存到服务器,或者获取新数据,而这些都是异步操作。
因此,路由的守卫可以返回一个 Observable<boolean> 或 Promise<boolean>,并且路由器会等待这个可观察对象被解析为 true 或 false。 所以接下来的代码我们会用两个版本分别试验同步和异步的写法。
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate, CanActivateChild, Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { UserService } from '../../../../common/services/user.service';
@Injectable()
export class ExampleGuardService implements CanActivate, CanActivateChild {
// version1.0 异步版
public isBecomeUser$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null);
constructor(private router: Router, private userService: UserService) {
this.verifyAccess();
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.isBecomeUser$.filter(status => typeof status === 'boolean');
}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.isBecomeUser$.filter(status => typeof status === 'boolean');
}
private verifyAccess() {
// 这里是用来返回isBecomeUser$的值
// 如果它返回 true,导航过程会继续
// 如果它返回 false,导航过程就会终止,且用户留在原地。
// 守卫还可以告诉路由器导航到别处,这样也会取消当前的导航。要想在守卫中这么做,就要返回 false;
}
// version2.0 同步版
public canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
const data = next.data;
const {authName} = data;
if (authName) {
return this.checkAuth(authName);
}
return true;
}
public canActivateChild(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
// CanActivateChild 守卫和 CanActivate 守卫很像。 它们的区别在于,CanActivateChild 会在任何子路由被激活之前运。
// 所以他们的判断逻辑是相同的只是使用的地方不同。
// 如果要保护管理特性模块
防止它被非授权访问,还要保护这个特性模块内部的那些子路由
你可以使用canActivateChild
return this.canActivate(next, state);
}
public checkAuth(authName: string): boolean { // 判断是否可以进入页面的相关逻辑
const hasAuth = this.example.isAuth(authName);
if (hasAuth) {
return true;
}
this.router.navigate(['/403']);
return false;
}
}
// CanActivate, CanActivateChild如何分别在路由模块中进行使用
eg: 'CanActivate'
const routes: Routes = [
{
path: '',
component: ExampleComponent,
canActivate: [ExampleGuardService],
data: {
title: '测试',
},
},
];
eg: 'CanActivateChild'
// 同样把这个 ExampleGuardService
添加到“无组件的”管理路由(无组件路由:"分组路由,而不需要组件, 一个无组件的路由能让守卫子路由变得更容易"),
来同时保护它的所有子路由,而不是为每个路由单独添加这个 ExampleGuardService。
const routes: Routes = [
{
path: '',
component: ExampleComponent,
canActivateChild: [ExampleGuardService],
children: [
{
path: '',
component: ExampleChildComponent,
data: { title: 'test' },
pathMatch: 'full'
}]
},
];
CanDeactivate
应用场景: 处理未保存的更改,相当于在离开这个路由的时候触发组件中的相关判断逻辑
// ExampleDetailDeactivateGuard文件
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { ExampleComponent } from '../exampl/exampl.component';
@Injectable()
export class ExampleDetailDeactivateGuard implements CanDeactivate<ExampleComponent> {
public canDeactivate(
component: ExampleComponent,
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | boolean {
return component.canDeactivate(); // 离开当前路由时,相关的判断是否需要保存逻辑放到具体的组件中
}
}
// ExampleComponent文件
创建了一个 Guard,它将检查这个(任意)组件中是否有 "canDeactivate()" 函数。 ExampleComponent文件就会有这个方法。
但是该守卫并不需要知道ExampleComponent文件确认退出激活状态的详情。 它只需要检查该组件是否有一个 canDeactivate() 方法,并调用它。
这就让该守卫可以复用。
public canDeactivate(): Observable<boolean> | boolean {
// 此组件判断是否离开保存的相关逻辑
}
希望这篇关于Guard的文章可以对各位小哥哥,小姐姐带来些许的帮助哈 😄(▽)~~
网友评论