目录

 一、核心概念(一句话概括)

二、实现步骤(按步骤说明)

第一步:创建路由管理模块(RouterModule)

 第二步:主页面(HAP包)初始化

第三步:HAR包页面设置

第四步:执行跳转

 三、跳转原理(push方法执行流程)

四、核心机制(关键技术点)

五、wrapBuilder详解

六、应用场景

 七、注意事项(面试可能问到)

八  示例代码结构

九、面试回答模板(30秒版本)

十、面试回答模板(2分钟详细版)


 一、核心概念(一句话概括)

Navigation动态路由实现了**跨模块页面跳转**,即使HAP包不直接依赖HAR包,也能动态跳转到HAR包中的页面,实现模块解耦。

二、实现步骤(按步骤说明)

第一步:创建路由管理模块(RouterModule)

 使用两个Map存储:

  - `builderMap`:存储页面构建器

  - `routerMap`:存储路由栈

- 提供注册、获取、跳转等方法

 第二步:主页面(HAP包)初始化

1. **创建NavPathStack并注册**

   aboutToAppear() {

     this.hapARouter = new NavPathStack();

     RouterModule.createRouter("HapA_Router", this.hapARouter);

   }

2. **使用Navigation组件,绑定动态路由映射**

   Navigation(this.hapARouter) {

     // 内容

   }

   .navDestination(this.routerMap)

3. **创建路由映射Builder**

   @Builder

   routerMap(builderName: string, param: object) {

     RouterModule.getBuilder(builderName).builder(param);

   }

第三步:HAR包页面设置

1. **创建页面Builder并注册**

   @Builder

   export function harBuilder(value: object) {

     NavDestination() { /* 页面内容 */ }

   }

   // 注册

   let builder = wrapBuilder(harBuilder);

   RouterModule.registerBuilder("HarA_Page1_Builder", builder)

2. **实现harInit函数(动态导入)**

   export function harInit(path: string): void {

     switch (path) {

       case "./src/main/ets/components/mainpage/page1":

         import("./src/main/ets/components/mainpage/page1");

         break;

     }

   }

第四步:执行跳转

- **URL格式**:`{har包名}/{页面路径}/{路由名}-{Builder名}`

- **示例**:`HarA/src/main/ets/components/mainpage/page1/HapA_Router-HarA_Page1_Builder`

- **调用**:`RouterModule.push(url)`

Button("跳转到页面")
  .onClick(() => {
    let url = "HarA/src/main/ets/components/mainpage/page1/HapA_Router-HarA_Page1_Builder";
    RouterModule.push(url);
  })

 三、跳转原理(push方法执行流程)

1. **解析URL**:拆分出HAR包名、路由名、Builder名

2. **动态导入**:`await import(harName)` 加载HAR包

3. **初始化页面**:调用 `harInit(path)` 加载具体页面模块

4. **执行跳转**:通过路由栈 `pushPathByName(builderName)` 跳转

public static async push(url: string): Promise<void>{
  // 1. 解析URL
  let params = url.split("/");
  const harName = params[0];  // HAR包名
  let context = params[params.length - 1].split("-");
  const routerName = context[0];  // 路由名
  const builderName = context[1];  // Builder名
  
  // 2. 构建页面路径
  let path = ".";
  for (let i = 1; i < params.length - 1; i++) {
    path += "/" + params[i];
  }
  
  // 3. 动态导入HAR包并初始化
  let ns: ESObject = await import(harName);
  ns.harInit(path);
  
  // 4. 通过路由栈跳转
  RouterModule.getRouter(routerName).pushPathByName(builderName, null);
}

四、核心机制(关键技术点)

1. 动态导入

- 使用 `import()` 动态加载HAR包

- 通过 `harInit()` 函数按需加载具体页面模块

2. WrappedBuilder包装

什么是wrapBuilder

`wrapBuilder()` 是HarmonyOS提供的API,用于将普通的 `@Builder` 函数包装成 `WrappedBuilder` 类型,使其能够在运行时动态调用。

 为什么需要wrapBuilder

- **普通Builder的限制**:普通的 `@Builder` 函数是编译时确定的,无法在运行时通过字符串名称动态调用

- **动态路由的需求**:动态路由需要在运行时根据URL中的Builder名称来调用对应的Builder

- **类型转换**:`wrapBuilder()` 将Builder转换为 `WrappedBuilder<[object]>` 类型,支持动态调用

 使用方式

// 1. 定义普通的Builder函数

@Builder

export function harBuilder(value: object) {

  NavDestination() {

    // 页面内容

  }

}

// 2. 使用wrapBuilder包装

let builder: WrappedBuilder<[object]> = wrapBuilder(harBuilder);

// 3. 注册到RouterModule

RouterModule.registerBuilder("HarA_Page1_Builder", builder);

 调用方式
 

// 在路由映射Builder中动态调用

@Builder

routerMap(builderName: string, param: object) {

  // 通过名称获取WrappedBuilder并调用

  RouterModule.getBuilder(builderName).builder(param);

}

关键特性

- **运行时动态调用**:支持通过字符串名称在运行时查找和调用Builder

- **类型安全**:包装后的 `WrappedBuilder` 保持了类型信息

- **参数传递**:支持通过 `builder(param)` 方法传递参数

- **跨模块支持**:可以在不同模块间传递和调用WrappedBuilder

 3. 路由栈管理

- 每个路由栈通过名称进行管理

