鸿蒙开发:HMRouter封装教程(三)
在前两篇教程中,我们完成了 HMRouter 的类型封装工具类封装编译插件配置和测试页面搭建。本篇我们将深入探讨HMRouter Interceptor 拦截器的封装和使用。拦截器是 HMRouter 框架的核心功能之一,它允许你在路由跳转过程中进行拦截、验证、权限检查等操作,实现灵活的路由控制。权限验证:检查用户是否有权限访问目标页面登录检查:未登录用户自动跳转到登录页参数验证:验证路由参数的有
📖 前言
在前两篇教程中,我们完成了 HMRouter 的类型封装、工具类封装、编译插件配置和测试页面搭建。本篇我们将深入探讨 HMRouter Interceptor 拦截器的封装和使用。
拦截器是 HMRouter 框架的核心功能之一,它允许你在路由跳转过程中进行拦截、验证、权限检查等操作,实现灵活的路由控制。通过拦截器,我们可以实现:
- 权限验证:检查用户是否有权限访问目标页面
- 登录检查:未登录用户自动跳转到登录页
- 参数验证:验证路由参数的有效性
- 日志记录:记录路由跳转日志
- 性能监控:统计路由跳转耗时
🎯 拦截器封装目标
- ✅ 类型统一:封装拦截器相关类型,保持项目代码风格一致
- ✅ 简化使用:提供清晰的拦截器定义和使用示例
- ✅ 功能完整:支持同步和异步两种拦截器实现方式
- ✅ 易于维护:统一管理拦截器,便于后续扩展

