第9篇:页面跳转——多页面应用开发 鸿蒙中文编程
本文介绍了多页面应用开发的核心概念和实践方法。主要内容包括:1)页面路由的基本概念,通过@ohos.router模块实现页面跳转;2)使用@Entry装饰器标记页面入口;3)两种跳转方式(pushUrl和replaceUrl)的区别与应用场景;4)页面间参数传递的实现方法;5)返回上一页的不同操作方式。文章还提供了完整的示例代码,展示如何构建包含首页、详情页和设置页的三页面应用,涵盖列表展示、参数
第9篇:页面跳转——多页面应用开发
本课目标:掌握页面路由和导航,能开发多页面应用
**作者:**中文编程倡导者—— 李金雨
预计课时:2课时(90分钟)
难度等级:⭐⭐⭐(进阶)
一、开篇引入
1.1 从单页面到多页面
前面的课程,我们做的应用都只有一个页面。但真正的应用通常有多个页面:
微信App:
├── 首页(聊天列表)
├── 通讯录
├── 发现
├── 我
└── 聊天详情页
淘宝App:
├── 首页
├── 分类
├── 购物车
├── 我的淘宝
└── 商品详情页
1.2 页面之间的关系
首页 ──→ 详情页 ──→ 评论页
│
└──→ 设置页 ──→ 关于页
- 跳转:从A页面到B页面
- 传参:把数据从A页面带到B页面
- 返回:从B页面回到A页面
1.3 本课目标
今天我们要学习:
- 什么是页面路由
- 怎么跳转到新页面
- 怎么传递参数
- 怎么返回上一页
- 实战:实现多页面应用
1.4 预期成果
完成本课后,你能做出这样的多页面应用:
首页 详情页 设置页
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 首页 >│ │ < 详情 │ │ < 设置 │
├─────────────┤ ├─────────────┤ ├─────────────┤
│ │ │ │ │ │
│ [商品1] │──点击──→│ 商品详情 │ │ 账号设置 │
│ │ │ ¥199 │ │ 通知设置 │
│ [商品2] │──点击──→│ [购买] │ │ 隐私设置 │
│ │ │ │ │ │
│ [商品3] │ │ [去设置] │──点击──→│ [关于我们] │──点击──→
│ │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
二、概念讲解
2.1 什么是页面路由?
定义
路由(Router)就是管理页面之间跳转的系统。
就像导航仪:
- 知道你在哪里(当前页面)
- 知道你要去哪里(目标页面)
- 规划路线(跳转方式)
ArkTS中的路由
ArkTS使用 @ohos.router 模块来管理页面跳转:
import router from '@ohos.router'
2.2 @Entry装饰器
什么是@Entry?
@Entry 标记一个组件是页面入口,可以被路由跳转。
@Entry // 标记这是页面入口
@Component
struct 首页 {
build() {
// 页面内容
}
}
页面文件结构
entry/src/main/ets/pages/
├── Index.ets // 首页(默认页面)
├── 详情页.ets // 详情页
├── 设置页.ets // 设置页
└── 关于页.ets // 关于页
注意:页面文件必须放在 pages 目录下!
2.3 页面跳转
pushUrl——普通跳转
import router from '@ohos.router'
// 跳转到新页面
router.pushUrl({
url: 'pages/详情页' // 目标页面路径
})
特点:
- 新页面覆盖当前页面
- 可以返回上一页
- 页面会入栈
replaceUrl——替换跳转
router.replaceUrl({
url: 'pages/详情页'
})
特点:
- 替换当前页面
- 不能返回上一页(上一页被替换了)
- 用于登录后跳转到首页等场景
跳转方式对比
| 方式 | 能否返回 | 使用场景 |
|---|---|---|
| pushUrl | 能 | 正常页面跳转 |
| replaceUrl | 不能 | 登录后跳转、不需要返回的跳转 |
2.4 页面传参
传递参数
// 从首页跳转到详情页,带上商品ID
router.pushUrl({
url: 'pages/详情页',
params: { // 传递的参数
商品ID: '12345',
商品名: '手机',
价格: 2999
}
})
接收参数
@Entry
@Component
struct 详情页 {
// 获取传递过来的参数
@State 商品信息: object = router.getParams()
build() {
Column() {
// 使用参数
Text(`商品:${this.商品信息?.['商品名']}`)
Text(`价格:¥${this.商品信息?.['价格']}`)
}
}
}
参数类型
// 可以传递各种类型的参数
router.pushUrl({
url: 'pages/目标页',
params: {
字符串: 'Hello',
数字: 123,
布尔值: true,
数组: [1, 2, 3],
对象: { a: 1, b: 2 }
}
})
2.5 返回上一页
基本返回
import router from '@ohos.router'
// 返回上一页
router.back()
返回到指定页面
// 返回到首页
router.back({
url: 'pages/Index'
})
返回并传参
// 返回并带上结果
router.back({
url: 'pages/首页',
params: {
操作结果: '成功',
选择项: '选项A'
}
})
2.6 获取页面信息
获取当前页面路径
let 当前页面 = router.getState().path
console.log('当前在:' + 当前页面)
获取页面栈信息
let 页面栈 = router.getState()
console.log('页面数量:' + 页面栈.length)
三、动手实践
3.1 基础练习:简单的三页面应用
创建三个页面:首页、详情页、设置页
首页(Index.ets):
import router from '@ohos.router'
// 完整可运行代码,复制到 Index.ets 即可运行
@Entry
@Component
struct Index {
@State 商品列表: object[] = [
{ id: '1', 名称: '无线耳机', 价格: 299 },
{ id: '2', 名称: '智能手表', 价格: 599 },
{ id: '3', 名称: '便携音箱', 价格: 199 }
]
build() {
Column() {
// 标题栏
Row() {
Text('🏠 首页')
.fontSize(22)
.fontWeight(FontWeight.Bold)
Button('设置')
.fontSize(14)
.backgroundColor('transparent')
.fontColor('#2196F3')
.onClick(() => {
this.去设置页()
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding(20)
.backgroundColor('#FFFFFF')
// 商品列表
List({ space: 15 }) {
ForEach(this.商品列表, (商品: object) => {
ListItem() {
Row({ space: 15 }) {
Text('📦')
.fontSize(40)
Column({ space: 5 }) {
Text(商品.名称)
.fontSize(18)
.fontWeight(FontWeight.Medium)
Text(`¥${商品.价格}`)
.fontSize(16)
.fontColor('#F44336')
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
Text('>')
.fontSize(20)
.fontColor('#CCCCCC')
}
.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(10)
.onClick(() => {
this.去详情页(商品)
})
}
})
}
.padding(15)
.layoutWeight(1)
.backgroundColor('#F5F5F5')
}
.width('100%')
.height('100%')
}
去详情页(商品: object) {
router.pushUrl({
url: 'pages/详情页',
params: {
商品: 商品
}
})
}
去设置页() {
router.pushUrl({
url: 'pages/设置页'
})
}
}
详情页(详情页.ets):
import router from '@ohos.router'
@Entry// 详情页
// 完整可运行代码,复制到 Index.ets 即可运行
@Component
struct Index {
@State 商品信息: object = router.getParams()?.['商品'] || {}
build() {
Column() {
// 标题栏
Row() {
Text('< 返回')
.fontSize(16)
.fontColor('#2196F3')
.onClick(() => {
router.back()
})
Text('商品详情')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Blank() // 占位,让标题居中
}
.width('100%')
.padding(20)
.backgroundColor('#FFFFFF')
// 商品信息
Column({ space: 20 }) {
Text('📦')
.fontSize(100)
.margin(30)
Text(this.商品信息?.['名称'] || '未知商品')
.fontSize(28)
.fontWeight(FontWeight.Bold)
Text(`¥${this.商品信息?.['价格'] || 0}`)
.fontSize(32)
.fontColor('#F44336')
.fontWeight(FontWeight.Bold)
Text('这是商品的详细介绍...')
.fontSize(14)
.fontColor('#666666')
.margin(20)
Button('立即购买', { type: ButtonType.Capsule })
.width('80%')
.height(50)
.backgroundColor('#2196F3')
.margin({ top: 30 })
}
.width('100%')
.layoutWeight(1)
.backgroundColor('#F5F5F5')
}
.width('100%')
.height('100%')
}
}
设置页(设置页.ets):
import router from '@ohos.router'// 设置页
// 完整可运行代码,复制到 Index.ets 即可运行
@Entry
@Component
struct Index {
build() {
Column() {
// 标题栏
Row() {
Text('< 返回')
.fontSize(16)
.fontColor('#2196F3')
.onClick(() => {
router.back()
})
Text('设置')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Blank()
}
.width('100%')
.padding(20)
.backgroundColor('#FFFFFF')
// 设置列表
Column({ space: 1 }) {
this.设置项('账号与安全')
this.设置项('通知设置')
this.设置项('隐私设置')
this.设置项('通用设置')
this.设置项('关于我们')
this.设置项('退出登录', '#F44336')
}
.margin(20)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.clip(true)
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
@Builder
设置项(标题: string, 颜色: string = '#333333') {
Row() {
Text(标题)
.fontSize(16)
.fontColor(color)
Text('>')
.fontSize(16)
.fontColor('#CCCCCC')
}
.width('100%')
.height(55)
.padding({ left: 20, right: 20 })
.justifyContent(FlexAlign.SpaceBetween)
.backgroundColor('#FFFFFF')
}
}
3.2 进阶练习:带返回结果的页面
选择页面(选择页.ets):
import router from '@ohos.router'
@Entry
@Component
struct 选择页 {
@State 选项列表: string[] = ['选项A', '选项B', '选项C', '选项D']
build() {
Column() {
Text('请选择一个选项')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin(30)
Column({ space: 15 }) {
ForEach(this.选项列表, (选项: string) => {
Button(选项, { type: ButtonType.Capsule })
.width('80%')
.height(50)
.backgroundColor('#2196F3')
.onClick(() => {
this.返回结果(选项)
})
})
}
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
返回结果(选择: string) {
router.back({
params: {
选择结果: 选择
}
})
}
}
主页面接收结果:
import router from '@ohos.router'
@Entry
@Component
struct 主页面 {
@State 选择结果: string = '未选择'
build() {
Column({ space: 30 }) {
Text(`当前选择:${this.选择结果}`)
.fontSize(20)
.margin(50)
Button('去选择')
.onClick(() => {
router.pushUrl({
url: 'pages/选择页'
})
})
}
}
// 页面显示时检查是否有返回参数
onPageShow() {
let 参数 = router.getParams()
if (参数?.['选择结果']) {
this.选择结果 = 参数['选择结果']
}
}
}
3.3 进阶练习:底部导航栏
实现带底部导航的多页面应用:
import router from '@ohos.router'
@Entry
@Component
struct 带导航的首页 {
@State 当前标签: number = 0
标签列表: object[] = [
{ 名称: '首页', 图标: '🏠' },
{ 名称: '分类', 图标: '📂' },
{ 名称: '购物车', 图标: '🛒' },
{ 名称: '我的', 图标: '👤' }
]
build() {
Column() {
// 内容区域
Stack() {
// 根据当前标签显示不同内容
if (this.当前标签 == 0) {
this.首页内容()
} else if (this.当前标签 == 1) {
this.分类内容()
} else if (this.当前标签 == 2) {
this.购物车内容()
} else {
this.我的内容()
}
}
.width('100%')
.layoutWeight(1)
// 底部导航栏
Row() {
ForEach(this.标签列表, (标签: object, 索引: number) => {
Column({ space: 5 }) {
Text(标签.图标)
.fontSize(24)
Text(标签.名称)
.fontSize(12)
}
.width('25%')
.height(60)
.fontColor(this.当前标签 == 索引 ? '#2196F3' : '#999999')
.onClick(() => {
this.当前标签 = 索引
})
})
}
.width('100%')
.height(70)
.backgroundColor('#FFFFFF')
.border({ width: { top: 1 }, color: '#EEEEEE' })
}
.width('100%')
.height('100%')
}
@Builder
首页内容() {
Column() {
Text('首页内容')
.fontSize(30)
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
.justifyContent(FlexAlign.Center)
}
@Builder
分类内容() {
Column() {
Text('分类内容')
.fontSize(30)
}
.width('100%')
.height('100%')
.backgroundColor('#E3F2FD')
.justifyContent(FlexAlign.Center)
}
@Builder
购物车内容() {
Column() {
Text('购物车内容')
.fontSize(30)
}
.width('100%')
.height('100%')
.backgroundColor('#FFF3E0')
.justifyContent(FlexAlign.Center)
}
@Builder
我的内容() {
Column() {
Text('我的内容')
.fontSize(30)
}
.width('100%')
.height('100%')
.backgroundColor('#E8F5E9')
.justifyContent(FlexAlign.Center)
}
}
四、知识总结
4.1 核心概念回顾
- 路由:管理页面跳转的系统
- @Entry:标记页面入口
- pushUrl:普通跳转(可返回)
- replaceUrl:替换跳转(不可返回)
- params:页面间传递参数
- back:返回上一页
4.2 路由API速查
import router from '@ohos.router'
// 普通跳转
router.pushUrl({ url: 'pages/目标页' })
// 带参数跳转
router.pushUrl({
url: 'pages/目标页',
params: { 键: 值 }
})
// 替换跳转
router.replaceUrl({ url: 'pages/目标页' })
// 返回上一页
router.back()
// 返回到指定页
router.back({ url: 'pages/首页' })
// 获取参数
let 参数 = router.getParams()
// 获取当前页面信息
let 状态 = router.getState()
4.3 页面生命周期
| 方法 | 触发时机 |
|---|---|
aboutToAppear() |
页面即将显示 |
onPageShow() |
页面显示时 |
onPageHide() |
页面隐藏时 |
aboutToDisappear() |
页面即将销毁 |
4.4 常见错误提醒
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
| 跳转失败 | 页面路径错误 | 检查pages目录下的文件名 |
| 参数为undefined | 没传参数或key错误 | 检查params和getParams的key |
| 返回后数据没更新 | 没使用onPageShow | 在onPageShow中处理返回数据 |
| 无法返回 | 用了replaceUrl | 改用pushUrl |
五、课后作业
5.1 巩固练习(必做)
练习1:登录流程
实现登录流程:
- 登录页 → 首页(replaceUrl,防止返回登录页)
- 首页可以跳转到设置页
- 设置页可以退出登录,返回登录页
练习2:商品浏览
实现商品浏览功能:
- 商品列表页
- 点击商品进入详情页(传递商品ID)
- 详情页可以查看评论(再跳转)
练习3:表单填写
实现多步表单:
- 第一步:填写基本信息
- 第二步:填写详细信息
- 第三步:确认提交
- 每步可以返回修改
5.2 创意编程(选做)
创意1:新闻阅读App
- 新闻列表页
- 新闻详情页
- 评论页面
- 个人中心
创意2:电商购物流程
- 商品浏览 → 商品详情 → 加入购物车
- 购物车 → 确认订单 → 支付页面
- 支付成功 → 订单详情
创意3:社交应用
- 好友列表 → 聊天页面
- 发现页面 → 动态详情
- 个人主页 → 编辑资料
5.3 下篇预习
下一篇,我们将学习网络请求,从服务器获取数据。预习问题:
- 怎么从网络获取数据?
- 什么是HTTP请求?
- 怎么处理异步操作?
恭喜你完成了第9篇的学习! 🎉
现在你已经掌握了页面跳转,可以开发多页面应用了。记住:路由让应用有结构,页面让功能更清晰!
下节课,我们将学习如何从网络获取数据!
更多推荐




所有评论(0)