HarmonyOS APP<<古今职鉴定>>开源教程第18篇:页面路由与导航架构
本篇学习 Navigation 路由系统,构建完整的导航架构
·
本篇学习 Navigation 路由系统,构建完整的导航架构

图:页面路由与导航架构 的关键流程与实现要点。
学习目标
完成本篇后,你将能够:
- ✅ 理解 Navigation 路由系统
- ✅ 使用 NavPathStack 管理路由
- ✅ 实现页面间参数传递
- ✅ 设计完整导航架构
预计学习时间
约 120 分钟
实战一:理解路由系统
第一步:传统 router vs Navigation
| 特性 | router | Navigation |
|---|---|---|
| 路由管理 | 全局单例 | 组件级路由栈 |
| 参数传递 | params 对象 | 类型安全 |
| 嵌套路由 | 不支持 | 支持 |
| 动画控制 | 有限 | 灵活 |
| 推荐程度 | 了解即可 | 推荐使用 |
第二步:Navigation 核心概念
| 概念 | 说明 |
|---|---|
| Navigation | 路由容器组件 |
| NavPathStack | 路由栈,管理页面 |
| NavDestination | 目标页面包装器 |
| navDestination | 路由映射函数 |
第三步:路由架构示意
┌─────────────────────────────────────┐
│ MainPage (@Entry) │
│ ┌─────────────────────────────────┐│
│ │ Navigation(navStack) ││
│ │ └─ HomePage (默认) ││
│ │ .navDestination(router) ││
│ └─────────────────────────────────┘│
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 子页面 (NavDestination) │
│ - DictionaryPage │
│ - PositionDetailPage │
│ - ExamPage │
└─────────────────────────────────────┘
实战二:创建 Navigation 容器
第一步:定义路由参数接口
// common/Types.ets
export interface NavRouteParams {
id?: number;
name?: string;
dynasty?: string;
data?: object;
}
第二步:创建主页面
// pages/MainPage.ets
import { HomePage } from './HomePage';
import { DictionaryPage } from './DictionaryPage';
import { PositionDetailPage } from './PositionDetailPage';
@Entry
@Component
struct MainPage {
@Provide('mainNavPathStack') navStack: NavPathStack = new NavPathStack();
@Builder
mainRouter(name: string, param?: NavRouteParams) {
if (name === 'HomePage') {
HomePage()
} else if (name === 'DictionaryPage') {
DictionaryPage()
} else if (name === 'PositionDetailPage') {
PositionDetailPage()
}
}
build() {
Navigation(this.navStack) {
// 默认显示首页
HomePage()
}
.navDestination(this.mainRouter)
.hideTitleBar(true)
.mode(NavigationMode.Stack)
}
}
第三步:理解关键配置
| 配置 | 说明 |
|---|---|
| @Provide | 向子组件提供路由栈 |
| navDestination | 绑定路由映射函数 |
| hideTitleBar | 隐藏默认标题栏 |
| NavigationMode.Stack | 栈式导航模式 |
实战三:创建子页面
第一步:子页面基本结构
// pages/DictionaryPage.ets
@Component
export struct DictionaryPage {
@Consume('mainNavPathStack') navStack: NavPathStack;
build() {
NavDestination() {
Column() {
// 顶部导航栏
Row() {
Image($r('app.media.ic_back'))
.width(24)
.height(24)
.onClick(() => {
this.navStack.pop();
})
Text('职官词典')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#1e293b')
.margin({ left: 16 })
Blank()
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor(Color.White)
// 页面内容
this.ContentView()
}
.width('100%')
.height('100%')
.backgroundColor('#f8f6f5')
}
.hideTitleBar(true)
}
@Builder
ContentView() {
// 页面具体内容
}
}
// 导出 Builder 函数
@Builder
export function DictionaryPageBuilder() {
DictionaryPage()
}
第二步:接收路由参数
// pages/PositionDetailPage.ets
@Component
export struct PositionDetailPage {
@Consume('mainNavPathStack') navStack: NavPathStack;
@State positionName: string = '';
@State dynasty: string = '';
aboutToAppear() {
// 获取路由参数
const params = this.navStack.getParamByName('PositionDetailPage');
if (params && params.length > 0) {
const param = params[0] as NavRouteParams;
this.positionName = param.name || '';
this.dynasty = param.dynasty || '';
}
}
build() {
NavDestination() {
Column() {
// 顶部导航栏
Row() {
Image($r('app.media.ic_back'))
.width(24)
.height(24)
.onClick(() => {
this.navStack.pop();
})
Text(this.positionName)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#1e293b')
.margin({ left: 16 })
Blank()
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor(Color.White)
// 详情内容
Column({ space: 16 }) {
Text(`官职:${this.positionName}`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#c41e3a')
Text(`朝代:${this.dynasty}`)
.fontSize(16)
.fontColor('#64748b')
}
.width('100%')
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor('#f8f6f5')
}
.hideTitleBar(true)
}
}
@Builder
export function PositionDetailPageBuilder() {
PositionDetailPage()
}
实战四:路由操作
第一步:跳转页面
// 无参数跳转
this.navStack.pushPathByName('DictionaryPage', {});
// 带参数跳转
this.navStack.pushPathByName('PositionDetailPage', {
name: '丞相',
dynasty: '秦'
} as NavRouteParams);
第二步:返回上一页
// 返回上一页
this.navStack.pop();
// 返回到指定页面
this.navStack.popToName('HomePage');
// 返回到根页面
this.navStack.clear();
第三步:替换当前页
// 替换当前页面
this.navStack.replacePath({
name: 'ResultPage',
param: { score: 100 }
});
第四步:获取路由信息
// 获取栈深度
const size = this.navStack.size();
// 获取参数
const params = this.navStack.getParamByName('PageName');
// 获取所有页面名称
const names = this.navStack.getAllPathName();
实战五:完整导航架构
第一步:创建完整的 MainPage
// pages/MainPage.ets
import { NavRouteParams } from '../common/Types';
@Entry
@Component
struct MainPage {
@Provide('mainNavPathStack') navStack: NavPathStack = new NavPathStack();
@Builder
mainRouter(name: string, param?: NavRouteParams) {
if (name === 'HomePage') {
HomePageBuilder()
} else if (name === 'DictionaryPage') {
DictionaryPageBuilder()
} else if (name === 'PositionDetailPage') {
PositionDetailPageBuilder()
} else if (name === 'ExamPage') {
ExamPageBuilder()
} else if (name === 'MatcherPage') {
MatcherPageBuilder()
} else if (name === 'NewYearCustomPage') {
NewYearCustomPageBuilder()
}
}
build() {
Navigation(this.navStack) {
HomePageBuilder()
}
.navDestination(this.mainRouter)
.hideTitleBar(true)
.mode(NavigationMode.Stack)
}
}
第二步:首页带底部导航
// pages/HomePage.ets
@Component
export struct HomePage {
@Consume('mainNavPathStack') navStack: NavPathStack;
@State currentTab: number = 0;
build() {
NavDestination() {
Column() {
// 内容区域
Stack() {
if (this.currentTab === 0) {
this.HomeContent()
} else if (this.currentTab === 1) {
this.ExploreContent()
} else {
this.MineContent()
}
}
.layoutWeight(1)
// 底部导航栏
Row() {
this.TabItem('首页', $r('app.media.ic_home'), 0)
this.TabItem('探索', $r('app.media.ic_explore'), 1)
this.TabItem('我的', $r('app.media.ic_person'), 2)
}
.width('100%')
.height(56)
.backgroundColor(Color.White)
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.height('100%')
}
.hideTitleBar(true)
}
@Builder
TabItem(title: string, icon: Resource, index: number) {
Column({ space: 4 }) {
Image(icon)
.width(24)
.height(24)
.fillColor(this.currentTab === index ? '#c41e3a' : '#9ca3af')
Text(title)
.fontSize(12)
.fontColor(this.currentTab === index ? '#c41e3a' : '#9ca3af')
}
.onClick(() => {
this.currentTab = index;
})
}
@Builder
HomeContent() {
Scroll() {
Column({ space: 16 }) {
// 功能入口
this.FeatureCard('职官词典', '查阅八朝官职', () => {
this.navStack.pushPathByName('DictionaryPage', {});
})
this.FeatureCard('古今匹配', '找到你的古代职业', () => {
this.navStack.pushPathByName('MatcherPage', {});
})
this.FeatureCard('科举考试', '体验古代科举', () => {
this.navStack.pushPathByName('ExamPage', {});
})
}
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor('#f8f6f5')
}
@Builder
FeatureCard(title: string, desc: string, onClick: () => void) {
Row() {
Column({ space: 4 }) {
Text(title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#1e293b')
Text(desc)
.fontSize(13)
.fontColor('#64748b')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Image($r('app.media.ic_chevron_right'))
.width(20)
.height(20)
.fillColor('#9ca3af')
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
.onClick(onClick)
}
@Builder
ExploreContent() {
Column() {
Text('探索')
.fontSize(18)
.fontColor('#1e293b')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#f8f6f5')
}
@Builder
MineContent() {
Column() {
Text('我的')
.fontSize(18)
.fontColor('#1e293b')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#f8f6f5')
}
}
@Builder
export function HomePageBuilder() {
HomePage()
}
第三步:运行验证
hvigorw assembleHap --no-daemon
本课小结
核心知识点
| 知识点 | 说明 |
|---|---|
| Navigation | 路由容器组件 |
| NavPathStack | 路由栈管理 |
| NavDestination | 目标页面包装 |
| @Provide/@Consume | 路由栈传递 |
| pushPathByName | 跳转并传参 |
| pop | 返回上一页 |
Navigation 迁移检查清单
| 步骤 | 说明 |
|---|---|
| 1 | 创建 MainPage 作为容器 |
| 2 | 定义 NavRouteParams 接口 |
| 3 | 实现 mainRouter 映射 |
| 4 | 子页面添加 @Consume |
| 5 | 子页面用 NavDestination 包裹 |
| 6 | 导出 Builder 函数 |
| 7 | 替换 router 调用 |
课后练习
练习1:实现页面返回确认
在返回时弹出确认对话框。
练习2:实现路由拦截
在跳转前检查登录状态。
下一课预告
第19课我们将学习 WebView 与混合开发,包括:
- Web 组件基础
- JavaScript 与 ArkTS 通信
- ECharts 地图集成
项目开源地址
更多推荐



所有评论(0)