OpenHarmony 入门——ArkUI 跨页面数据同步和页面级UI状态存储LocalStorage小结(二)

文章大纲

  • 引言
  • 一、在代码逻辑使用LocalStorage
  • 二、从UI内部使用LocalStorage
  • 三、@LocalStorageProp和LocalStorage单向同步
  • 四、@LocalStorageLink和LocalStorage双向同步
  • 五、兄弟组件之间同步状态变量
  • 七、将LocalStorage实例从UIAbility共享到一个或多个视图

引言

前面一篇文章主要介绍了OpenHarmony 入门——ArkUI 管理跨页面和应用级LocalStorage 页面级UI状态存储小结(一)的相关语法和基础理论知识,这篇就好好学习下其用法。

一、在代码逻辑使用LocalStorage

在代码逻辑使用LocalStorage意思是通过相关的API 来建立联系并实现同步。

let para: Record<string,number> = { 'PropA': 47 };
let storage: LocalStorage = new LocalStorage(para); // 创建新实例并使用给定对象初始化
let propA: number | undefined = storage.get('PropA') // propA == 47
let link1: SubscribedAbstractProperty<number> = storage.link('PropA'); // link1.get() == 47
let link2: SubscribedAbstractProperty<number> = storage.link('PropA'); // link2.get() == 47
let prop: SubscribedAbstractProperty<number> = storage.prop('PropA'); // prop.get() == 47
link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48
link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49

二、从UI内部使用LocalStorage

除了应用程序逻辑使用LocalStorage,还可以借助LocalStorage相关的两个装饰器@LocalStorageProp和@LocalStorageLink,在UI组件内部获取到LocalStorage实例中存储的状态变量
以@LocalStorageLink为例:

  • 使用构造函数创建LocalStorage实例storage;
  • 使用@Entry装饰器将storage添加到LocalParent顶层组件中;
  • @LocalStorageLink绑定LocalStorage对给定的属性,建立双向数据同步
//1、LocalStorage
let obj :Record<string, number> = {'PropA': 66}
// 创建新实例并使用给定对象初始化,LocalStorage接收的是一个Object
let storageObj = new LocalStorage(obj);@Component
struct LocalChild {@LocalStorageLink('PropA') propALinked : number = 88;build() {Column() {// 初始化时读取LocalStorage变量的值66,在按钮点击一次后依然为66不变Text(`LocalStorage: ${storageObj.get('PropA')}`).width('100%').height(36)//初始化为storage的值,再点击了自己的按钮一次后为Text(`LocalStorageLink: ${this.propALinked}`).width('100%').height(36)Button(`在LocalChild中读取自己的@LocalStorageLink: ${this.propALinked}`).onClick(() => {// 更新@LocalStorageLink变量的值,Text上的值会改变this.propALinked += 2;}).width('100%').height('36')}}
}// ???使LocalStorage可从@Component组件访问,好像我传不传过来都不影响结果呀????
@Entry(storageObj)
@Component
struct LocalParent {// @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定@LocalStorageLink('PropA') storLinkP: number = 68;build() {Column({ space: 15 }) {Text(`LocalParent LocalStorage: ${storageObj.get('PropA')}`).width('100%').height(36)Button(`LocalParent 中LocalStorageLink: ${this.storLinkP}`).width('100%') // initial value from LocalStorage will be 66, because 'PropA' initialized already.onClick(() => this.storLinkP += 3)// @Component子组件自动获得对LocalParent LocalStorage实例的访问权限。LocalChild()}}
}

在这里插入图片描述

三、@LocalStorageProp和LocalStorage单向同步

在下面的示例中,CompA 组件和Child组件分别在本地创建了与storage的’PropA’对应属性的单向同步的数据,我们可以看到:

  • CompA中对this.storProp1的修改,只会在CompA中生效,并没有同步回storage;
  • Child组件中,Text绑定的storProp2 依旧显示47。
let para: Record<string, number> = { 'PropA': 66 };
let storage: LocalStorage = new LocalStorage(para);
// 使LocalStorage可从@Component组件访问
@Entry(storage)
@Component
struct CompP {// @LocalStorageProp变量装饰器与LocalStorage中的'PropA'属性建立单向绑定@LocalStorageProp('PropA') storageProp1: number = 2;build() {Column({ space: 15 }) {Text(`@LocalStorageProp和LocalStorage单向同步 ${storage.get('PropA')}`).width('100%').height(40).fontStyle(FontStyle.Italic).fontSize(26)// 点击后从66开始加2,只改变当前组件显示的storageProp1,不会同步到LocalStorage中,即Child中的storageProp1不会改变Button(`CompP 中 LocalStorage ${this.storageProp1}`).onClick(() => {this.storageProp1 += 2})ChildComp()}}
}@Component
struct ChildComp {// @LocalStorageProp变量装饰器与LocalStorage中的'PropA'属性建立单向绑定@LocalStorageProp('PropA') storageProp2: number = 2;build() {Column({ space: 15 }) {// 初始化时显示的依然是66而不是2,当CompP改变时,当前storageProp2也不会改变,显示66Text(`ChildComp 中的LocalStorageProp: ${this.storageProp2} && ${storage.get('PropA')}`);}}
}

在这里插入图片描述

四、@LocalStorageLink和LocalStorage双向同步

@LocalStorageLink装饰的数据和LocalStorage双向同步的场景,还是上面的代码把@LocalStorageLink替换掉@LocalStorageProp就行了。

Text(`@LocalStorageProp和LocalStorage单向同步 ${storage.get('PropA')} && ${this.storageProp1}`).width('100%').height(40).fontStyle(FontStyle.Italic).fontSize(24)

在这里插入图片描述

五、兄弟组件之间同步状态变量

通过@LocalStorageLink双向同步兄弟组件之间的状态。先看Parent自定义组件中发生的变化:

  • 点击“playCount ${this.playCount} dec by 1”,this.playCount减1,修改同步回LocalStorage中,Child组件中的playCountLink绑定的组件会同步刷新;
  • 点击“countStorage ${this.playCount} incr by 1”,调用LocalStorage的set接口,更新LocalStorage中“countStorage”对应的属性,Child组件中的playCountLink绑定的组件会同步刷新;
  • Text组件“playCount in LocalStorage for debug ${storage.get(‘countStorage’)}”没有同步刷新,因为storage.get(‘countStorage’)返回的是常规变量,常规变量的更新并不会引起Text组件的重新渲染。

Child自定义组件中的变化,playCountLink的刷新会同步回LocalStorage,并且引起兄弟组件和父组件相应的刷新。

let ls: Record<string, number> = { 'countStorage': 88 }
let storageBro: LocalStorage = new LocalStorage(ls);@Component
struct Bro {// 子组件实例的名字label: string ='';// 和LocalStorage中“countStorage”的双向绑定数据@LocalStorageLink('countStorage') playCountLink: number = 0;build() {Row() {Text(this.label).width(50).height(40).fontSize(12)Text(`Bro playCountLink(+2): ${this.playCountLink} && ${storageBro.get<number>('countStorage')}`).onClick(() => {this.playCountLink += 2 }).width(200).height(40).fontSize(12)}.width(300).height(40)}
}
//若不传进来的话playCount的值不是用storageBro的来初始化, ${this.playCount}的值就会是99,而不是storage的88
@Entry(storageBro)
@Component
struct ParentBro {@LocalStorageLink('countStorage') playCount: number = 99;build() {Column() {Text(`ParentBro playCount(-1): ${this.playCount} && ${storageBro.get<number>('countStorage')} `).onClick(() => {this.playCount -= 1;}).width('100%').height(40).fontSize(12)Text(`ParentBro playCount(+3): ${this.playCount} `).onClick(() => {storageBro.set<number | undefined>('countStorage', Number(storageBro.get<number>('countStorage')) + 3);}).width('100%').height(40).fontSize(12)Bro({ label: 'ChildA' })Bro({ label: 'ChildB' })Text(`ParentBro ${storageBro.get<number>('countStorage')}`).width('100%').height(40).fontSize(12)}}
}

在这里插入图片描述

点击另外的按钮效果也是和点击这个ChildA一样,改动的都是联动的

七、将LocalStorage实例从UIAbility共享到一个或多个视图

LocalStorage的实例仅仅在一个@Entry装饰的组件和其所属的子组件(一个页面)中共享,如果希望其在多个视图中共享,可以在所属UIAbility中创建LocalStorage实例,并调用windowStage.loadContent传入,然后再需要使用时候通过LocalStorage.getShared() 实例来复用可共享了。下面以一个UIAbility中的多个组件共享一个LocalChildStorage来说明:

  • 在所属UIAbility中创建LocalStorage实例,并作为windowStage.loadContent的参数传入
export default class EntryAbility extends UIAbility {param:Record<string,number> = {'PropAbility':68};storageAbility:LocalStorage = new LocalStorage(this.param);onWindowStageCreate(windowStage: window.WindowStage): void {// Main window is created, set main page for this abilityhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');//把storageAbility传递过去windowStage.loadContent('pages/StatePageMgr', this.storageAbility);}...}

在UI页面通过getShared接口获取通过loadContent共享的LocalStorage实例。LocalStorage.getShared()只在模拟器或者实机上才有效,在Previewer预览器中使用不生效。