- 支持多个独立的路由栈

 4. 跨模块跳转

- HAP包可以跳转到未直接依赖的HAR包页面

- 实现了真正的动态路由

五、wrapBuilder详解

1. wrapBuilder的作用

`wrapBuilder()` 是动态路由实现的关键API,它解决了以下问题:

问题背景

- Navigation组件的 `navDestination` 需要接收一个Builder函数

- 动态路由需要在运行时根据名称动态调用不同的Builder

- 普通的 `@Builder` 函数无法通过字符串名称动态调用

解决方案

通过 `wrapBuilder()` 将Builder包装成 `WrappedBuilder` 类型:

- 可以在Map中存储,通过名称查找

- 支持运行时动态调用

- 保持了Builder的类型安全

 2. wrapBuilder的工作流程

普通Builder函数

    ↓ wrapBuilder()

WrappedBuilder对象

    ↓ 注册到RouterModule

存储在builderMap中

    ↓ 通过名称获取

动态调用builder(param)

3. 完整示例

// 步骤1:定义页面Builder

@Builder

export function harBuilder(value: object) {

  NavDestination() {

    Column() {

      Text('页面内容')

    }

  }

  .title('HarA_Page1')

}



// 步骤2:包装并注册

let builderName = 'HarA_Page1_Builder';

if (!RouterModule.getBuilder(builderName)) {

  // 使用wrapBuilder包装

  let builder: WrappedBuilder<[object]> = wrapBuilder(harBuilder);

  // 注册到RouterModule

  RouterModule.registerBuilder(builderName, builder);

}



// 步骤3:动态调用(在主页面)

@Builder

routerMap(builderName: string, param: object) {

  // 通过名称获取WrappedBuilder

  let wrappedBuilder = RouterModule.getBuilder(builderName);

  // 调用builder方法执行构建

  wrappedBuilder.builder(param);

}

4. 注意事项

1. **必须使用wrapBuilder**:普通的Builder函数无法直接存储到Map中动态调用

2. **类型必须匹配**:`WrappedBuilder<[object]>` 中的泛型参数必须与Builder函数签名匹配

3. **注册时机**:Builder需要在页面模块加载时注册,通常在模块顶层代码中执行

4. **避免重复注册**:使用 `if (!RouterModule.getBuilder(builderName))` 检查避免重复注册

5. wrapBuilder与动态路由的关系

动态路由跳转流程:

1. RouterModule.push(url)

   ↓

2. 解析URL获取builderName

   ↓

3. 动态import HAR包

   ↓

4. HAR包中的页面模块加载,执行Builder注册

   ↓

5. wrapBuilder包装Builder并注册到RouterModule

   ↓

6. pushPathByName(builderName) 触发navDestination

   ↓

7. routerMap通过builderName获取WrappedBuilder

   ↓

8. 调用WrappedBuilder.builder(param) 渲染页面

六、应用场景

1. **插件化架构**:不同功能模块作为HAR包,主应用动态加载

2. **按需加载**:减少初始包体积,按需加载功能模块

3. **模块解耦**:HAP包与HAR包之间无需编译时依赖

4. **动态配置**:通过配置文件或网络请求动态决定跳转目标

 七、注意事项(面试可能问到)

1. 动态import限制:目前不支持动态import变量表达式和跨模块相对路径,需要使用switch语句作为替代方案

2. Builder注册:每个页面的Builder需要在模块加载时注册到RouterModule

3. 路由名一致性:跳转时使用的路由名必须与注册时的路由名一致

4. URL格式:必须严格按照 `{har包名}/{路径}/{路由名}-{Builder名}` 的格式

5. 环境差异:由于环境差异,不建议直接编译,应参考示例代码进行编写

八  示例代码结构

entry (HAP包)
├── pages/Index.ets          # 主页面,创建NavPathStack
├── RouterModule             # 路由管理模块
│   └── utils/RouterModule.ets
harA (HAR包)
├── Index.ets                # harInit函数
└── pages/
    ├── page1.ets           # 注册Builder
    ├── page2.ets
    └── page3.ets
harB (HAR包)
├── Index.ets                # harInit函数
└── pages/
    ├── page1.ets           # 注册Builder
    ├── page2.ets
    └── page3.ets

九、面试回答模板(30秒版本)

> "Navigation动态路由实现了跨模块页面跳转。核心是RouterModule统一管理路由栈和页面构建器。使用步骤:1)主页面创建NavPathStack并注册;2)HAR包页面创建Builder并注册;3)通过URL格式调用push方法跳转。关键技术是动态import加载HAR包,wrapBuilder包装页面构建器,实现运行时动态调用。主要用于插件化架构和模块解耦场景。"

十、面试回答模板(2分钟详细版)

> "Navigation动态路由解决了跨模块页面跳转的问题,即使HAP包不直接依赖HAR包也能跳转。

> **实现分为4步:**

> 1. 创建RouterModule,用Map存储路由栈和Builder

> 2. 主页面创建NavPathStack并注册,Navigation组件绑定动态路由映射

> 3. HAR包页面创建Builder并用wrapBuilder包装后注册,实现harInit函数用于动态导入

> 4. 通过URL格式调用RouterModule.push跳转

> **核心机制:**

> - 动态import加载HAR包

> - wrapBuilder包装Builder支持运行时调用

> - URL解析获取路由信息

> **应用场景:** 插件化架构、模块解耦、按需加载。需要注意动态import的限制,需要用switch替代变量表达式。"

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