HarmonyOS NEXT 的导航体系
HarmonyOS NEXT 提供了两套导航方案,适合不同场景:
Navigation 组件(推荐)
ArkUI 原生导航容器,支持自适应单/双列布局(手机显示单列,平板自动变双列)、NavDestination 页面管理、转场动画、路由拦截。这是 HarmonyOS NEXT 官方推荐的主导航方案,适合绝大多数应用。
Router 模块(传统方案)
@ohos.router 提供的命令式路由 API,通过 router.pushUrl()、router.back() 控制页面栈。语法更简单,但功能不如 Navigation 丰富,不支持自适应布局。适合简单应用或旧代码迁移。
Navigation 组件
Navigation 是一个智能导航容器,它会根据设备屏幕大小自动决定显示方式:手机显示单页模式(Stack),平板/折叠屏展开后显示双栏模式(Split),开发者无需为不同设备单独适配。
基本结构
// NavPathStack 是页面栈的控制器,负责 push/pop/replace 操作
// 通常在根组件中创建,向下传递
@Entry
@Component
struct MainPage {
// NavPathStack:页面路由栈,管理所有 NavDestination 页面
navStack: NavPathStack = new NavPathStack()
build() {
// Navigation 组件包裹整个应用导航区域
Navigation(this.navStack) {
// 这里是"主页"内容,也是 Navigation 的首屏
HomeContent({ navStack: this.navStack })
}
// 设置标题栏模式
.title('首页')
// 隐藏返回按钮(首页不需要)
.hideBackButton(true)
// 设置导航模式:Auto 自适应(手机Stack/平板Split)
.mode(NavigationMode.Auto)
// 注册路由表:key → 对应的 NavDestination 组件
.navDestination(this.PageMap)
}
// @Builder 定义页面路由映射表
@Builder
PageMap(name: string, param: object) {
if (name === 'ArticleDetail') {
ArticleDetailPage({ param: param as ArticleParam })
} else if (name === 'UserProfile') {
UserProfilePage({ param: param as UserParam })
} else if (name === 'Settings') {
SettingsPage()
}
}
}
页面跳转与传参
// 定义参数类型(强烈推荐定义接口,保证类型安全)
interface ArticleParam {
articleId: number
title: string
source: string
}
// 首页组件:触发页面跳转
@Component
struct HomeContent {
navStack: NavPathStack = new NavPathStack()
build() {
Column() {
Button('查看文章详情')
.onClick(() => {
// pushPathByName:跳转到命名路由,传递参数
this.navStack.pushPathByName('ArticleDetail', {
articleId: 42,
title: 'ArkUI 深度解析',
source: 'home'
} as ArticleParam)
})
Button('个人主页')
.onClick(() => {
this.navStack.pushPathByName('UserProfile', { userId: 1001 })
})
Button('替换当前页(不留历史)')
.onClick(() => {
// replacePathByName:替换当前页,不产生历史记录
this.navStack.replacePathByName('Settings', {})
})
}
}
}
// 详情页:接收参数
@Component
struct ArticleDetailPage {
param: ArticleParam = { articleId: 0, title: '', source: '' }
// @Consume 获取 Navigation 注入的路由栈(在子页面中使用)
pathStack: NavPathStack = new NavPathStack()
build() {
// NavDestination 是每个子页面的根容器
NavDestination() {
Column({ space: 16 }) {
Text(this.param.title).fontSize(24).fontWeight(FontWeight.Bold)
Text(`文章 ID:${this.param.articleId}`)
Button('返回')
.onClick(() => {
this.pathStack.pop() // 普通返回
// this.pathStack.popToName('Home') // 返回到指定页面
// this.pathStack.clear() // 清空历史
})
}
.padding(24)
}
.title(this.param.title)
}
}
底部 Tab 导航
大多数应用都有底部 Tab 栏。在 HarmonyOS NEXT 中,可以用 Tabs 组件或在 Navigation 内部嵌套实现:
@Entry
@Component
struct MainTabsPage {
@State currentTab: number = 0
private tabsController: TabsController = new TabsController()
build() {
Tabs({
barPosition: BarPosition.End, // 底部 Tab 栏
controller: this.tabsController,
index: this.currentTab
}) {
// 每个 TabContent 对应一个 Tab 页
TabContent() {
HomePage()
}
.tabBar(this.TabBarItem('首页', '🏠', 0))
TabContent() {
DiscoverPage()
}
.tabBar(this.TabBarItem('发现', '🔍', 1))
TabContent() {
ProfilePage()
}
.tabBar(this.TabBarItem('我的', '👤', 2))
}
.onChange((index: number) => {
this.currentTab = index
})
.barMode(BarMode.Fixed) // Tab 均分宽度
}
// 自定义 TabBar 图标样式
@Builder
TabBarItem(label: string, icon: string, index: number) {
Column({ space: 4 }) {
Text(icon).fontSize(22)
Text(label)
.fontSize(11)
.fontColor(this.currentTab === index ? '#CF0A2C' : '#768390')
}
.padding({ top: 8, bottom: 8 })
}
}
页面转场动画
HarmonyOS NEXT 提供了丰富的页面转场动画,既有系统预设,也支持完全自定义:
// NavDestination 内设置转场动画
NavDestination() {
// 页面内容
}
.customNavContentTransition(this.customTransition)
// 自定义转场:从右侧滑入
customTransition(
from: NavContentInfo,
to: NavContentInfo,
operation: NavigationOperation
): NavigationAnimatedTransition | undefined {
if (operation === NavigationOperation.PUSH) {
return {
onTransitionEnd: (isSuccess: boolean) => {
console.log('转场完成', isSuccess)
},
timeout: 1000,
transition: (transitionProxy: NavigationTransitionProxy) => {
// 使用 animateTo 控制动画
animateTo({
duration: 350,
curve: Curve.EaseOut
}, () => {
transitionProxy.finishTransition()
})
}
}
}
return undefined // 使用默认转场
}
// 组件内动画(进入/退出)
Column()
.transition(
TransitionEffect.OPACITY.combine(
TransitionEffect.translate({ x: 100 })
)
.animation({ duration: 300, curve: Curve.EaseOut })
)
深链接与 Want
深链接(Deep Link)允许外部应用或网页直接跳转到应用内的特定页面。在 HarmonyOS NEXT 中,通过配置 Want 的 URI 和 Action 实现:
// module.json5 中配置深链接
// "skills" 字段声明 Ability 响应的 URI
{
"skills": [{
"entities": ["entity.system.home"],
"actions": ["ohos.want.action.viewData"],
"uris": [{
"scheme": "myapp",
"host": "article",
"pathStartWith": "/"
}]
}]
}
// EntryAbility.ts — 处理深链接跳转
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
this.handleWant(want)
}
// 应用已在前台时收到新 Want
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
this.handleWant(want)
}
handleWant(want: Want) {
const uri = want.uri // e.g. "myapp://article/123"
if (uri) {
const url = new URL(uri)
const articleId = url.pathname.replace('/', '')
// 通过 AppStorage 传递跳转目标,让页面组件监听并跳转
AppStorage.setOrCreate('deepLinkTarget', {
page: 'ArticleDetail',
params: { articleId: Number(articleId) }
})
}
}
路由拦截与守卫
类似 Vue Router 的 beforeEach 守卫,Navigation 支持在页面跳转前执行拦截逻辑,常用于登录态检验:
Navigation(this.navStack) {
HomeContent()
}
.navDestination(this.PageMap)
// 路由拦截:跳转前执行检查
.onNavBarStateChange((isVisible: boolean) => {
console.log('导航栏可见性变化:', isVisible)
})
// 监听路由栈变化
.onNavigationModeChange((mode: NavigationMode) => {
console.log('导航模式变化(单/双栏切换):', mode)
})
// 在跳转时手动拦截
function navigateWithAuth(
navStack: NavPathStack,
pageName: string,
params: object
) {
const isLoggedIn = AppStorage.get<boolean>('isLoggedIn')
const needsAuth = ['UserProfile', 'Orders', 'Checkout']
if (needsAuth.includes(pageName) && !isLoggedIn) {
// 未登录跳转到登录页,带上原目标作为重定向参数
navStack.pushPathByName('Login', {
redirect: pageName,
redirectParams: params
})
return
}
navStack.pushPathByName(pageName, params)
}
Navigation vs Router 如何选择
新项目统一使用 Navigation + NavDestination 方案。它支持多设备自适应、转场动画定制、路由拦截,且与华为未来的多窗口特性兼容。Router 模块虽然简单,但不支持自适应布局,在折叠屏和平板上体验差。老项目可以逐步将 Router 迁移到 Navigation。