HarmonyOS开发 :Router 和 NavPatchStatck 如何实现跳转(传参)及页面回调

news2024/11/20 16:27:18

路由的选择

HarmonyOS提供两种路由实现的方式,分别是 RouterNavPatchStack。两者使用场景和特效各有优劣。

组件适用场景特点备注
Router模块间与模块内页面切换通过每个页面的url实现模块间解耦
NavPathStack模块内页面切换通过组件级路由统一路由管理
  • 什么时候使用 NavPatchStack ?

如果是单包应用开发,不使用动态包(hsp)进行拆包,只是使用静态包(har)简单的进行模块拆分,那么我推荐使用 navPatchStack

  • 什么时候使用 Router ?

如果像开发 鸿蒙元服务,对单包体积有 2M 的限制,那么我们不得不使用动态包的方式。将相对独立的功能,二级页面等拆分出去,封装成动态包,可避开 dependencies 直接依赖得引用形式。

此时使用 router 跳转 url 的方式才可跳转到动态包内非直接引用的页面

NavPatchStatck 如何跳转(传参)及页面回调

NavPathStack 是配合 Navigation 一起使用的, Navigation导航组件做统一的页面跳转管理,它提供了一系列属性方法来设置页面的标题栏、工具栏以及菜单栏的各种展示样式。

如何跳转(传参)及实现页面回调?

//第一步:定义一个用于传参和实现页面回调的模型
export interface RouterModel {
  params?: Object, // 要传递给跳转页面的参数
  popCallback?: (value: Object | undefined) => void // 用于页面回调
}
//第二步,需要在应用的根页面自行维护 navStack 实例,并传递给根节点 Navigation
@Provide('navPathStack') navPathStack: NavPathStack = new NavPathStack()

Navigation(this.pageInfos) {
  Column() {}
}
.title('NavIndex')
.navDestination(this.PageMap)


// 统一管理维护路由跳转
@Builder
  PageMap(name: string, params: RouterModel) {
    if (name === 'pageOne') {
      TestNavPathPage({ // TestNavPathPage 就是要跳转的目标页面
        routerParams: params
      })
    } else {
      // 默认空页面
    }
}

/// 任意一个页面获取 navPathStack 调用跳转并传参
@Component
export struct RouterCallbackExample {
  @Consume('navPathStack') navPathStack: NavPathStack;
 

  // NavPatchStack 方式跳转并获取回调
  navPathStackJump() {
    const routerParams: RouterModel = {
      params: '我是入参 123', //传递到跳转页面的入参
      popCallback: (callbackValue) => {
        // 这里拿到回调结果,注意要判断 callbackValue !== undefine
        // 这里拿到下面目标页面回传的结果 ‘我是回调的结果 345’
      }
    }
   this.navPathStack.pushPathByName('pageOne', routerParams) // 'pageOne' 对应上面 'PageMap' 方法内定义的路径名称常量
  }

  build() {
    Button('跳转').onClick(() => {
        this.navPathStackJump()
    })
  }
}

/// 目标页面接收入参、并返回页面回调
@Component
export struct TestNavPathPage {
  @Consume('navPathStack') navPathStack: NavPathStack;
  routerParams?: RouterModel
  @State receiveParams: string = ''

  aboutToAppear(): void {
    // 接收入参,这里拿到上面传入的 ‘我是入参 123’
    let receiveParams = this.routerParams!.params
  }

  build() {
    NavDestination() {
      Button('关闭页面并回调结果').onClick(() => {
        if (this.routerParams?.popCallback !== undefined) {
          this.routerParams.popCallback('我是回调的结果 345 ')
        }
        this.navPathStack.pop()
      })
    }.title('跳转目标页')
  }
}

Router 如何跳转(传参)及页面回调

Router 跳转可支持跳转本包内页面以及动态包或者拆包内的页面,

  • url 的定义举例如下:
1. 本地包内,或者直接依赖的静态包内页面,url 定义为 : pages/Page1
2. 分包内的页面,url 定义为 :@bundle:com.rex.harmony.atomic.service/featureName/ets/pages/Page2

