一、鸿蒙页面路由核心概念
1. 路由基础与配置
鸿蒙通过@ohos/router模块实现页面跳转,核心前提是在main_pages.json中注册页面路径(所有跳转页面必须配置):
| // main_pages.json{ "src": [ "pages/TaskListPage", // 任务列表页(首页) "pages/TaskDetailPage" // 任务详情页 ]} |
|---|
路由核心 API 说明:
| API | 作用 | 关键参数 |
|---|---|---|
| router.pushUrl() | 打开新页面(入栈) | url(页面路径)、params(传递参数) |
| router.backUrl() | 返回上一页(出栈) | params(返回时携带参数) |
| router.clear() | 清空路由栈 | - |
2. 页面参数传递
正向传递(列表页→详情页):通过pushUrl的params携带数据(支持 string/number/boolean/object 类型)
反向传递(详情页→列表页):通过backUrl的params携带返回数据,列表页通过onPageShow接收
二、跨组件状态管理:@Link 与 @Provide/@Consume
单页应用中@State足够使用,但多页 / 跨组件场景需以下装饰器:
1. @Link:父子组件双向绑定
作用:实现父子组件数据同步(修改子组件数据会同步到父组件,反之亦然)
使用场景:详情页修改任务状态,同步到列表页(父子页面关系)
语法:父组件传递时加$,子组件用@Link接收
2. @Provide/@Consume:跨层级数据共享
作用:解决多层嵌套组件的数据传递(无需层层传递参数)
使用场景:全局任务列表数据共享(列表页→详情页→子组件)
语法:@Provide(提供方,如列表页)声明数据,@Consume(消费方,如详情页子组件)接收,二者通过相同的「别名」关联
三、实战:开发任务清单 APP(完整代码)
1. 需求说明
列表页(TaskListPage):展示所有任务,点击任务进入详情页,支持新增任务
详情页(TaskDetailPage):编辑任务标题、切换完成状态,返回后列表页同步更新
状态同步:详情页修改任务后,列表页实时刷新
2. 步骤 1:定义任务数据模型
新建model/TaskModel.ets,统一数据结构:
| // model/TaskModel.etsexport interface Task { id: string; // 任务唯一ID title: string; // 任务标题 isCompleted: boolean; // 完成状态} |
|---|
3. 步骤 2:任务列表页(TaskListPage)
作为路由首页和数据提供方,使用@Provide共享任务列表:
// pages/TaskListPage.etsimport router from '@ohos/router';import { Task } from '../model/TaskModel';import { FlexAlign, ItemAlign } from '@ohos/ui';@Componentexport struct TaskListPage { // 提供全局任务数据(供详情页消费) @Provide('taskList') taskList: Task[] = [ { id: '1', title: '学习鸿蒙路由', isCompleted: false }, { id: '2', title: '掌握@Link状态绑定', isCompleted: true } ]; // 接收详情页返回的参数 onPageShow() { const params = router.getParams(); if (params?.updatedTask) { // 详情页修改后,更新列表数据 const updatedTask = params.updatedTask as Task; this.taskList = this.taskList.map(task => task.id === updatedTask.id ? updatedTask : task ); } } // 新增任务(简化逻辑) addTask() { this.taskList.push({ id: Date.now().toString(), title: 新任务${this.taskList.length + 1}, isCompleted: false }); } build() { Column({ space: 20 }) .width('100%') .height('100%') .padding(30) .backgroundColor('#f5f5f5') { // 标题与新增按钮 Row({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { Text('任务清单') .fontSize(32) .fontWeight(FontWeight.Bold) Button('新增任务') .type(ButtonType.Capsule) .backgroundColor('#4a6cf7') .onClick(() => this.addTask()) } // 任务列表 List({ space: 15 }) { ForEach(this.taskList, (task: Task) => { ListItem() { Row({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) .width('100%') .padding(20) .backgroundColor('#ffffff') .borderRadius(12) .onClick(() => { // 跳转到详情页,传递当前任务(正向参数) router.pushUrl({ url: 'pages/TaskDetailPage', params: { task: task } }); }) { // 任务标题(完成状态划横线) Text(task.title) .fontSize(22) .fontColor(task.isCompleted ? '#999999' : '#333333') .textDecoration(task.isCompleted ? TextDecorationType.LineThrough : TextDecorationType.None) // 完成状态图标 Image(task.isCompleted ? r('app.media.uncheck') ) .width(30) .height(30) } } }) } } }} |
|---|
4. 步骤 3:任务详情页(TaskDetailPage)
接收列表页参数,使用@Consume获取全局任务,@Link绑定当前任务:
| // pages/TaskDetailPage.etsimport router from '@ohos/router';import { Task } from '../model/TaskModel';import { FlexAlign, ItemAlign } from '@ohos/ui';@Componentexport struct TaskDetailPage { // 接收列表页传递的任务参数 private task: Task = router.getParams().task as Task; // 双向绑定任务(修改后同步到列表页) @Link currentTask: Task = this.task; // 消费全局任务列表(用于获取最新数据) @Consume('taskList') taskList: Task[]; build() { Column({ space: 40 }) .width('100%') .height('100%') .padding(30) .backgroundColor('#f5f5f5') { // 任务标题输入框 TextInput({ placeholder: '输入任务标题', text: this.currentTask.title }) .width('100%') .height(60) .padding(20) .backgroundColor('#ffffff') .borderRadius(12) .fontSize(22) .onChange((value: string) => { // 修改标题,双向绑定同步 this.currentTask.title = value; }) // 完成状态切换 Row({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Text('标记为已完成') .fontSize(22) .fontColor('#333333') Switch() .checked(this.currentTask.isCompleted) .onChange((isChecked: boolean) => { // 切换状态,双向绑定同步 this.currentTask.isCompleted = isChecked; }) } // 返回按钮(携带修改后的任务返回列表页) Button('保存并返回') .type(ButtonType.Capsule) .width(250) .height(60) .fontSize(22) .backgroundColor('#4a6cf7') .onClick(() => { // 反向传递参数,通知列表页更新 router.backUrl({ params: { updatedTask: this.currentTask } }); }) } }} |
|---|
5. 关键代码说明
(1)路由跳转与参数传递
列表页→详情页:router.pushUrl传递task对象,详情页通过router.getParams()接收
详情页→列表页:router.backUrl传递updatedTask,列表页在onPageShow中接收并更新列表
(2)状态同步核心
@Provide('taskList'):列表页提供全局任务数据,详情页通过@Consume('taskList')接收,确保数据一致性
@Link currentTask:详情页与列表页的任务对象双向绑定,修改currentTask会直接同步到列表页的taskList
四、常见问题与解决方案
1. 页面跳转失败
检查main_pages.json是否注册目标页面路径
确保pushUrl的url路径与配置一致(如pages/TaskDetailPage,不带.ets后缀)
2. 状态不同步
使用@Link时,父组件传递必须加task)
复杂对象修改后需触发引用更新,可使用扩展运算符:this.currentTask = {...this.currentTask, title: value}
3. 参数传递类型限制
不支持传递函数、Promise 等复杂类型,建议仅传递 JSON 可序列化的数据(字符串、数字、对象、数组)