当前位置: 首页 > news >正文

鸿蒙开发5--鸿蒙页面导航(声明式导航Navigation组件)

上文中我们用@ohos.router做了一个商品信息的列表和详情间的跳转页面。

但是我们发现@ohos.router是一种编程式导航。你必须在代码的某个地方调用函数router.pushUrl()来命令应用跳转到下一个页面。

而声明式导航就不一样了,核心思想是导航本身也是UI状态的一部分。我们不再发出“跳转”的命令,只需要通过改变一个状态变量来声明我们希望看到哪个页面。

一、Navigation框架的核心三要素

声明式导航主要由三个部分协同工作:

  1. <Navigation>容器:

    • 这是一个特殊的根组件,包裹了所有参与导航的页面视图。

    • 定义了一个导航的上下文或作用域。

  2. NavPathStack栈:

    • 这是一个我们需要自己定义和维护的状态变量,通常是一个数组。

    • 这个数组的内容直接决定了当前的导航路径。

      • 数组为空,显示根页面(首页)。

      • 数组中有一个元素,显示栈顶元素对应的页面。

      • 数组中有多个元素,形成一个导航层级。

    • 通过对这个数组进行.push()、.pop()等操作,来驱动UI进行页面的推入和弹出。

  3. <NavDestination>目标页:

    • 这是一个用来“注册”或“定义”可跳转目标页面的组件。

    • 我们给每个目标页面创建一个NavDestination,通过他的builder来指定该页面具体长什么样。

二、重构商品应用页面

我们把之前的商品应用页面重构一下。

2.1. 创建模块

同样的,我们先创建一个模块day5_navigation。

image-20251009094810270

在src/main/ets/pages目录下,创建两个UI Page文件:ProductListPage.ets、ProductDetailPage.ets(Index.ets可以删除)

image-20251009095008895

记得把Day5_navigationAbility.ets中UIAbility的入口页面修改了。

image-20251009095251387

2.2. 定义数据模型和导航栈

为了在页面间传递数据,并让代码更规范,我们先定义好数据类型。

创建一个新文件src/main/ets/models/ProductModels.ets

// 商品的数据结构export interface Product {id: string;name: string;description: string;}

2.3. 改造ProductListPage.ets(列表页)

把列表页改造成我们的导航主容器。

import { Product } from '../models/ProductModels';import { ProductDetailPage } from './ProductDetailPage';​const products: Product[] = [{ id: 'p001', name: '鸿蒙智能手表', description: '最新款,搭载HarmonyOS NEXT。' },{ id: 'p002', name: 'ArkUI T恤', description: '开发者信仰充值,100%纯棉。' },{ id: 'p003', name: 'DevEco Studio贴纸', description: '让你的笔记本充满极客范。' },{ id: 'p004', name: '手机', description: '拍个月球给你看。' }];​@Entry@Componentstruct ProductListPage {@State path: NavPathStack = new NavPathStack();​@BuilderdestinationBuilder(name: string, param: object) {if (name === 'ProductDetail') {NavDestination() {ProductDetailPage({ product: param as Product })}.title('产品详情')} else {NavDestination() {Text('Invalid destination').fontSize(16).fontColor(Color.Red)}.title('Error')}}​build() {Navigation(this.path) {Column() {List({ space: 12 }) {ForEach(products, (item: Product) => {ListItem() {Text(item.name).width('100%').fontSize(20).padding(20).backgroundColor(Color.White).borderRadius(10)}.onClick(() => {this.path.pushPathByName('ProductDetail', item);})})}.width('95%').layoutWeight(1)}.width('100%').height('100%').backgroundColor('#f1f3f5').padding({ top: 10 })}.title('商品列表').navDestination(this.destinationBuilder)}}

使用import导入了Product数据模型和ProductDetailPage组件。

@State path: NavPathStack是整个声明式导航的核心。

定义了一个名叫path的变量,类型是NavPathStack,这是一个专门用来管理导航路径的特殊对象。

@State装饰器就是告诉ArkUI框架,要关注path这个变量,如果发生了变化,就要自动刷新所有依赖他的UI。

@Builder也是一个装饰器,表示destinationBuilder方法不是一个普通的逻辑函数,是一个专门用来构建UI片段的模版。

destinationBuilder(name: string, param: object)构造器接收两个参数,这两个参数都是path.pushPathByName方法在跳转的时候提供的。