// com.rex.harmony.atomic.service 是我的应用包名
// featureName 是跳转页面所在的模块名称,对应 module.json5 里面额 name
// ets/pages/Page2 为目标页面在模块内的页面路径,对应 main_pages.json 内的页面路径
  • url 跳转
router.pushUrl({ url: '', params: Object })
  • 注意: 使用 router + url 进行跳转的目标页面必须使用 @Entry 修饰,且在main_pages.json 文件内填写对应路径

重点:截止 API11 版本,router 支持传递的 params 传参,不是引用传递,所以在动态包内实际获取到的不是同一个对象,为了实现页面回调,router 我们需要做如下封装:

  • 如何跳转(传参)及实现页面回调?抛砖引玉 ---
  1. 在公共的har包内定义 Router 管理类 FastRouter

(在下文扩展中解释单例为什么这么实现)

import { RouterModel } from './model/RouterModel'
import { router } from '@kit.ArkUI'

/// 基于 router 库封装,为了实现页面回调
export class FastRouter {
  public readonly routerStack: RouterModel[] = []

  /// 跨 hsp 使用这种方式实现单例
  public static instance(): FastRouter {
    const storageKey = 'REX_FAST_ROUTER'
    if (!AppStorage.has(storageKey)) {
      AppStorage.setOrCreate(storageKey, new FastRouter())
    }
    return AppStorage.get<FastRouter>(storageKey)!
  }

  /// 获取路由传递的入参
  public static get getRouterCurrentParams(): RouterModel | undefined {
    const stack = FastRouter.instance().routerStack
    if (stack.length === 0) {
      return undefined
    }
    return stack[stack.length - 1]
  }

  /// push 页面
  public static async push(route: RouterModel): Promise<void> {
    try {
      await router.pushUrl({ url: route.url, params: route.params })
      FastRouter.instance().routerStack.push(route)
    } catch (_) {
      console.log('>>>>')
    }
  }

  /// replace 页面
  public static async replace(route: RouterModel): Promise<void> {
    try {
      await router.replaceUrl({ url: route.url, params: route.params })
      const instance = FastRouter.instance()
      const list = instance.routerStack
      if (list.length > 0) {
        instance.routerStack.splice(instance.routerStack.length - 1, 1, route)
      }
    } catch (_) {
      // 暂无处理
    }
  }

  /// 退出栈顶页面
  public static async pop(animated?: boolean): Promise<void> {
    router.back()
    const routerStack = FastRouter.instance().routerStack
    routerStack.pop()
  }
}
  1. 任一页面使用 FastRouter 进行 url 跳转
// 跳转到 hsp 包(feature_hsp_page)内的 TestHspHomePage 页面
const routerParams: RouterModel = {
  url: '@bundle:com.rex.harmony.atomic.service/feature_hsp_page/ets/pages/TestHspHomePage',
  params: '我是入参 1488',
  popCallback: (callbackValue) => {
    if (callbackValue !== undefined) {
      //这里获取跳转页的回调数据
      //接收到下文中目标页面的回调结果:‘我是回调的结果 6100 ’
    }
  }
}
FastRouter.push(routerParams)
  1. 在目标页面内接收入参并回调结果
@Entry
@Component
struct Index {
  routerParams?: RouterModel

  aboutToAppear(): void {
    this.routerParams = FastRouter.getRouterCurrentParams as RouterModel
    let receiveParams = this.routerParams.params //这里接收入参,也就是上面传递的 ‘我是入参 1488’
  }

  build() {
    Button('关闭页面并回调结果').onClick(() => {
      if (this.routerParams?.popCallback !== undefined) {
        this.routerParams.popCallback('我是回调的结果 6100 ')
      }
      FastRouter.pop()
    })
  }
}

总结

NavPatchStackRouter 两种路由方式各有优劣,NavPatchStack 方便统一管理,Router 方便解耦,两者没有任何关联,可以一起使用,也可以单独使用。