📁 拦截器封装结构
entry/src/main/ets/hmRouter/
├── interceptor/ # 拦截器相关封装目录
│ ├── Index.ets # 统一导出入口
│ ├── HMRouterUtilInterceptor.ets # 拦截器接口类型别名
│ ├── HMRouterUtilInterceptorAction.ets # 拦截器动作枚举
│ ├── HMRouterUtilInterceptorInfo.ets # 拦截器信息类型别名
│ ├── HMRouterUtilInterceptorChain.ets # 拦截器链类型别名
│ ├── HMRouterUtilInterceptorContext.ets # 拦截器上下文类型别名
│ └── HMRouterUtilInterceptorParam.ets # 拦截器参数类型别名
└── interceptorInstance/ # 拦截器实例目录
├── Index.ets # 统一导出入口
└── HMRouterUtilTestInterceptor.ets # 拦截器示例实现
🚀 拦截器封装步骤
步骤 1:封装拦截器类型定义
1.1 封装拦截器接口
文件: interceptor/HMRouterUtilInterceptor.ets
import { IHMInterceptor } from '@hadss/hmrouter';
/**
* HMRouter 拦截器类型别名
* 用于项目内部统一使用,定义路由拦截器接口
*
* 支持两种实现方式:
* - 同步拦截器:实现 handle 方法
* - 异步拦截器:实现 intercept 方法
*
* 注意:至少需要实现 handle 或 intercept 方法中的一个
*/
export type HMRouterUtilInterceptor = IHMInterceptor;
说明:
- 拦截器必须实现
IHMInterceptor接口 - 可以只实现
handle方法(同步拦截器) - 可以只实现
intercept方法(异步拦截器) - 也可以同时实现两个方法(异步路由优先调用
intercept)
1.2 封装拦截器动作枚举
文件: interceptor/HMRouterUtilInterceptorAction.ets
import { HMInterceptorAction } from '@hadss/hmrouter';
/**
* HMRouter 拦截器动作枚举
* 用于同步拦截器控制路由流程
*/
export { HMInterceptorAction as HMRouterUtilInterceptorAction };
拦截器动作说明:
|
动作 |
说明 |
|
|
继续执行下一个拦截器 |
|
|
拦截当前路由操作,不执行后续拦截器和路由操作 |
|
|
拦截当前路由操作,但继续执行后续拦截器 |
1.3 封装拦截器信息类型
文件: interceptor/HMRouterUtilInterceptorInfo.ets
import { HMInterceptorInfo } from '@hadss/hmrouter';
/**
* HMRouter 拦截器信息类型别名
* 包含路由跳转的完整信息,用于拦截器判断和处理
*/
export type HMRouterUtilInterceptorInfo = HMInterceptorInfo;
HMInterceptorInfo 包含的信息:
sourceName:跳转发起页面名称targetName:目标页面名称param:路由参数navigationId:导航容器ID
1.4 封装拦截器链类型
文件: interceptor/HMRouterUtilInterceptorChain.ets
import { IHMInterceptorChain } from '@hadss/hmrouter';
/**
* HMRouter 拦截器链类型别名
* 用于异步拦截器控制路由流程
*/
export type HMRouterUtilInterceptorChain = IHMInterceptorChain;
拦截器链方法:
onContinue():继续执行下一个拦截器onReject():拦截当前路由操作getContext():获取拦截器上下文,用于共享数据
1.5 封装拦截器上下文类型
文件: interceptor/HMRouterUtilInterceptorContext.ets
import { InterceptorContext } from '@hadss/hmrouter';
/**
* HMRouter 拦截器上下文类型别名
* 用于拦截器之间共享数据
*/
export type HMRouterUtilInterceptorContext = InterceptorContext;
1.6 封装拦截器参数类型
文件: interceptor/HMRouterUtilInterceptorParam.ets
import { HMInterceptorParam } from '@hadss/hmrouter/src/main/ets/annotation/HMInterceptor';
/**
* HMRouter 拦截器参数类型别名
* 用于项目内部统一使用,定义拦截器配置参数
*
* 属性包括:
* - interceptorName: 拦截器的唯一名称 (string, 必填)
* - priority: 拦截器的优先级 (number, 数值越大优先级越高,默认为 9)
* - global: 是否为全局拦截器 (boolean, 默认为 false)
*/
export type HMRouterUtilInterceptorParam = HMInterceptorParam;
1.7 统一导出
文件: interceptor/Index.ets
/**
* HMRouter 拦截器相关类型统一导出
*/
export type { HMRouterUtilInterceptor } from './HMRouterUtilInterceptor';
export { HMRouterUtilInterceptorAction } from './HMRouterUtilInterceptorAction';
export type { HMRouterUtilInterceptorInfo } from './HMRouterUtilInterceptorInfo';
export type { HMRouterUtilInterceptorChain } from './HMRouterUtilInterceptorChain';
export type { HMRouterUtilInterceptorContext } from './HMRouterUtilInterceptorContext';
export type { HMRouterUtilInterceptorParam } from './HMRouterUtilInterceptorParam';
步骤 2:实现同步拦截器
同步拦截器通过实现 handle 方法,返回 HMInterceptorAction 枚举值来控制路由流程。
2.1 基本同步拦截器示例
文件: interceptorInstance/HMRouterUtilTestInterceptor.ets
import { HMInterceptor } from '@hadss/hmrouter';
import { HMRouterUtilInterceptor } from '../interceptor/HMRouterUtilInterceptor';
import {
HMRouterUtilInterceptorAction,
HMRouterUtilInterceptorInfo
} from '../interceptor/Index';
/**
* 拦截器名称常量
*/
const HM_ROUTER_UTIL_INTERCEPTOR: string = 'HMRouterUtilTestInterceptor';
/**
* HMRouter 测试拦截器
*
* 用于测试拦截器功能,同时实现了同步和异步两种拦截方式
* - 同步拦截器:直接放行,不做任何拦截
* - 异步拦截器:直接放行,不做任何拦截
*
* 注意:这是一个全局拦截器,会对所有路由跳转生效
*/
@HMInterceptor({
interceptorName: HM_ROUTER_UTIL_INTERCEPTOR,
global: true
})
export class HMRouterUtilTestInterceptor implements HMRouterUtilInterceptor {
/**
* 同步拦截器方法
* @param info 拦截器信息
* @returns 拦截器动作,返回 DO_NEXT 表示继续执行下一个拦截器
*/
handle(info: HMRouterUtilInterceptorInfo): HMRouterUtilInterceptorAction {
console.log('同步拦截器执行:', info.targetName);
return HMRouterUtilInterceptorAction.DO_NEXT;
}
}
2.2 登录拦截器示例
import { HMInterceptor } from '@hadss/hmrouter';
import { HMRouterUtil } from '../util/HMRouterUtil';
import {
HMRouterUtilInterceptor,
HMRouterUtilInterceptorAction,
HMRouterUtilInterceptorInfo
} from '../interceptor/Index';
/**
* 登录拦截器
* 检查用户是否已登录,未登录则跳转到登录页
*/
@HMInterceptor({
interceptorName: 'LoginInterceptor',
priority: 10,
global: false // 非全局拦截器,需要在 @HMRouter 中指定
})
export class LoginInterceptor implements HMRouterUtilInterceptor {
handle(info: HMRouterUtilInterceptorInfo): HMRouterUtilInterceptorAction {
// 检查用户是否已登录
const isLoggedIn = this.checkLoginStatus();
if (isLoggedIn) {
// 已登录,继续下一个拦截器
return HMRouterUtilInterceptorAction.DO_NEXT;
} else {
// 未登录,跳转到登录页面
HMRouterUtil.push(
'pages/LoginPage',
{ targetUrl: info.targetName },
{ skipAllInterceptor: true } // 避免循环拦截
);
// 拦截当前路由操作
return HMRouterUtilInterceptorAction.DO_REJECT;
}
}
private checkLoginStatus(): boolean {
// 实现登录状态检查逻辑
return false; // 示例:返回 false 表示未登录
}
}
2.3 权限拦截器示例
import { HMInterceptor } from '@hadss/hmrouter';
import {
HMRouterUtilInterceptor,
HMRouterUtilInterceptorAction,
HMRouterUtilInterceptorInfo
} from '../interceptor/Index';
/**
* 权限拦截器
* 检查用户是否有权限访问目标页面
*/
@HMInterceptor({
interceptorName: 'PermissionInterceptor',
priority: 9,
global: false
})
export class PermissionInterceptor implements HMRouterUtilInterceptor {
handle(info: HMRouterUtilInterceptorInfo): HMRouterUtilInterceptorAction {
// 检查用户权限
const hasPermission = this.checkPermission(info.targetName);
if (hasPermission) {
return HMRouterUtilInterceptorAction.DO_NEXT;
} else {
console.warn('权限不足,无法访问:', info.targetName);
return HMRouterUtilInterceptorAction.DO_REJECT;
}
}
private checkPermission(pageUrl: string): boolean {
// 实现权限检查逻辑
// 例如:检查用户角色、页面访问权限等
return true; // 示例:返回 true 表示有权限
}
}
步骤 3:实现异步拦截器
异步拦截器通过实现 intercept 方法,接收 IHMInterceptorChain 参数,支持异步操作和洋葱模型。
3.1 基本异步拦截器示例
import { HMInterceptor } from '@hadss/hmrouter';
import { HMRouterUtilInterceptor } from '../interceptor/HMRouterUtilInterceptor';
import {
HMRouterUtilInterceptorChain
} from '../interceptor/Index';
/**
* 异步拦截器示例
* 支持异步操作,如网络请求、数据获取等
*/
@HMInterceptor({
interceptorName: 'AsyncInterceptor',
priority: 10,
global: false
})
export class AsyncInterceptor implements HMRouterUtilInterceptor {
/**
* 异步拦截器方法
* @param chain 拦截器链
*/
async intercept(chain: HMRouterUtilInterceptorChain): Promise<void> {
const context = chain.getContext();
console.log('异步拦截器开始执行');
context?.setData('startTime', Date.now());
// 模拟异步操作,如网络请求
await new Promise<void>((resolve) => {
setTimeout(() => {
console.log('异步操作完成');
context?.setData('asyncCompleted', true);
resolve();
}, 1000);
});
// 继续执行下一个拦截器
await chain.onContinue();
// 洋葱模型:拦截器链返回后的处理
console.log('异步拦截器执行完成');
const endTime = Date.now();
const startTime = context?.getData<number>('startTime') || 0;
console.log(`总耗时: ${endTime - startTime}ms`);
}
}
3.2 异步登录拦截器示例
import { HMInterceptor } from '@hadss/hmrouter';
import { HMRouterUtil } from '../util/HMRouterUtil';
import {
HMRouterUtilInterceptor,
HMRouterUtilInterceptorChain
} from '../interceptor/Index';
/**
* 异步登录拦截器
* 通过异步方式检查登录状态
*/
@HMInterceptor({
interceptorName: 'AsyncLoginInterceptor',
priority: 10,
global: false
})
export class AsyncLoginInterceptor implements HMRouterUtilInterceptor {
async intercept(chain: HMRouterUtilInterceptorChain): Promise<void> {
// 异步检查登录状态
const isLoggedIn = await this.checkLoginStatusAsync();
if (isLoggedIn) {
// 已登录,继续下一个拦截器
await chain.onContinue();
} else {
// 未登录,跳转到登录页
HMRouterUtil.push(
'pages/LoginPage',
{ targetUrl: chain.getContext()?.getData<string>('targetUrl') },
{ skipAllInterceptor: true }
);
// 拦截当前路由操作
await chain.onReject();
}
}
private async checkLoginStatusAsync(): Promise<boolean> {
// 实现异步登录状态检查
// 例如:调用网络接口验证 token
return new Promise((resolve) => {
setTimeout(() => {
resolve(false); // 示例:返回 false 表示未登录
}, 500);
});
}
}
步骤 4:注册和使用拦截器
4.1 全局拦截器注册
全局拦截器会对所有路由跳转生效,有两种注册方式:
方式1:使用 global: true 属性
@HMInterceptor({
interceptorName: 'GlobalInterceptor',
global: true, // 全局拦截器
priority: 10
})
export class GlobalInterceptor implements HMRouterUtilInterceptor {
handle(info: HMRouterUtilInterceptorInfo): HMRouterUtilInterceptorAction {
console.log('全局拦截器执行');
return HMRouterUtilInterceptorAction.DO_NEXT;
}
}
方式2:通过 API 动态注册
import { HMRouterUtil } from '../hmRouter/util/HMRouterUtil';
import { HMInterceptorInstance } from '@hadss/hmrouter/src/main/ets/store/ComponentInstance';
// 创建拦截器实例
const interceptorInstance: HMInterceptorInstance = {
interceptorName: 'DynamicInterceptor',
interceptor: new MyInterceptor(),
priority: 10
};
// 注册全局拦截器
HMRouterUtil.registerGlobalInterceptor(interceptorInstance);
// 注销全局拦截器
HMRouterUtil.unRegisterGlobalInterceptor('DynamicInterceptor');
4.2 页面级拦截器注册
页面级拦截器只对特定页面的路由跳转生效,需要在 @HMRouter 注解中指定:
import { HMRouter } from '@hadss/hmrouter';
@HMRouter({
pageUrl: 'pages/DetailPage',
interceptors: ['LoginInterceptor', 'PermissionInterceptor'] // 指定拦截器
})
@Component
export struct DetailPage {
// ...
}
4.3 拦截器执行顺序
拦截器的执行顺序遵循以下规则:
- 按优先级排序:优先级高的先执行(
priority值越大优先级越高) - 优先级相同时:先执行页面级拦截器,再执行全局拦截器
- 同一优先级页面级拦截器:先执行发起页面的拦截器,再执行目标页面的拦截器
执行顺序示例:
优先级 15: 发起页面拦截器A
优先级 15: 目标页面拦截器B
优先级 15: 全局拦截器C
优先级 10: 发起页面拦截器D
优先级 10: 全局拦截器E
优先级 9: 全局拦截器F
步骤 5:拦截器上下文使用
拦截器上下文(InterceptorContext)用于在拦截器之间共享数据,特别适用于异步拦截器。
5.1 设置和获取上下文数据
async intercept(chain: HMRouterUtilInterceptorChain): Promise<void> {
const context = chain.getContext();
// 设置数据
context?.setData('userId', '12345');
context?.setData('startTime', Date.now());
// 继续执行下一个拦截器
await chain.onContinue();
// 获取数据
const userId = context?.getData<string>('userId');
const startTime = context?.getData<number>('startTime');
console.log('用户ID:', userId);
console.log('开始时间:', startTime);
}
5.2 上下文数据传递示例
// 拦截器1:设置用户信息
async intercept(chain: HMRouterUtilInterceptorChain): Promise<void> {
const context = chain.getContext();
context?.setData('user', { id: '123', name: '张三' });
await chain.onContinue();
}
// 拦截器2:使用用户信息
async intercept(chain: HMRouterUtilInterceptorChain): Promise<void> {
const context = chain.getContext();
const user = context?.getData<{ id: string; name: string }>('user');
if (user) {
console.log('当前用户:', user.name);
}
await chain.onContinue();
}
💡 实际应用示例
示例 1:完整的登录拦截器
import { HMInterceptor } from '@hadss/hmrouter';
import { HMRouterUtil } from '../util/HMRouterUtil';
import {
HMRouterUtilInterceptor,
HMRouterUtilInterceptorAction,
HMRouterUtilInterceptorInfo
} from '../interceptor/Index';
/**
* 登录拦截器
* 检查用户登录状态,未登录则跳转到登录页
*/
@HMInterceptor({
interceptorName: 'LoginInterceptor',
priority: 10,
global: true // 全局拦截器
})
export class LoginInterceptor implements HMRouterUtilInterceptor {
// 需要登录的页面列表
private readonly loginRequiredPages: string[] = [
'pages/ProfilePage',
'pages/OrderPage',
'pages/SettingPage'
];
handle(info: HMRouterUtilInterceptorInfo): HMRouterUtilInterceptorAction {
// 检查目标页面是否需要登录
const needLogin = this.loginRequiredPages.includes(info.targetName);
if (!needLogin) {
// 不需要登录,直接放行
return HMRouterUtilInterceptorAction.DO_NEXT;
}
// 检查登录状态
const isLoggedIn = this.checkLoginStatus();
if (isLoggedIn) {
return HMRouterUtilInterceptorAction.DO_NEXT;
} else {
// 未登录,跳转到登录页
HMRouterUtil.push(
'pages/LoginPage',
{
targetUrl: info.targetName,
sourceUrl: info.sourceName
},
{ skipAllInterceptor: true } // 跳过所有拦截器,避免循环
);
return HMRouterUtilInterceptorAction.DO_REJECT;
}
}
private checkLoginStatus(): boolean {
// 实现登录状态检查
// 例如:从本地存储或状态管理中读取
return false;
}
}
示例 2:日志记录拦截器
import { HMInterceptor } from '@hadss/hmrouter';
import {
HMRouterUtilInterceptor,
HMRouterUtilInterceptorAction,
HMRouterUtilInterceptorInfo
} from '../interceptor/Index';
/**
* 日志记录拦截器
* 记录所有路由跳转日志
*/
@HMInterceptor({
interceptorName: 'LogInterceptor',
priority: 1, // 低优先级,最后执行
global: true
})
export class LogInterceptor implements HMRouterUtilInterceptor {
handle(info: HMRouterUtilInterceptorInfo): HMRouterUtilInterceptorAction {
// 记录路由跳转日志
console.log('路由跳转:', {
from: info.sourceName,
to: info.targetName,
param: info.param,
timestamp: new Date().toISOString()
});
// 可以发送到日志服务器
this.sendLogToServer({
from: info.sourceName,
to: info.targetName,
param: info.param
});
return HMRouterUtilInterceptorAction.DO_NEXT;
}
private sendLogToServer(log: any): void {
// 实现日志发送逻辑
}
}
示例 3:性能监控拦截器
import { HMInterceptor } from '@hadss/hmrouter';
import {
HMRouterUtilInterceptor,
HMRouterUtilInterceptorChain
} from '../interceptor/Index';
/**
* 性能监控拦截器
* 统计路由跳转耗时
*/
@HMInterceptor({
interceptorName: 'PerformanceInterceptor',
priority: 1,
global: true
})
export class PerformanceInterceptor implements HMRouterUtilInterceptor {
async intercept(chain: HMRouterUtilInterceptorChain): Promise<void> {
const context = chain.getContext();
const startTime = Date.now();
context?.setData('routeStartTime', startTime);
// 继续执行下一个拦截器
await chain.onContinue();
// 计算耗时
const endTime = Date.now();
const duration = endTime - startTime;
console.log(`路由跳转耗时: ${duration}ms`);
// 如果耗时过长,记录警告
if (duration > 1000) {
console.warn('路由跳转耗时过长:', duration, 'ms');
}
}
}
⚠️ 注意事项
1. 装饰器必须使用原始名称
HMRouter 编译插件只识别原始的装饰器名称:
// ✅ 正确:使用原始装饰器
@HMInterceptor({ interceptorName: 'MyInterceptor' })
export class MyInterceptor { }
// ❌ 错误:封装后的装饰器不会被识别
@HMRouterInterceptorDecorator({ interceptorName: 'MyInterceptor' })
export class MyInterceptor { }
2. 同步拦截器 vs 异步拦截器
|
特性 |
同步拦截器 |
异步拦截器 |
|
实现方法 |
|
|
|
返回值 |
|
|
|
支持异步操作 |
❌ |
✅ |
|
支持洋葱模型 |
❌ |
✅ |
|
调用方式 |
同步/异步路由均可 |
仅异步路由方法 |
重要提示: 异步拦截器只能通过异步路由方法(如 pushAsync、replaceAsync)触发。
3. 拦截器执行时机
拦截器在以下时机执行:
- 路由栈发生变化前
- 转场动画发生前
- 页面生命周期回调前
特殊情况:
- 当
pageUrl为空时,拦截器不会执行 - 当目标页面不存在时,执行全局和发起页面拦截器,然后执行
onLost回调 - 当目标页面存在时,执行全局、发起页面和目标页面的拦截器
4. 避免循环拦截
在拦截器中跳转到其他页面时,应使用 skipAllInterceptor: true 避免循环拦截:
HMRouterUtil.push(
'pages/LoginPage',
{ targetUrl: info.targetName },
{ skipAllInterceptor: true } // 跳过所有拦截器
);
5. 拦截器优先级
- 优先级数值越大,执行越早
- 默认优先级为 9
- 建议将关键拦截器(如登录检查)设置为较高优先级(如 10)
- 将辅助拦截器(如日志记录)设置为较低优先级(如 1)
📊 拦截器使用场景对比
场景 1:登录检查
直接在每个页面检查:
// ❌ 代码重复,难以维护
aboutToAppear() {
if (!isLoggedIn()) {
HMRouterUtil.push('pages/LoginPage');
return;
}
// 页面逻辑
}
使用拦截器:
// ✅ 统一管理,易于维护
@HMInterceptor({ interceptorName: 'LoginInterceptor', global: true })
export class LoginInterceptor {
handle(info: HMInterceptorInfo): HMInterceptorAction {
if (!isLoggedIn()) {
HMRouterUtil.push('pages/LoginPage', { targetUrl: info.targetName });
return HMInterceptorAction.DO_REJECT;
}
return HMInterceptorAction.DO_NEXT;
}
}
场景 2:参数验证
直接在每个页面验证:
// ❌ 代码分散
aboutToAppear() {
const param = HMRouterUtil.getCurrentParam();
if (!param || !param.id) {
console.error('参数错误');
HMRouterUtil.pop();
return;
}
}
使用拦截器:
// ✅ 统一验证
@HMInterceptor({ interceptorName: 'ParamValidator', global: false })
export class ParamValidator {
handle(info: HMInterceptorInfo): HMInterceptorAction {
if (!info.param || !info.param.id) {
console.error('参数错误');
return HMInterceptorAction.DO_REJECT;
}
return HMInterceptorAction.DO_NEXT;
}
}
🎯 设计原则
|
原则 |
说明 |
|
单一职责 |
每个拦截器专注于特定功能(登录、权限、日志等) |
|
优先级合理 |
关键拦截器设置高优先级,辅助拦截器设置低优先级 |
|
避免循环 |
在拦截器中跳转时使用 |
|
类型安全 |
使用封装的类型别名,保证类型安全 |
|
易于测试 |
拦截器可以独立测试,不依赖页面 |
📝 总结
本文介绍了 HMRouter Interceptor 拦截器的封装和使用,包括:
- ✅ 类型封装:封装了 6 个拦截器相关类型
- ✅ 同步拦截器:通过
handle方法实现同步拦截 - ✅ 异步拦截器:通过
intercept方法实现异步拦截,支持洋葱模型 - ✅ 全局拦截器:使用
global: true或 API 注册全局拦截器 - ✅ 页面级拦截器:在
@HMRouter中指定页面级拦截器 - ✅ 拦截器上下文:使用上下文在拦截器之间共享数据
- ✅ 实际应用:提供了登录、日志、性能监控等实际应用示例
通过拦截器封装,我们可以:
- 实现统一的路由控制逻辑
- 减少代码重复,提高可维护性
- 支持复杂的路由验证和权限控制
- 实现路由跳转的日志记录和性能监控
更多推荐




所有评论(0)