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

鸿蒙技术分享:Navigation页面容器封装-鸿蒙@fw/router框架源码解析(三)

本文是系列文章,其他文章见:
鸿蒙@fw/router框架源码解析(一)-router页面管理
鸿蒙@fw/router框架源码解析(二)-Navigation页面管理
鸿蒙@fw/router框架源码解析(四)-路由Hvigor插件实现原理
鸿蒙@fw/router框架源码解析(五)-无代码依赖如何实现拦截器逻辑
鸿蒙@fw/router框架源码解析(六)-模块化开发如何实现代码解耦

鸿蒙@fw/router框架源码解析

介绍

@fw/router是在HarmonyOS鸿蒙系统中开发应用所使用的开源模块化路由框架。
该路由框架基于模块化开发思想设计,支持页面路由和服务路由,支持自定义装饰器自动注册,与系统路由相比使用更便捷,功能更丰富。

具体功能介绍见https://juejin.cn/post/7386917612675301388@fw/router:鸿蒙模块化路由框架,助力开发者实现高效模块化开发!

基于模块化的开发需求,本框架支持以下功能:

  • 支持页面路由和服务路由;
  • 页面路由支持多种模式(router模式,Navigation模式,混合模式);
  • router模式支持打开非命名路由页面;
  • 页面打开支持多种方式(push/replace),参数传递;关闭页面,返回指定页面,获取返回值,跨页面获取返回值;
  • 支持服务路由,可使用路由url调用公共方法,达到跨技术栈调用以及代码解耦的目的;
  • 支持页面路由/服务路由通过装饰器自动注册;
  • 支持动态导入(在打开路由时才import对应har包),支持自定义动态导入逻辑;
  • 支持添加拦截器(打开路由,关闭路由,获取返回值);
  • Navigation模式下支持自定义Dialog对话框;

详见gitee传送门

代码解析

FWNavigation

Navigation容器设置

因为本文章侧重于讲解@fw/router的实现逻辑,所以在上一节中并没有完整的讲Navigation页面如何使用。
其实,Navigation页面想要正常打开,除了注册页面外,还需要对导航容器进行设置。