扩展:动态包、静态包的使用差异

说到动态包(HAR)和静态包(HSP),这里扩展一下两者的区别。

静态包的 module.json5 文件,type 标识为 har

{
  "module": {
    "name": "静态包模块名称",
    "type": "har",
    "deviceTypes": [
      "default",
      "tablet"
    ]
  }
}

静态包的 module.json5 文件,type 标识为 shared

{
  "module": {
    "name": "动态包模块名称",
    "type": "shared",
    "description": "$string:shared_desc",
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "deliveryWithInstall": true,
    "installationFree": true,
    "pages": "$profile:main_pages"
  }
}

动态包和静态包都可以被直接引用,在 oh-package.json5

{
 ...省略
  "dependencies": {
    "@rex/任意名称": "file:../../base/静态包模块名称",
    "@rex/任意名称": "file:../../base/动态包模块名称"
  }
}

重点:

  • 动态包可以不直接依赖( 例如:使用 preload ),跳转动态包内的页面可以通过 router 拼接 url 进行跳转
  • har 中的代码和资源跟随使用方编译,如果有多个使用方,存在多个 hap,也包括使用了 hsp 的场景。该 har 的编译产物中会存在多份相同拷贝。

存在两种情况,如果harA和harB都依赖harC,单个hap依赖harA、harB,那么只会存在一份harA、harB、harC;如果harA和harB都依赖harC,有两个hap,hapA依赖harA,hapB依赖harB,那么最终会存在一份harA、harB,两份harC;

  • hsp 中的代码和资源可以独立编译,运行时在一个进程中代码也只会存在一份

举个例子:

  • 如果应用内没有使用动态包,或者把单例的封装放在动态包里被其他包(静态包或动态包)直接依赖,我们的单例可以这么写:
    class SimgleProvider {
      private static _instance?: SimgleProvider

      public static instance(): SimgleProvider {
        if (!SimgleProvider._instance) {
          SimgleProvider._instance = new SimgleProvider()
        }
        return SimgleProvider._instance
      }
    }
  • 在应用的任意一处获取这个单例都是同一个对象

  • 但如果单例封装放在 har 包内,该 har 包被其他包(静态包和动态包)依赖引用。仍然使用上述代码实现单例,我们在 entry 或者 被 entry 直接依赖的 har 中获取到的 SimgleProvider 单例 和在 hsp 包内获取到的 SimgleProvider 单例 不是指向同一份内存,它会被拷贝两份。

可以简单的总结为:一个应用内,同一个 har 包,如果同时被 har (或者entry)和 hsp 依赖引用,会被拷贝两份。

  • 如果需要整个应用内,包括 entry、har、hsp 都指向的是同一个单例对象,要么把这个单例封装放在 hsp 内,如果单例封装放在 har 内,需要把上面的单例实现代码改成如下:
class SimgleProvider {
  private static _instance?: SimgleProvider

  public static instance(): FastRouter {
    const storageKey = 'SimgleProvider'
    if (!AppStorage.has(storageKey)) {
      AppStorage.setOrCreate(storageKey, new SimgleProvider())
    }
    return AppStorage.get<SimgleProvider>(storageKey)!
  }
}
  • 借助AppStorage,实现全应用单例


最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

