在鸿蒙应用中,自API 11开始可以采用 Navigation 组件进行跳转,分析如下。
1 在Index.ets文件中
scss
@Entry
@Component
struct Index {
store: IndexStore = new IndexStore()
@State
state?: IndexState = undefined
aboutToAppear(): void {
this.store.observe((state) => {
this.state = state
})
// 应用启动时,在 aboutToAppear 生命周期方法中,默认跳转到 OverviewPage 页面,使用 replacePath 方法替换当前页面,而不是添加新页面到栈中.
this.router.replacePath({
name: 'OverviewPage'
})
}
aboutToDisappear(): void {
this.store.clear()
}
// 使用 @Provide router: NavPathStack = new NavPathStack() 创建了一个全局共享的导航栈实例
// 通过HarmonyOS的状态共享机制,该 router 实例可以在所有子组件中通过 @Consume router 访问
// 这实现了跨组件层级的导航状态共享, @Provide 实现 "跨层级组件的状态共享",与 @Consume 配对,解决 "层层传参" 问题,支持状态双向同步。
// @Provide 本质是鸿蒙 ArkTS 语言为 "状态管理" 设计的基础装饰器,定义在 @ohos.ui.components 模块中(ArkUI 的核心组件与装饰器模块)。
// ArkTS 会自动引入 "状态管理相关的基础装饰器"(包括 @Provide、@Consume、@State、@Prop 等),只要代码是 ArkUI 组件(用 @Component 装饰),就能直接使用 @Provide,无需额外导入步骤。
// @Provide 不能单独使用,必须与子组件的 @Consume 配对 ------@Provide 是 "状态提供者",@Consume 是 "状态订阅者",二者通过相同的 "状态标识"(默认是变量名,也可自定义) 关联
// 可自定义 "状态标识"(避免同名冲突),如果多个 @Provide 变量名相同(如不同组件都有 router),可通过 @Provide('标识名') 自定义标识,子组件用 @Consume('标识名') 匹配:
// 父组件:自定义标识为"appRouter", @Provide('appRouter') router: NavPathStack = new NavPathStack();
// 子组件:通过标识"appRouter"订阅,避免与其他同名状态冲突,@Consume('appRouter') router: NavPathStack;
@Provide
router: NavPathStack = new NavPathStack() // 创建路由栈(NavPathStack),用@Provide共享给子组件
@State
index?: number = undefined
// tabNames :存储标签页显示文本的数组
tabNames: string[] = [
'A操作', 'B数据', 'C显示', 'D监控'
]
// routeNames :存储标签页对应的页面名称的数组,这两个数组通过索引位置一一对应,实现了标签到页面的映射
routeNames: string[] = [
'AView', 'BView', 'CView', 'DView'
]
build() {
Column() {
// Column() 组件是 垂直布局容器 ,会将所有子组件沿垂直方向(从上到下)排列
Column() {
// 通过 IndexTabView 的 onChange 回调监听标签页切换,根据选中的标签索引,从 routeNames 数组中获取对应的页面名称
// 在各个子页面中(如 IPManageView ),可以通过 @Consume 的router实例调用 pushPath 等方法进行页面跳转
IndexTabView({
index: this.index,
tabs: this.tabNames,
onChange: (index) => {
this.index = index
if (index !== undefined) {
// 使用 router.replacePath 方法切换到对应的页面
// 当使用this.router.replacePath()或this.router.pushPath()进行页面跳转时,Navigation组件会调用 navDestination 属性指定的PagesRouter函数,PagesRouter根据传入的路由名称参数,动态构建并渲染对应的视图组件
this.router.replacePath({
name: this.routeNames[index]
}, false)
} else {
// 当索引无效时,回退到 OverviewPage 页面
this.router.replacePath({
name: 'OverviewPage'
}, false)
}
}
})
Blank()
.height('10px')
// Row() 组件是 水平布局容器 ,会将所有子组件沿水平方向(从左到右)排列
Row() {
OverviewActionView({
onActionClick: (action) => {
this.store.performAction(action)
}
})
// 右侧放置 Navigation 组件(主要内容显示区域),
// Navigation 组件:通过@Provide/@Consume或NavController共享NavPathStack
// Navigation是 Stage 模型的导航容器组件,NavPathStack是管理路径的 "栈容器",二者配合实现路由,支持组件级导航、自定义标题栏、动画过渡等,是你之前代码中使用的方案。
Navigation(this.router) // 绑定路由栈到Navigation组件
.hideTitleBar(true)
.mode(NavigationMode.Stack) // 配置为栈式导航模式( NavigationMode.Stack )
.navDestination(this.PagesRouter) // 通过 navDestination 属性关联了 PagesRouter 构建器函数, 也即是绑定页面构建器(路径→组件映射)
.layoutWeight(1)
.height('100%')
.backgroundColor(Color.Transparent)
}
.layoutWeight(1)
.alignItems(VerticalAlign.Top)
.padding({ bottom: '10px'})
}
.layoutWeight(1)
.padding({ left: '9px', right: '9px' })
}
.width('100%')
.height('100%')
.backgroundImage($r("app.media.bg_window"))
.backgroundImageSize({ width: '100%', height: '100%' })
}
// PagesRouter 是一个 @Builder 装饰的函数,用于根据页面名称动态创建对应的组件实例,它是整个应用页面路由的核心映射机制.
// @Builder是HarmonyOS ArkUI框架中的UI构建函数装饰器,具有以下特点:
//组件构建封装:将UI组件的创建逻辑封装在函数中,实现组件复用和逻辑分离
//动态UI构建:根据传入参数动态决定构建哪种UI组件
//编译期优化:Builder函数在编译期会被优化处理,提升渲染性能
//无返回值:Builder函数不需要显式返回UI组件,直接在函数体内声明组件即可
@Builder
PagesRouter(name: string) { // 页面构建器:路径名→页面组件的映射
if (name === 'AView') {
AView()
} else if (name === 'OverviewPage') {
OverviewPage()
}
}
}
2 分析路由的发布与订阅的联系
在Index.ets中
less
@Provide
router: NavPathStack = new NavPathStack()
在AView.ets中
css
@Consume
router: NavPathStack
两者的联系 :
在 Index.ets 中定义了 @Provide router: NavPathStack = new NavPathStack()。
在 IPManageView.ets 中,使用 @Consume router: NavPathStack 进行消费。
这是HarmonyOS中的状态共享机制,@Provide 装饰的变量可以在其组件树的子组件中被 @Consume 装饰的变量共享和访问。它们共享同一个NavPathStack实例,用于应用内的页面导航。
命名规则 :
默认情况下,@Provide和@Consume需要使用相同的变量名来建立绑定关系,比如两者都使用了"router"作为变量名。
也可以使用相同的别名来建立绑定,可以使用 @Provide('myRouter') router: NavPathStack 和 @Consume('myRouter') customRouter: NavPathStack
这样即使变量名不同,通过共享的别名'myRouter'也能建立正确的绑定关系。
这种机制实现了组件树中跨层级的数据共享,避免了逐层传递参数的复杂性,特别适合用于全局状态管理如导航栈。
3 在BView中应用NavDestination
scss
build() {
NavDestination() {
Row() {
... }
} .hideTitleBar(true) .backgroundColor(Color.Transparent)}
在BView中的 build 函数中使用 NavDestination 包裹整个BView页面。
在BView.ets文件中,build方法使用NavDestination()包裹整个页面内容,这是HarmonyOS ArkUI框架中导航系统的重要设计模式。
使用NavDestination的原因
3.1 导航系统的层次关系
在Index.ets中,项目使用了完整的导航栈架构:
less
@Provide
router: NavPathStack = new NavPathStack()
// 在UI中Navigation(this.router) .hideTitleBar(true) .mode(NavigationMode.Stack) .navDestination(this.PagesRouter)
NavDestination作为Navigation的目的地组件,形成了完整的导航层次结构:Navigation(导航容器)→ NavDestination(导航目的地)。
3.2 页面组件的标准化封装
使用NavDestination包裹页面内容的主要原因包括:
导航上下文整合:NavDestination为页面提供了完整的导航上下文,使其能够正确地参与到导航栈的管理中。
路由参数传递支持:便于接收和处理通过路由传递的参数。
生命周期统一管理:保证页面在导航过程中能正确触发组件生命周期方法。
导航状态同步:确保页面状态与导航栈状态保持同步。
3.3 导航机制的实现
Index.ets中使用@Provide定义全局共享的NavPathStack实例。 其它页面使用@Consume获取并使用这个导航栈。 通过this.router.pushPath()进行页面跳转,this.router.pop()返回上一页。
3.4 NavDestination作为被导航到的目标页面容器的技术设计优势
使用NavDestination的设计优势包括:
组件化设计:每个页面作为独立的导航目的地,便于维护和复用。
统一的导航体验:通过Navigation和NavDestination的配合,提供一致的导航体验。
灵活的页面配置:可以通过NavDestination的属性(如.hideTitleBar())自定义页面的导航行为。
状态管理集成:与@State、@Provide、@Consume等状态管理机制无缝集成。
总结来说,BView.ets中build方法使用NavDestination是HarmonyOS ArkUI导航架构的标准实践,确保页面能够正确参与导航栈管理,并与应用的整体导航机制保持一致。