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组件能够自动适配窗口显示大小,在窗口较大的场景下自动切换分栏展示效果。
Navigation组件的页面包含主页和内容页。
主页由标题栏、内容区和工具栏组成,可在内容区中使用NavRouter子组件实现导航栏功能。内容页主要显示NavDestination子组件中的内容。
NavRouter是配合Navigation使用的特殊子组件,默认提供点击响应处理,不需要开发者自定义点击事件逻辑。
NavRouter有且仅有两个子组件,其中第二个子组件必须是NavDestination。
NavDestination是配合NavRouter使用的特殊子组件,用于显示Navigation组件的内容页。当开发者点击NavRouter组件时,会跳转到对应的NavDestination内容区。
例如使用 Navigation实现首页到详情页的跳转。
分别实现 Home组件和Detail组件,Home组件默认包裹在Navigation组件中,Detail组件包裹在NavDestination组件中。通过pushPathByName进行跳转。
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) => {
<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(() => {
<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应用开发基础架构搭建-路由管理的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。
Beta版本就是api12
有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html
我在beta1的应用导航这篇文档中看到的还是老的解决方案 通过自己传入路由map https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-application-navigation-design-V5
当看到你的route_map.json的方式去导航页面 真的太方便了
希望能帮助到您
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
是的
好的,感谢!另外测试到,如果Home模块是引用Detail的har包方式,而不是module,那跳不到DetailPage,直接报错100002-找不到页面,请问你有遇到这样的情况吗?
如果使用 navigation.使用官方的系统路由就行