  • 在所需要使用这个LocalStorage的组件的Page下通过LocalStorage.getShared()函数来获取实例(而不是自己new去创建哈),然后剩下的就是和传统的自己定义一个LocalStorage实例的使用方法一样了。如LocalPage.ets实现如下
// 在通过getShared接口获取stage共享的LocalStorage实例
let storageFromAbility: LocalStorage = LocalStorage.getShared();@Entry(storageFromAbility)
@Component
struct FromAbilityComp {@LocalStorageLink('PropAbility') propLink: number = 88;build() {Column() {Text(`LocalStorageFromAbility: ${this.propLink} && ${storageFromAbility.get<number>('PropAbility')}`).width('100%').height(36)Button('To Page B').width('100%').onClick(() => {router.pushUrl({url: 'pages/Index'})})}.height('100%')}
}

Index.ets

let storageFromAbility2 = LocalStorage.getShared()@Entry(storageFromAbility2)
@Component
struct IndexComp {@LocalStorageLink('PropAbility') propA: number = 66;build() {Row() {Column({space: 10}) {Text(`IndexComp this.propA: ${this.propA} && ${storageFromAbility2.get<number>('PropAbility')}`).width('100%').height(36).fontSize(22).fontWeight(FontWeight.Bold)Button("IndexComp: Change LocalStorageLink this.propA=100").onClick(() => {this.propA = 100;}).height(36)Button("Back Prev page").onClick(() => {router.back()})}.width('100%')}}
}

在这里插入图片描述

对于开发者更建议使用这个方式来构建LocalStorage的实例,并且在创建LocalStorage实例的时候就写入默认值,因为默认值可以作为运行异常的备份,也可以用作页面的单元测试。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

干货分享|DeepSeek技术革命、算力范式重构与场景落地洞察

本文为TsingtaoAI公司负责人汶生为某证券公司管理层和投资者教授的《DeepSeek技术革命、算力范式重构与场景落地洞察》主题培训内容&#xff0c;此次主题培训系统阐述了当前AI技术演进的核心趋势、算力需求的结构性变革&#xff0c;以及行业应用落地的关键路径。 现在我们将全…

从切图仔到鸿蒙开发01-文本样式

从切图仔到鸿蒙开发01-文本样式 本系列教程适合 HarmonyOS 初学者&#xff0c;为那些熟悉用 HTML 与 CSS 语法的 Web 前端开发者准备的。 本系列教程会将 HTML/CSS 代码片段替换为等价的 HarmonyOS/ArkUI 代码。 页面结构 HTML 与 ArkUI 在 Web 开发中&#xff0c;HTML 文档结…

零基础入门网络爬虫第5天:Scrapy框架

4周 Srapy爬虫框架 不是一个简单的函数功能库&#xff0c;而是一个爬虫框架 安装&#xff1a;pip install scrapy 检测&#xff1a;scrapy -h Scrapy爬虫框架结构 爬虫框架 爬虫框架是实现爬虫功能的一个软件结构和功能组件集合爬虫框架是一个半成品&#xff0c;能够帮助…

C语言:扫雷

在编程的世界里&#xff0c;扫雷游戏是一个经典的实践项目。它不仅能帮助我们巩固编程知识&#xff0c;还能锻炼逻辑思维和解决问题的能力。今天&#xff0c;就让我们一起用 C 语言来实现这个有趣的游戏&#xff0c;并且通过图文并茂的方式&#xff0c;让每一步都清晰易懂 1. 游…

同一个局域网的话 如何访问另一台电脑的ip

在局域网内访问另一台电脑&#xff0c;可以通过以下几种常见的方法来实现&#xff1a; ‌直接通过IP地址访问‌&#xff1a; 首先&#xff0c;确保两台电脑都连接在同一个局域网内。获取目标电脑的IP地址&#xff0c;这可以通过在目标电脑上打开命令提示符&#xff08;Windows系…

记录我的ICME2025论文之旅:困顿与收获

人生第一次中B会&#xff0c;还是在课业繁重的大三上&#xff08;有点说法~&#xff09; “在最黑暗的时刻&#xff0c;总有一束光为你指引前行。” ——记录这段难忘的历程 今年的ICME投稿量创下新高&#xff0c;录取率却跌至20多%&#xff0c;并且首次加入了rebuttal&#xf…

MySQL多表查询

这是两个表多表查询&#xff0c;需要一个连接条件customer_id。如果有n个表实现多表查询&#xff0c;至少需要n-1个连接条件。如果少于n-1个&#xff0c;就会出现笛卡尔积的错误。 SELECT orders.order_id, customers.customer_name FROM orders INNER JOIN customers ON orde…

vue3 项目的最新eslint9 + prettier 配置

注意&#xff1a;eslint目前升级到9版本了 在 ESLint v9 中&#xff0c;配置文件已经从 .eslintrc 迁移到了 eslint.config.js 配置的方式和之前的方式不太一样了&#xff01;&#xff01;&#xff01;&#xff01; 详见自己的语雀文档&#xff1a;5、新版eslint9prettier 配…

目标检测20年(三)

对这篇论文感兴趣的小伙伴可以订阅笔者《目标检测》专栏&#xff0c;关注笔者对该文献的阅读和理解。 前两篇解读链接&#xff1a; 目标检测20年&#xff08;一&#xff09;-CSDN博客 目标检测20年&#xff08;二&#xff09;-CSDN博客 目录 四、 检测器的加速发展 4.1 特…

LLM之RAG实战(五十二)| 如何使用混合搜索优化RAG 检索

在RAG项目中&#xff0c;大模型生成的参考内容&#xff08;专业术语称为块&#xff09;来自前一步的检索&#xff0c;检索的内容在很大程度上直接决定了生成的效果&#xff0c;因此检索对于RAG项目至关重要&#xff0c;最常用的检索方法是关键字搜索和语义搜索。本文将分别介绍…

2025-3-24 leetcode刷题情况(动态规划——01背包)

一、416.分割等和子集 1.题目描述 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 2.代码 3.思路 首先进行边界检查&#xff0c;若数组为空则直接返回 false。接着计算数组元素总和&#xff…

Lineageos 22.1(Android 15)实现负一屏

一、前言 方案是参考的这位大佬的&#xff0c;大家可以去付费订阅支持一波。我大概理一下Android15的修改。 大佬的方案代码 二、Android15适配调整 1.bp调整&#xff0c;加入aidl引入&#xff0c;这样make之后就可以索引代码了 filegroup {name: "launcher-src"…

5G NR PRACH 随机接入前导序列

目录 一、前言二、随机接入前导序列的产生三、 N c s N_{cs} Ncs​的规划3.1、 L R A L_{RA} LRA​839 N c s N_{cs} Ncs​规划3.2、 L R A L_{RA} LRA​139 N c s N_{cs} Ncs​规划3.3、 N c s N_{cs} Ncs​确定方法 四、根序列的规划4.1、根序列的选择与确定4.2、循环移位 …

【VUE】day07 路由

【VUE】day07 路由 1. 路由2. 前端路由的工作方式3. 实现简易的前端路由4. 安装和配置路由4.1 安装vue-router包4.2 创建路由模块4.3 导入并挂在路由模块 5. 在路由模块中声明路由的对应关系5.1 router-view 1. 路由 在 Vue.js 中&#xff0c;路由&#xff08;Routing&#xf…

WPS宏开发手册——使用、工程、模块介绍

目录 系列文章前言1、开始1.1、宏编辑器使用步骤1.2、工程1.3、工程 系列文章 使用、工程、模块介绍 JSA语法 第三篇练习练习题&#xff0c;持续更新中… 前言 如果你是开发人员&#xff0c;那么wps宏开发对你来说手拿把切。反之还挺吃力&#xff0c;需要嘻嘻&#xf…

数学概念学习

# 欧式空间 ## 定义 日常生活观察到的几何空间&#xff1a;一维、平面和三维空间。 ## 点与向量 是欧式空间的基本元素。 ## 距离和内积 距离&#xff1a;通过欧几里得距离公式计算 内积&#xff08;点积&#xff09;&#xff1a; 通过两个向量的内积来测量他们的相似性&…

InnoDB 引擎核心知识点

InnoDB 引擎核心知识点 6.1 逻辑存储结构 表空间&#xff08;Tablespace&#xff09;&#xff1a;所有数据逻辑上存储在一个表空间中&#xff0c;物理上可能由多个文件组成。段&#xff08;Segment&#xff09;&#xff1a;分为数据段&#xff08;B树叶子节点&#xff09;、索引…

C++《红黑树》

在之前的篇章当中我们已经了解了基于二叉搜索树的AVL树&#xff0c;那么接下来在本篇当中将继续来学习另一种基于二叉搜索树的树状结构——红黑树&#xff0c;在此和之前学习AVL树类似还是通过先了解红黑树是什么以及红黑树的结构特点&#xff0c;接下来在试着实现红黑树的结构…

java实现coze平台鉴权+工作流调用(踩坑记录)

问题偏多建议大家看完文章后再开始实现 OAuth鉴权 https://www.coze.cn/open/docs/developer_guides/preparation https://www.coze.cn/open/docs/developer_guides/oauth_apps OAuth 授权码鉴权 https://www.coze.cn/open/docs/developer_guides/oauth_code 创建OAuth应…

2025年优化算法:龙卷风优化算法(Tornado optimizer with Coriolis force,TOC)

龙卷风优化算法&#xff08;Tornado optimizer with Coriolis force&#xff09;是发表在中科院二区期刊“ARTIFICIAL INTELLIGENCE REVIEW”&#xff08;IF&#xff1a;11.7&#xff09;的2025年智能优化算法 01.引言 当自然界的狂暴之力&#xff0c;化身数字世界的智慧引擎&…