HarmonyOS 鸿蒙Next应用开发基础架构搭建-路由管理

发布于 1周前 作者 caililin 来自 鸿蒙OS

HarmonyOS 鸿蒙Next应用开发基础架构搭建-路由管理

HarmonyOS NEXT应用开发基础架构搭建-设计理念和目录结构

HarmonyOS NEXT应用开发基础架构搭建-模块设计

HarmonyOS NEXT应用开发基础架构搭建-路由管理

HarmonyOS NEXT应用开发基础架构搭建-路由页面权限控制

HarmonyOS NEXT应用开发基础架构搭建-多端布局之自适应布局

HarmonyOS NEXT应用开发基础架构搭建-多端布局之响应式布局

路由管理是指在应用程序开发中对用户界面的不同页面或视图之间导航和流转进行控制和管理的一种机制。它确保了用户能够从一个界面平滑过渡到另一个界面,并且能够跟踪和控制这些界面(或称为路由)的堆叠顺序和生命周期。

鸿蒙Next提供了@ohos.router和Navigation两种路由管理。

1.页面路由 (@ohos.router)

Router模块提供了两种跳转模式,分别是router.pushUrl()和router.replaceUrl()

  • router.pushUrl():目标页面不会替换当前页,而是压入页面栈。这样可以保留当前页的状态,并且可以通过返回键或者调用router.back()方法返回到当前页。

  • router.replaceUrl():目标页面会替换当前页,并销毁当前页。这样可以释放当前页的资源,并且无法返回到当前页。

router模块也支持命名路由

  • router.pushNamedRoute 跳转到指定的命名路由页面

2.Navigation

Navigation组件一般作为页面的根容器,包括单页面、分栏和自适应三种显示模式。

Navigation组件适用于模块内页面切换,一次开发,多端部署场景。通过组件级路由能力实现更加自然流畅的转场体验,并提供多种标题栏样式来呈现更好的标题和内容联动效果。一次开发,多端部署场景下,Navigation组件能够自动适配窗口显示大小,在窗口较大的场景下自动切换分栏展示效果。

0000000000011111111.20240612140638.48907631802419755591334574054886.png

0000000000011111111.20240612140638.50339043560680255058384977542362.png

Navigation组件的页面包含主页和内容页。

主页由标题栏、内容区和工具栏组成,可在内容区中使用NavRouter子组件实现导航栏功能。内容页主要显示NavDestination子组件中的内容。

NavRouter是配合Navigation使用的特殊子组件,默认提供点击响应处理,不需要开发者自定义点击事件逻辑。

NavRouter有且仅有两个子组件,其中第二个子组件必须是NavDestination

NavDestination是配合NavRouter使用的特殊子组件,用于显示Navigation组件的内容页。当开发者点击NavRouter组件时,会跳转到对应的NavDestination内容区。

  

例如使用 Navigation实现首页到详情页的跳转。

分别实现 Home组件和Detail组件,Home组件默认包裹在Navigation组件中,Detail组件包裹在NavDestination组件中。通过pushPathByName进行跳转。

cke_1315.png

cke_6645.png

cke_11993.png

Navigation使用中的问题

但是Navigation依然存在一些问题,例如可以下面的代码,当需要跳转的时候,需要配置NavPathStack路由栈,并根据判断加载不同的组件。

这样会导致各个模块之间耦合度过高。

该场景采用一个Navigation+多个har/hsp的架构,其中一个模块对应一个har/hsp。

当多个har/hsp的UI组件存在相互跳转的业务需求时,将出现模块间相互依赖的问题。

我们使用这种模式,实现Home页面向Detail页面的跳转:

1. 在Phone模块中的Home页面组件中开发Navigation组件,并关联与之对应的NavPathStack路由栈,示例代码如下:

@Component
struct Home{

@State appPathStack: NavPathStack = new NavPathStack();

build() {

Navigation(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.appPathStack) {
  <span class="hljs-comment"><span class="hljs-comment">// ...</span></span>
}

} }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