鸿蒙HarmonyOS Next全套学习资料←点击领取!(安全链接,放心点击

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

鸿蒙(HarmonyOS NEXT)最新学习路线

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

HarmonyOS Next 最新全套视频教程

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

大厂面试必问面试题

鸿蒙南向开发技术

鸿蒙APP开发必备

鸿蒙生态应用开发白皮书V2.0PDF


获取以上完整鸿蒙HarmonyOS学习资料,请点击→

总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1838046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

凌凯科技冲刺上市:2023年业绩反弹,靠关联交易助推业务发展?

近日&#xff0c;上海凌凯科技股份有限公司&#xff08;下称“凌凯科技”&#xff09;向港交所递交上市申请&#xff0c;华泰国际担任其独家保荐人。 透过招股书不难看出&#xff0c;在化学合成一体化这个虹吸效应显著的细分赛道中&#xff0c;凌凯科技拥有头部玩家的先发优势…

freemarker导出doc文档多个图片处理

POI freemarker处理多图片插入到doc文档 文章目录 POI前言一、doc模板转换成xml文件格式&#xff1f;二、修改xml文件并转为ftl文件1.集合内容2.xml修改集合处理&#xff08;1&#xff09;头部加入图片的循环&#xff08;2&#xff09;需要循环的数据集合处理&#xff08;3&am…

计算机SCI期刊,中科院2区TOP,收稿范围广泛!

一、期刊名称 IEEE Transactions on Automation Science and Engineering 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机科学 影响因子&#xff1a;5.6 中科院分区&#xff1a;2区top 三、期刊征稿范围 IEEE Transactions on Automation Science…

SAP ABAP开发:如何读取物料主数据中的长文本?

在SAP ERP系统中&#xff0c;物料的基本描述可存储40个字符&#xff0c;见下图&#xff1a; 但长文本信息如何从系统中读取呢&#xff1f; 在SAP ABAP开发中&#xff0c;读取物料主数据&#xff08;Material Master Data&#xff09;中的基本视图&#xff08;Basic View&#…

Redis变慢了?之二

Redis变慢了&#xff1f;之二 Redis变慢了规律性变慢Redis几种过期策略的区别&#xff1f;定时过期惰性过期定期过期优化方案 实例内存达上限内存淘汰策略 写在最后 Redis变慢了 Redis变慢上一篇文章地址&#xff1a;Redis变慢了&#xff1f;这篇文章继续Redis变慢情况的分析。…

PyQt5.QtWidgets常用函数及说明

目录 PyQt5.QtWidgets简介常用函数设置窗口标题和固定大小创建垂直布局创建进度条 PyQt5.QtWidgets简介 PyQt5.QtWidgets 是 PyQt5 库中的一个模块&#xff0c;它包含了用于创建图形用户界面&#xff08;GUI&#xff09;的各种小部件&#xff08;widgets&#xff09;。这些小部…

【ARM】如何通过Keil MDK查看芯片的硬件信息

【更多软件使用问题请点击亿道电子官方网站】 1、文档目标&#xff1a; 解决在开发过程中对于开发项目所使用的的芯片的参数查看的问题 2、问题场景&#xff1a; 在项目开发过程中&#xff0c;经常需要对于芯片的时钟、寄存器或者一些硬件参数需要进行确认。大多数情况下是需…

【前端取不到cookie的的原因】http-only

某条cookie有http-only属性时&#xff0c;下面两种方法都取不到&#xff0c;还是改需求吧&#xff0c;别取了 1、 npm install js-cookie --save import Cookies from js-cookie let cookieValue Cookies.get(name)2、document.cookie

STM32单片机-通信协议(下)

STM32单片机-通信协议(下&#xff09; 一、通信协议介绍二、USART(通用同步/异步收发器)2.1 USART框图和基本结构2.2 串口发送2.2.1 Printf函数移植2.2.2 串口发送汉字 2.3 串口接收2.3.1 串口接收查询2.3.2 串口接收中断 2.4 USART串口数据包2.4.1 数据包格式2.4.2 数据包接收…

可平滑替代传统FTP的国产FTP方案,了解一下

企业在处理数据传输时&#xff0c;效率和安全性是关键。尽管传统FTP曾被广泛采用&#xff0c;然而&#xff0c;随着企业业务需求的增长&#xff0c;传统FTP在传输速度、安全性、稳定性以及可控性方面的不足逐渐显现。许多企业正在寻找更为高效、安全且用户体验更好的的国产FTP方…

助力低空经济-eVTOL/无人机ADS-B航管应答机选型指南

一、低空经济概述 “低空经济”在今年全国两会首次写入政府工作报告。近日&#xff0c;工业和信息化部、科学技术部、财政部、中国民用航空局印发《通用航空装备创新应用实施方案&#xff08;2024—2030年&#xff09;》&#xff0c;提出到2030年&#xff0c;推动低空经济形成…

操作系统 大作业

1、现有成绩文件按“姓名 学校 年级 班级 分数”五列组成&#xff0c;编写Shell脚本&#xff0c;将某目录下所有成绩文件&#xff08;≥3个&#xff09;合并为一个&#xff0c;形成“姓名 班级 分数”三列&#xff0c;并按成绩排序&#xff0c;输出年级排名前十。同时输出60以下…

Three.js框架的技术难点

Three.js作为一款功能强大的3D JavaScript框架&#xff0c;在为开发者提供丰富的功能和灵活性的同时&#xff0c;也带来了一些技术难点&#xff0c;需要开发者具备一定的知识和经验才能克服。以下是一些Three.js框架的技术难点。北京木奇移动技术有限公司&#xff0c;专业的软件…

高考志愿选专业,文科生如何分析选择专业?

每到高考时节&#xff0c;学生们最关注的就是专业选择&#xff0c;以及未来职业发展问题&#xff0c;对于文科生来说&#xff0c;面对文科专业的众多选择&#xff0c;很多人都有些不知所措&#xff0c;如何选择适合自己兴趣爱好&#xff0c;又有良好就业前景的工作。从哪些方面…

RTthread+STM32F407ZGTx+烟雾报警检测+蜂鸣器报警+LED闪烁||使用RTthread Studio

目录 实验背景 1.安装环境 2.配置环境 3.先编译下载实例程序2&#xff0c;观察DS0是否闪烁 4.实验方法 5.实例代码 6.硬件连接 7.实验效果 8.关于这次开发遇到的问题 1.反应慢&#xff0c;都熄灭1分钟多了&#xff0c;才报的问题&#xff1f; 2.关于rt_pin_mode(KEY…

Linux 图形化编程GTK3.0 快速入门之布局

GTK3.0 布局之水平布局 核心语法&#xff1a; 水平布局容器&#xff1a; 水平布局容器的创建&#xff1a; GtkWidget *gtk_hbox_new( gboolean homogeneous, gint spacing ); homogeneous&#xff1a;容器内控件是否大小一致( gboolean 取值为TRUE 或 FALSE ) spacing&#…

什么是数字化,什么是数智化?数字化与数智化的区别和联系

什么是数字化&#xff1f;什么是数智化&#xff1f;以及数字化与数智化的区别&#xff0c;下面分为三块跟大家详细讲解。 一、什么是数字化&#xff1f; 1、概念&#xff1a; 数字化&#xff08;Digitalization&#xff09;是将信息转换为数字&#xff08;即计算机可读&#…

操作系统之如何使用C语言完成SFJ和SRTJ,并完成他的甘特图

目录 前言 SFJ SRTJ 结束语 前言 不知不觉已经写博客一个月了&#xff0c;前段时间因为学业上的一些原因咕咕咕了&#xff0c;今天我又回来了。今天我给大家带来的是C语言代码完成的SFJ和SRTJ&#xff0c;并且带大家描述他的甘特图。如果有对SFJ和SRTJ不了解的小伙伴可以翻…

windows anaconda 安装 Labelme

安装 # 创建环境 conda create -n labelme python3.6 #激活环境 conda activate labelme # 安装依赖 conda install pyqt conda install pillow # 安装labelme conda install labelme3.16.2 # 启动labelme labelme右键选择标注类型&#xff0c;从上到下为多边形&#xff08;常…

超声波清洗机哪个牌子好用点?四大卓越臻品不容错过!

选购超声波清洗机能为日常生活提供非常多的便利&#xff01;比如像是戴眼镜或者是有婴儿的家庭&#xff0c;使用超声波清洗机不仅能够帮助清洗需要清洗的物品&#xff0c;同时更能保证物品健康清洁&#xff0c;对清洗的物品进行杀菌灭菌&#xff01;相对于比较费时间并且容易损…