name是路由目标的名称,用他来区分跳转到哪个页面。

param是携带的参数,是一个通用的object。

NavDestination()是真正定义目标导航页的容器。所有可以被导航到的页面,都必须被他包裹。

在NavDestination内部,我们创建了ProductDetailPage组件的实例。param as Product是一个类型断言,明确告诉编译器:虽然param是object类型,但确定他实际上是一个Product对象,然后把他传递给详情页的product属性。

.title('产品详情')就是给这个目标页设置导航栏的标题。

Navigation(this.path)是导航的根容器,我们把@State变量this.path传给他,建立双向绑定。当path改变时,Navigation组件会自动更新视图;当用户在UI上进行返回操作时,Navigation组件也会自动更新path变量。

这里的.title('商品列表')是根页面(也就是列表页自身)设置导航栏标题。

.navDestination(this.destinationBuilder)是关键的一步。我们把刚才用@Builder定义的destinationBuilder方法,注册给了Navigation容器。这样Navigation就知道当path发生变化时,应该调用哪个模版去构建目标页面。

当用户点击列表项时,我们不再调用router,而是直接修改状态。

this.path.pushPathByName('ProductDetail', item)调用path对象的pushPathByName方法。

ProductDetail这个字符串会作为name参数传递给我们的destinationBuilder。

item是当前点击的商品对象(Product类型),会作为param参数传递给destinationBuilder。

一旦这行代码执行,@State变量path的内容就变了,ArkUI框架侦测到这个变化,就会自动使用destinationBuilder去构建ProductDetailPage并显示出来。

2.4. 改造ProductDetailPage.ets(详情页)

这个页面比较简单,只负责一件事,就是接收一个Product对象,显示出来。

 import { Product } from '../models/ProductModels';@Entry@Componentexport struct ProductDetailPage {@Prop product: Product;​build() {Column() {Text(this.product.name).fontSize(28).fontWeight(FontWeight.Bold).margin(20)Text(this.product.description).fontSize(18).fontColor(Color.Gray).margin({ left: 20, right: 20 })}.width('100%').height('100%').justifyContent(FlexAlign.Start).padding(15)}}

@Prop product: Product;是子组件接收父组件传递数据的标准方式。

@Prop装饰器声明product是一个外部属性,他的值由创建ProductDetailPage的地方(也就是destinationBuilder)提供。

这样就建立了一个从父到子的单向数据流。

在build函数中,我们可以像使用普通成员变量一样,直接通过this.product.name和this.product.description来访问由@Prop传入的数据,并把他们渲染成UI。

2.5. 改造后界面

列表

image-20251009120224417

详情

http://www.dtcms.com/a/461762.html

相关文章:

  • sql题目练习——单表查询
  • html怎么做成网站多软件网站下载安装
  • 做网站服务销售wordpress user level
  • 【C++贪心】P10537 [APIO2024] 九月|普及+
  • 大模型问答原理解析
  • 【二叉树的递归算法与层序遍历算法】
  • 【STM32】I2C通信—软件模拟
  • 公司网站怎么修改内容wordpress 4.7.2 中文
  • 怎么建手机网站seo新方法
  • 第六章 QT和OPENCV交叉编译开发环境以及QT远程调试
  • hello_mybatis
  • 【大模型理论篇】MCP协议中sse、stdio、streamable_http含义
  • Git 小白超详细指南
  • 深度学习基础:从原理到实践——第二章神经网络(上)
  • 企业网站制作报价单哈尔滨视频剪辑培训机构
  • SOME/IP车载服务的形式化安全分析和防护
  • TCP三次握手与四次挥手状态解析
  • 网站想换空间invoker wordpress
  • Eureka注册中心
  • 网站建设销售总结房屋装修在线设计网站
  • 机器学习基本概念
  • Buffer:Node.js 里处理二进制数据的 “小工具”
  • 网站开发博客大前端d8扁平化wordpress模板
  • Go 语言环境安装指南
  • UiPath2025笔记第六节:java调试API触发器
  • Python实现自动化巡检ESXi6.7并输出excel报告
  • wordpress手机显示不了图片关键词优化计划
  • Python学习之基础篇
  • 手机app开发 网站建设描述网站开发的广告词
  • 24届-Python面经(华为OD)