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

embedded/2025/4/1 23:29:23/

文章大纲

  • 引言
  • 一、在代码逻辑使用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.ppmy.cn/embedded/176568.html

相关文章

NAT 模式

使用LVS的 NAT 模式实现 3 台RS的轮询访问。IP地址和主机自己规划。 1.节点规划 主机角色系统网络IPclientclientredhat 9.5仅主机192.168.180.100/24lvslvsredhat 9.5仅主机 NAT192.168.180.200/24 VIP 192.168.72.8/24 DIPnginxrs1redhat 9.5NAT192.168.226.7/24nginxrs2r…

挖洞日记 | Webpack实操

目录&#xff1a; 1 信息搜集 2 实战教学 技巧1 技巧2 3 pdf存储xss 4 webpack知识补充 地址&#xff1a;zkanzz 1 信息搜集 当然哈&#xff0c;首先还是先想办法搞到一个统一身份认证&#xff0c;教给大家怎么搞&#xff1a; 这里我又找到了我一个高中同学&#xff0…

采样率24G DA子卡

FMC DAC 子卡 单通道16bit 12GS/s 或8bit 24GS/s&#xff1b; 双通道16bit 6.2GS/s 或8bit 12GS/s&#xff1b; DA子卡是一款高分辨率、高采样率DAC FMC子板。它提供2路16bit 6.2GS/s或8bit 12GS/s D/A通道或者1路16bit 12GS/s或8bit 24GS/s D/A通道&#xff0c;输出带宽 (-3dB…

深入理解智能家居领域中RS485、Modbus、KNX 和 Zigbee协议概念

首先详细介绍一下 RS485 和 Modbus 这两个在工业自动化和数据通讯领域中非常重要的概念。 RS485 1. 定义与特点 RS485 标准&#xff1a;RS485 是一种串行通信标准&#xff0c;也称为TIA-485标准&#xff0c;主要用于数据传输。它规定了物理层的电气特性&#xff0c;与数据格式…

nginx代理前端请求

一&#xff0c;项目配置 我在 ip 为 192.168.31.177 的机器上使用 vue3 开发前端项目&#xff0c;项目中使用 axios 调用后端接口。 这是 axios 的配置&#xff1a; import axios from axios;const request axios.create({baseURL: http://192.168.31.177:8001,// 设置请求…

图像信号处理平台设计原理图:721-基于VU9P的32+8路光纤交换板卡硬件设计

一、板卡概述 本卡是基于IDT TSI721桥芯片&#xff0c;用于实现Serial RapidIO(S-RIO) Gen2.1到PCI Express (PCIE) Gen2.1协议转换&#xff0c;将基于RapidIO的对等网络多重处理器集群拓展至x86处理器环境&#xff0c;能够实现基于RapidIO的对等网络多重处理器集群和基于x86…

项目流程中关键节点的测试类型

一、全流程测试框架图 #mermaid-svg-LmUdhLObstSpThwP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-LmUdhLObstSpThwP .error-icon{fill:#552222;}#mermaid-svg-LmUdhLObstSpThwP .error-text{fill:#552222;strok…

Spring Boot整合SSE实现消息推送:跨域问题解决与前后端联调实战

摘要 本文记录了一次完整的Spring Boot整合Server-Sent Events&#xff08;SSE&#xff09;实现实时消息推送的开发过程&#xff0c;重点分析前后端联调时遇到的跨域问题及解决方案。通过CrossOrigin注解的实际应用案例&#xff0c;帮助开发者快速定位和解决类似问题。 一、项…