如何基于进度数组使用Ionic Auth Guard的canLoad限制页面访问?
嘿,这个需求完全可以用单个Auth Guard搞定!我来给你一步步拆解实现思路和代码:
解决方案
1. 给路由绑定进度索引
首先,在你的路由配置里,给每个课程页面的路由添加自定义data属性,把页面对应的progress数组索引存进去。这样单个Guard就能通过路由数据知道当前要访问的页面对应哪个进度节点:
const routes: Routes = [ { path: 'course', children: [ { path: 'page1', loadChildren: () => import('./pages/page1/page1.module').then(m => m.Page1Module), canLoad: [CourseProgressGuard], // 后面会定义这个Guard data: { requiredProgressIndex: 0 } // 对应progress[0] }, { path: 'page2', loadChildren: () => import('./pages/page2/page2.module').then(m => m.Page2Module), canLoad: [CourseProgressGuard], data: { requiredProgressIndex: 1 } // 对应progress[1] }, { path: 'page3', loadChildren: () => import('./pages/page3/page3.module').then(m => m.Page3Module), canLoad: [CourseProgressGuard], data: { requiredProgressIndex: 2 } // 对应progress[2] }, // 不管多少页面,都按这个模式添加就行 ] } ];
2. 全局管理进度状态(推荐)
把progress数组放在一个全局服务里,用Observable维护,这样进度变化时Guard能实时响应,也方便各个页面更新进度:
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ProgressService { // 用BehaviorSubject保存进度,初始值按你的需求设置 private progressSubject = new BehaviorSubject<boolean[]>([true, false, false]); progress$ = this.progressSubject.asObservable(); // 更新进度的方法,比如页面1结束时调用 updateProgress(newProgress: boolean[]) { this.progressSubject.next(newProgress); } }
3. 编写单个Auth Guard的canLoad逻辑
这个Guard会读取路由的requiredProgressIndex,对比当前用户的活跃进度,决定是否允许加载页面,不允许的话直接导航回当前应该在的页面:
import { Injectable } from '@angular/core'; import { CanLoad, Route, Router, UrlTree } from '@angular/router'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ProgressService } from './progress.service'; @Injectable({ providedIn: 'root' }) export class CourseProgressGuard implements CanLoad { constructor( private progressService: ProgressService, private router: Router ) {} canLoad(route: Route): Observable<boolean | UrlTree> { return this.progressService.progress$.pipe( map(progress => { // 找到当前用户所在的进度节点(数组中唯一为true的索引) const currentActiveIndex = progress.findIndex(isActive => isActive); // 获取要访问页面对应的进度索引 const targetIndex = route.data?.requiredProgressIndex; // 核心校验:只能访问当前活跃进度对应的页面 if (targetIndex === currentActiveIndex) { return true; // 允许加载页面 } else { // 尝试跳转时,导航回当前应该在的页面 const currentPagePath = `course/page${currentActiveIndex + 1}`; return this.router.parseUrl(currentPagePath); } }) ); } }
4. 在页面中更新进度
比如页面1结束时,调用服务的updateProgress方法切换进度:
// page1.component.ts import { ProgressService } from '../progress.service'; import { Router } from '@angular/router'; constructor( private progressService: ProgressService, private router: Router ) {} onPageComplete() { // 更新进度:页面1完成,切换到页面2的进度状态 this.progressService.updateProgress([false, true, false]); // 自动导航到页面2(也可以让用户手动点击,按需求选择) this.router.navigate(['/course/page2']); }
关键逻辑说明
- 复用性:不管你有多少个课程页面,只需要在路由里添加
canLoad: [CourseProgressGuard]和对应的requiredProgressIndex,Guard的逻辑完全不用修改。 - 拦截所有跳转:不管用户是通过导航链接、地址栏输入还是其他方式跳转,
canLoad都会拦截校验,确保只能访问当前进度对应的页面。 - 响应式更新:用Observable维护进度,进度变化时Guard会自动重新校验,保证状态一致。
内容的提问来源于stack exchange,提问作者Pine van Wageningen
相关产品推荐
相关产品推荐