2. 在Home模块的oh-package.json5文件中添加Detail模块的依赖,并且把har Detail模块中需要跳转的Detail组件添加到Home模块的Navigation组件路由表中,示例代码如下:

// har home的oh-package.json5文件
“dependencies”: {
// 添加对Detail的依赖
“Detail”: “file:…/detail”
}

<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

在Home模块的home组件中的routerMap路由表中,添加Detail模块的Detail组件,示例代码如下:

// 导入Detail.har的Detail页面组件
import { Detail } from ‘Detail’;
struct Home {
@State appPathStack: NavPathStack = new NavPathStack();

@Builder routerMap(builderName: string, param: object) { if (builderName === ‘Detail’) { Detail() } }

build() { Navigation(this.appPathStack) { // … } .navDestination(this.routerMap) } }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

3.在home模块的Navigation组件中添加跳转到Detail模块的Detail页面的逻辑,完整示例代码如下:

import { Detail } from ‘Detail’;

struct Home { @State appPathStack: NavPathStack = new NavPathStack();

@Builder routerMap(builderName: string, param: object) { if (builderName === ‘Detail’) { Detail() } }

build() { Navigation(this.appPathStack) { Button(‘跳转到Detail的Detail页面’) .onClick(() => {

      <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.appPathStack.pushPathByName(<span class="hljs-string"><span class="hljs-string">'Detail'</span></span>, <span class="hljs-literal"><span class="hljs-literal">null</span></span>);
    })
}
.navDestination(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.routerMap)

} }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

可以看到上面的写法存在很多问题:

  • 使用Navigation时,所有路由页面需要通过import方式导入当前页面,并存入页面路由表routerMap中
  • 主动使用import的方式需显性指定加载路径,造成开发态模块耦合严重;
  • 模块无法独立编译,且存在开发态模块间循环依赖问题。

Navigation动态路由方案

为了实现多模块路由管理和模块间解耦。在Next Beta1版本中,Navigation增加了动态路由

从API version 12开始,Navigation支持使用系统路由表的方式进行动态路由。

各业务模块(HSP/HAR)中需要独立配置router_map.json文件,在触发路由跳转时,应用只需要通过NavPactStack提供的路由方法,传入需要路由的页面配置名称,此时系统会自动完成路由模块的动态加载、页面组件构建,并完成路由跳转,从而实现了开发层面的模块解耦。

动态路由包括系统路由表自定义路由两种形式。我们以系统路由表来进行实际演示:

1.在Detail模块的配置文件module.json5添加路由表配置:

  {
“module” : {
“routerMap”: “$profile:route_map”
}
}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

2. 添加完路由配置文件地址后,需要在Detail模块的resources/base/profile中创建route_map.json文件。添加如下配置信息:

  {
“routerMap”: [
{
“name”: “DetailPage”,
“pageSourceFile”: “src/main/ets/pages/Detail.ets”,
“buildFunction”: “DetailPageBuilder”,
“data”: {
“description” : “this is Detail”
}
}
]
}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

相关参数如下:

name 跳转页面名称。
pageSourceFile 跳转目标页在包内的路径,相对src目录的相对路径。
buildFunction 跳转目标页的入口函数名称,必须以@Builder修饰。
data 应用自定义字段。可以通过配置项读取接口getConfigInRouteMap获取。

3. 在Detail页面中,需要配置入口Builder函数,函数名称需要和router_map.json配置文件中的buildFunction保持一致,否则在编译时会报错。


@Builder
export function DetailPageBuilder() {
Detail()
}

@Component struct Detail{ pathStack: NavPathStack = new NavPathStack()

build() {
  NavDestination() {
  }
  .title(<span class="hljs-string"><span class="hljs-string">'Detail'</span></span>)
  .onReady((context: NavDestinationContext) =&gt; {
     <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.pathStack = context.pathStack
  })
}

}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

4. 在Home模块中,通过pushPathByName等路由接口进行页面跳转。此时Navigation中可以不用配置navDestination属性

  @Entry
@Component
struct Home{
appPathStack: NavPathStack = new NavPathStack();

build() {
  Navigation(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.appPathStack){
  }.onAppear(() =&gt; {
    <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.pageStack.pushPathByName(<span class="hljs-string"><span class="hljs-string">"DetailPage"</span></span>, <span class="hljs-literal"><span class="hljs-literal">null</span></span>, <span class="hljs-literal"><span class="hljs-literal">false</span></span>);
  })
  .hideNavBar(<span class="hljs-literal"><span class="hljs-literal">true</span></span>)
}

}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

我们可以看到通过使用系统路由表,不再需要导入跳转所需页面,减少了模块之间的依赖,达到了解耦的目的。

3. router和Navigation的技术选择、推荐使用场景

在不涉及复杂动效、交互、多级路由等场景时,可以使用router。

但考虑到应用当前或以后可能出现的复杂场景,以及整体交互体验的一致,推荐使用Navigation,Navigation可以完全替换router的能力。

后续router的策略是不演进,但现有能力会继续维护。后续对路由能力的增强需求在Navigation上持续构建。

HarmonyOS NEXT应用开发基础架构搭建-设计理念和目录结构

HarmonyOS NEXT应用开发基础架构搭建-模块设计

HarmonyOS NEXT应用开发基础架构搭建-路由管理

HarmonyOS NEXT应用开发基础架构搭建-路由页面权限控制

HarmonyOS NEXT应用开发基础架构搭建-多端布局之自适应布局

HarmonyOS NEXT应用开发基础架构搭建-多端布局之响应式布局



关于HarmonyOS 鸿蒙Next应用开发基础架构搭建-路由管理的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。

19 回复
发布到用户的 next 版本 是 API version 12 的?

Beta版本就是api12

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

你好,首先很感谢你的分享,想请教下你是如何获取到api12导航的这些变化的,我找了好久文档也没看到相关资料呢

我在beta1的应用导航这篇文档中看到的还是老的解决方案 通过自己传入路由map https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-application-navigation-design-V5

当看到你的route_map.json的方式去导航页面 真的太方便了

希望能帮助到您

在同一模块可以跳转,跨模块,提示找不到modue

 E     [ecmascript] When the route jump, Cannot find module 'com.test.myapplication/entry[@TestHar](/user/TestHar)/ets/pages/PageThree'

请问如何解决呀

可以贴一下代码,和项目结构,是使用的三层结构设计吗

找到原因,每次新增路由需要 clean 否则一直会提示找不到。。。

是的IDE有这个问题,有时候就很难受

系统路由表有自动生成的方式吗?每个目标页面都要手动配置一次有点麻烦

暂时没在文档中发现有自动生成的方式,如果想减少步骤,可以使用动态路由的方式,但是需要额外的路由管理模块

我昨天从原来的动态路由库里把「自动生成配置文件「的部分抽出来改造了一下,通过注解可以在编译期自动生成了router_map.json和页面的 Builder 入口了,封装了一个插件~ https://github.com/Star1128/AutoGenRouterMap/tree/main

谢谢楼主分享,这篇文章通俗明白的讲解了系统路由表的使用,并对比了router和Navigation的使用方式。zan
楼主你好,我的页面路由场景不是很复杂,比如pageA->B->C 这样,是不是就不推荐用Navigation了,我的页面也没有导航页,只有子页面上的一些布局,是不是就用不了Navigation了

好的,感谢!另外测试到,如果Home模块是引用Detail的har包方式,而不是module,那跳不到DetailPage,直接报错100002-找不到页面,请问你有遇到这样的情况吗?

如果使用 navigation.使用官方的系统路由就行

回到顶部