具体如下:

  @BuilderpageMap(name: string, param?: ESObject) {if (RouterManagerForNavigation.getInstance().getBuilder(name).builder.length == 0) {RouterManagerForNavigation.getInstance().getBuilder(name).builder()} else {RouterManagerForNavigation.getInstance().getBuilder(name).builder(param)}}build() {Navigation(this.pageStack) {// ...}.navDestination(this.pageMap)}

核心就是两点:

  1. Navigation容器需要绑定NavPathStack对象;
  2. Navigation容器需要设置navDestination方法,因为它才是真正的页面跳转处理逻辑;

如果你的应用只使用Navigation进行页面管理,那么可能就只有一个Navigation容器,上面这些代码只需要设置一次,手动编写没什么问题。
但如果你准备router页面栈和Navigation页面栈混用,或者主用router页面栈但Dialog想用Navigation支持,那么理论上每个router页面都需要一个Navigation容器,上面的设置代码就需要写多次。
正是基于以上原因,@fw/router中封装了FWNavigation容器。

FWNavigation整体代码
@Component
export struct FWNavigation {// 接受外部传入的AttributeModifier类实例@Prop modifier: NavigationModifier | null = null;@Provide('pageStack') pageStack: NavPathStack = new NavPathStack()aboutToAppear(): void {RouterManagerForNavigation.getInstance().pushNavPathStack(this.pageStack)}aboutToDisappear(): void {RouterManagerForNavigation.getInstance().popNavPathStack(this.pageStack)}@BuilderpageMap(name: string, param?: ESObject) {if (RouterManagerForNavigation.getInstance().getBuilder(name).builder.length == 0) {RouterManagerForNavigation.getInstance().getBuilder(name).builder()} else {RouterManagerForNavigation.getInstance().getBuilder(name).builder(param)}}@BuilderParam closure: Functionbuild() {Navigation(this.pageStack) {this.closure()}.navDestination(this.pageMap).titleMode(NavigationTitleMode.Mini).attributeModifier(this.modifier)}
}

FWNavigation的代码不多,但是大致也分为三部分,分别是容器设置,多容器逻辑,系统组件扩展。

FWNavigation容器设置
@Component
export struct FWNavigation {@BuilderpageMap(name: string, param?: ESObject) {if (RouterManagerForNavigation.getInstance().getBuilder(name).builder.length == 0) {RouterManagerForNavigation.getInstance().getBuilder(name).builder()} else {RouterManagerForNavigation.getInstance().getBuilder(name).builder(param)}}build() {Navigation(this.pageStack) {// ...}.navDestination(this.pageMap)}
}

容器设置代码就是我们在上一节中讲的,主要是绑定NavPathStack对象和设置navDestination方法。

多容器逻辑
@Component
export struct FWNavigation {@Provide('pageStack') pageStack: NavPathStack = new NavPathStack()aboutToAppear(): void {RouterManagerForNavigation.getInstance().pushNavPathStack(this.pageStack)}aboutToDisappear(): void {RouterManagerForNavigation.getInstance().popNavPathStack(this.pageStack)}build() {Navigation(this.pageStack) {}}
}

多容器逻辑主要是解决Navigation绑定的NavPathStack对象从哪里来的问题。
如果整个应用只有一个Navigation容器,其实很简单,只需要让RouterManager单例自己创建NavPathStack对象,Navigation使用即可。
但对于应用中存在多个Navigation容器的情况,就比较复杂了。
从以上的代码中,我们看到,NavPathStack对象是由FWNavigation容器自己创建,并在aboutToAppear方法中,讲之托管给了RouterManagerForNavigation单例。
aboutToDisappear方法中,也会将我们使用的NavPathStack对象从RouterManagerForNavigation单例中移除。

export class RouterManagerForNavigation implements RouterHandler {// 多Navigation状态下,每个Navigation都要将自己的`navPathStacks`对象托管给管理器。navPathStacks: NavPathStack[] = [];get currentNavPathStack(): NavPathStack | undefined {return this.navPathStacks[this.navPathStacks.length-1]}pushNavPathStack(stack: NavPathStack) {this.navPathStacks.push(stack)}popNavPathStack(stack?: NavPathStack) {if (stack != undefined && this.navPathStacks.indexOf(stack) >= 0) {this.navPathStacks = this.navPathStacks.filter((item) => item !== stack)} else {this.navPathStacks.pop()}}
}

RouterManagerForNavigation主要是使用currentNavPathStack方法,所以上面的处理主要是为了让使用的NavPathStack对象和当前UI层展示的保持一致。

除了普通的push/pop场景,其实还有更复杂的情况,比如Tab嵌套。
当多个页面嵌入到Tab中时,我们建议Tab页外面统一套一层FWNavigation容器,Tab内页不套FWNavigation容器,否则当Tab页面selectedIndex变动时,还需要保证currentNavPathStack获取到的对象和当前页面的NavPathStack对象一致,否则Navigation页面无法正常显示。

系统组件扩展

FWNavigation容器其实也只是对系统Navigation容器进行了封装,为了更好的兼容性,理论上我们需要支持所有Navigation支持的属性。
好消息是,官方给我们提供了方案:AttributeModifier

@Component
export struct FWNavigation {// 接受外部传入的AttributeModifier类实例@Prop modifier: NavigationModifier | null = null;@BuilderParam closure: Functionbuild() {Navigation(this.pageStack) {this.closure()}.attributeModifier(this.modifier)}
}

使用起来也算方便:

export struct TestPage {@State modifier: NavigationModifier = new NavigationModifier().mode(NavigationMode.Stack).subTitle('TestPage')build() {Column() {FWNavigation({ modifier: this.modifier }) {TestPageContent({ pageName: 'TestPage' })}}}
}

但坏消息是,即便是系统自己实现的NavigationModifier,也并不是所有方法都可以使用。
有些属性你在IDE里可以调用,但运行会报错。

Error message:Method not implemented.

当你遇到这个报错时,很不幸,你要使用的属性并不支持。

其他方案

那么,除了AttibuteModifier,还有其他方案吗?

肯定有,比如可以将Navigation所有支持的参数放到FWNavigation的构造方法入参中,自己对接实现。

但是该方案存在几个缺点:

  1. 代码逻辑不灵活,当系统api变动时自己也需要变动;
  2. 自定义组件不能使用链式语法,自定义参数只能放在构造方法入参中;也就是说如果现有代码从Navigation写法迁移到FWNavigation,无法通过改类名的方式直接迁移;(当然AttributeModifier也不行)
  3. 还有就是自己实现,无法使用系统api的默认取值。

第三个问题或许有点难以理解,下面详细解释下。

比如,Navigation有个属性叫hideToolBar是否隐藏工具栏。默认值:false。true: 隐藏工具栏。false: 显示工具栏。

我们看到系统的默认值现在是false。

我们在封装时,代码类似于:

class FWNavigationOptions {hideToolBar?: boolean
}struct FWNavigation {@Prop options: FWNavigationOptionsbuild() {Navigation() {}.hideToolBar(this.options.hideToolBar)}
}

现在的问题在于这一句.hideToolBar(this.options.hideToolBar)
我们自己封装的hideToolBar是可选参数,可以为undefined。
但是系统的Navigation.hideToolBar()入参却是必传参数,不能为undefined。

理论上有几种处理方法:

  1. 自己手动写死默认值:.hideToolBar(this.options.hideToolBar ?? false);但面对Navigation20多种属性,写起来也太麻烦,而且那些方法类型的属性,还需要自己实现默认的方法,太复杂;
  2. 通过条件渲染来避免.hideToolBar()方法调用;这种方法对于一两个属性的情况还行,属性多了就不行,毕竟它就是枚举,有10个属性你就要写2^10个条件分支语句;

所以最终,还是老老实实选择了AttributeModifier方案,虽然暂时还不完美,但还可以期待官方早点优化好……

总结

FWNavigation核心还是Navigation容器的封装扩展,对于@fw/router而言只是一个附加功能。

在混合栈的使用场景下,FWNavigation的价值比较明显,这也是@fw/router一开始进行封装的原因,对于鸿蒙开发而言,能够避坑的封装其实越早越好。

相关文章:

鸿蒙技术分享:Navigation页面容器封装-鸿蒙@fw/router框架源码解析(三)

本文是系列文章,其他文章见:鸿蒙fw/router框架源码解析(一)-router页面管理鸿蒙fw/router框架源码解析(二)-Navigation页面管理鸿蒙fw/router框架源码解析(四)-路由Hvigor插件实现原…...

三步入门Log4J 的使用

本篇基于Maven 的Project项目&#xff0c; 快速演示Log4j 的导入和演示。 第一步&#xff1a; 导入Log4j依赖 <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.24.2</version&…...

VBA中类的解读及应用第十八讲:利用类方法,判断任意单元格类型

《VBA中类的解读及应用》教程【10165646】是我推出的第五套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。 类&#xff0c;是非常抽象的&#xff0c;更具研究的价值。随着我们学习、应用VBA的深入&#xff0…...

查询品牌涉及两张表(brand、brand_admin_mapping)

文章目录 1、BrandController2、AdminCommonService3、BrandApiService3、BrandCommonService4、BrandSqlService涉及的表SQL 查询逻辑参数处理执行查询完整 SQL 逻辑参数映射总结 查询指定管理员下的品牌所涉及的表有哪些&#xff1f; http://127.0.0.1:8087/brand/admin/list…...

Eureka和Zookeeper、Nacos的区别

目录 一、Eureka与Zookeeper的区别 适用场景&#xff1a; 架构设计&#xff1a; 功能特性&#xff1a; 社区生态&#xff1a; 二、Eureka与Nacos的区别 接口方式&#xff1a; 实例类型&#xff1a; 健康检测&#xff1a; 服务发现&#xff1a; 一致性与可用性&#…...

微信小程序怎么实现非tabbar页面显示tabbar,自定义组件实现

微信小程序没有发现可以实现非tabbar页面显示tabbar的方法&#xff0c;但是可以在tabbar页面当中隐藏tabbar&#xff0c;使用wx.hideTabBar()方法就可以实现&#xff0c;在非tabbar页面调用wx.showTabBar()方法却会显示失败&#xff0c;不能显示tabbar onLoad() {wx.showTabBar…...

SpringBoot如何使用EasyExcel实现表格导出(简洁快速入门版本)

前言 前面给大家介绍了动态表头的导入&#xff0c;这篇文章给大家介绍如何实现导出 前面给大家介绍了动态表头的导入&#xff0c;我们了解了如何通过EasyExcel灵活地读取结构不固定的Excel文件。这次&#xff0c;我们将目光转向数据导出——即如何将数据以Excel文件的形式输出…...

多种平台上安装部署调试Open5GS(四)

OpenWRT 源码安装 UERANSIM 安装依赖openwrt源码安装cmake其他依赖准备UERANSIM安装测试验证Open5GS 是一个功能完善的开源5G项目,具备5G、4G核心网功能,最新代码支持R17标准, 本系列文章介绍Open5GS在x86、ARM平台上的安装部署方法,并通过搭建UERANSIN、商用5G基站和终端两…...

单片机的基本构成与工作原理

单片机&#xff0c;即微控制器&#xff08;Microcontroller Unit&#xff0c;MCU&#xff09;&#xff0c;是一种将中央处理器(CPU)、存储器(ROM/RAM)、定时/计数器(Timer/Counter)、中断系统、输入输出(I/O)接口等集成在一块芯片上的微型计算机。它具有体积小、功耗低、成本低…...

opencv常用图像处理操作

OpenCV 处理图像的通用流程通常包括以下几个步骤&#xff0c;根据具体需求可以调整或跳过某些步骤。以下是一个通用的框架&#xff1a; 读取图像 加载图像文件到内存中以进行后续处理。 import cv2 读取图像 image cv2.imread(‘image.jpg’) # 彩色图像 gray_image cv2…...

Svn如何切换删除账号

记录Svn清除切换账号 1.首先打开小乌龟的设置如下图 打开设置后单击已保存数据&#xff0c;然后选择清除 接上图选择清除后&#xff0c;就可以打勾选择清除已保存的账号&#xff0c;我们再次检出的就可以切换账号了 &#x1f449;总结 本次记录Svn清除切换账号 如能帮助到你…...

使用PaddleOCR遇到的问题Bug

Q1: 训练模型的预测效果比inference模型的预测效果差距很大,怎么办?原因是什么? A1: 训练模型:使用训练数据集进行训练后的模型。 inference模型:把模型结构和模型参数保存在文件中的固化模型,多用于预测部署场景。训练过程中保存的模型是checkpoints模型,保存的只有模…...

了解Xcode在iOS开发中的作用和功能有哪些

Xcode是什么&#xff1f;它在iOS开发中的作用和功能有哪些&#xff1f; 一、Xcode是什么&#xff1f; Xcode是苹果公司针对macOS平台开发的一款集成开发环境&#xff08;Integrated Development Environment&#xff0c;简称IDE&#xff09;。它主要用于开发iOS、iPadOS、mac…...

《船舶物资与市场》是什么级别的期刊?是正规期刊吗?能评职称吗?

问题解答 问&#xff1a;《船舶物资与市场》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《船舶物资与市场》级别&#xff1f; 答&#xff1a;国家级。主管单位&#xff1a;中国船舶集团有限公司 主办单…...

商汤完成组织架构调整,改革完成的商汤未来何在?

首先&#xff0c;从核心业务的角度来看&#xff0c;商汤科技通过新架构明确了以AI云、通用视觉模型等为核心业务的战略方向。这一举措有助于商汤科技集中资源&#xff0c;加强在核心业务领域的研发和市场拓展&#xff0c;提高市场竞争力。同时&#xff0c;坚定生成式AI为代表的…...

MyBatis异常体系中ErrorContext和ExceptionFactory原理分析

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 exceptions包分包设计ExceptionFactory类介绍为什么使用工厂不是直接new呢&#xff1f;【统一的异常处理机制】【异常的封装与转化】【…...

WHLUG丨deepin、华中科技大学开放原子开源俱乐部、 RustSBI 和清华大学开源操作系统训练营共话开源新生代成长之路

2024年11月30日下午&#xff0c;由 deepin&#xff08;深度&#xff09;社区联合华中科技大学开放原子开源俱乐部、 RustSBI 开源社区和清华大学开源操作系统训练营共同举办的WHLUG&#xff08;武汉Linux用户组&#xff09;线下沙龙在华中科技大学成功举办。 本次活动聚集了50余…...

通过HTML Canvas 在图片上绘制文字

目录 前言 一、HTML Canvas 简介 二、准备工作 三、绘制图片 四、绘制文字 五、完整代码 效果演示&#xff1a; 前言 HTML canvas 为我们提供了无限的创意可能性。今天&#xff0c;我们就来探索一下如何通过 HTML canvas 将图片和文字绘制到图片上&#xff0c;创造出独特…...

C# 冒泡的算法

C# 冒泡的算法 public void BubbleSort(int[] arr) {int temp;for (int j 0; j < arr.Length - 2; j){for (int i 0; i < arr.Length - 2; i){if (arr[i] > arr[i 1]){temp arr[i 1];arr[i 1] arr[i];arr[i] temp;}}} }使用方法 int[] array new int[] { 5,…...

大数据项目-Django基于聚类算法实现的房屋售房数据分析及可视化系统

《[含文档PPT源码等]精品Django基于聚类算法实现的房屋售房数据分析及可视化系统》该项目含有源码、文档、PPT、配套开发软件、软件安装教程课程答疑等&#xff01; 数据库管理工具&#xff1a;phpstudy/Navicat或者phpstudy/sqlyog 后台管理系统涉及技术&#xff1a; 后台使…...

AWS创建ec2实例并连接成功

aws创建ec2实例并连接 aws创建ec2并连接 1.ec2创建前准备 首先创建一个VPC隔离云资源并且有公有子网 2.创建EC2实例 1.启动新实例或者创建实例 2.创建实例名 3.选择AMI使用linux(HVM) 4.选择实例类型 5.创建密钥对下载到本地并填入密钥对名称 6.选择自己创建的VPC和公有子网…...

TypeScript 开始学习 -接触的新东西

目录 语言类型类型总览JavaScript 中的数据类型TypeScript 中的数据类型 定义类型断言索引签名泛型 语言类型 JS -> 弱类型 TS -> 强类型 TypeScript&#xff08;TS&#xff09;是一种强类型语言。‌这意味着在TypeScript中&#xff0c;变量和函数参数的类型必须在编译时…...

非对称任意进制转换器(安卓)

除了正常进制转换&#xff0c;还可以输入、输出使用不同的数字符号&#xff0c;达成对数值进行加密的效果 点我下载APK安装包 使用unity开发。新建一个c#代码文件&#xff0c;把代码覆盖进去&#xff0c;再把代码文件添加给main camera即可。 using System.Collections; usin…...

【优选算法篇】寻找隐藏的宝藏:用二分查找打开算法世界的大门(上篇)

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…...

基于Vue实现的移动端手机商城项目 电商购物网站 成品源码

&#x1f4c2;文章目录 一、&#x1f4d4;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站演示 &#x1f4f8;部分截图 &#x1f3ac;视频演示 五、⚙️网站代码 &#x1f9f1;项目结构 &#x1f492;vue代码预览 六、&#x1f527;完整…...

C语言:数组

数组 数组的概念 引例 如果我们要在程序中表示一个学生的成绩&#xff0c;我们会使用一个int来表示&#xff0c;如&#xff1a;int score。假如我们要在程序中表示一组成绩&#xff0c;此时我们所学的常规的数据类型就无法再表示&#xff0c;这个时候我们就需要使用一种新的…...

时间序列预测之FiLM

没错&#xff0c;就是看电影 文章目录 前言1. 问题描述2. 创新之处3. 贡献 一、时间序列在legende - fourier域的表示1. 勒让德投影2. 傅里叶变换 二、 模型结构1. LPU: Legendre Projection Unit2. FEL: Frequency Enhanced Layer3. 多尺度专家机制的混合 二、实验结果长时预测…...

【机器学习】窥数据之序,悟算法之道:机器学习的初心与远方

文章目录 机器学习入门&#xff1a;从零开始学习基础与应用前言第一部分&#xff1a;什么是机器学习&#xff1f;1.1 机器学习的定义1.1.1 举个例子&#xff1a;垃圾邮件分类器 1.2 机器学习的核心思想1.2.1 数据驱动的模式提取1.2.2 为什么机器学习比传统方法更灵活&#xff1…...

OpenCL介绍

OpenCL&#xff08;Open Computing Language&#xff09;详解 OpenCL 是一个开源的框架&#xff0c;用于编写在异构平台&#xff08;包括中央处理单元&#xff08;CPU&#xff09;、图形处理单元&#xff08;GPU&#xff09;、数字信号处理器&#xff08;DSP&#xff09;和其他…...

「Mac畅玩鸿蒙与硬件42」UI互动应用篇19 - 数字键盘应用

本篇将带你实现一个数字键盘应用&#xff0c;支持用户通过点击数字键输入数字并实时更新显示内容。我们将展示如何使用按钮组件和状态管理来实现一个简洁且实用的数字键盘。 关键词 UI互动应用数字键盘按钮组件状态管理用户交互 一、功能说明 数字键盘应用将实现以下功能&…...