页面级UI状态存储LocalStorage

       

目录

1、@LocalStorageProp

3、LocalStorage的使用

4、从UI内部使用LocalStorage

5、@LocalStorageProp和LocalStorage单向同步的简单场景

6、@LocalStorageLink和LocalStorage双向同步的简单场景

7、兄弟节点之间同步状态变量


 LocalStorage是页面级的UI状态存储,通过@Entry装饰器接收的参数可以在页面内共享同一个LocalStorage实例。LocalStorage也可以在UIAbility内,页面间共享状态。

        LocalStorage是ArkTS为构建页面级别状态变量提供存储的内存内“数据库”。

  • 应用程序可以创建多个LocalStorage实例,LocalStorage实例可以在页面内共享,也可以通过GetShared接口,获取在UIAbility里创建的GetShared,实现跨页面、UIAbility内共享。
  • 组件树的根节点,即被@Entry装饰的@Component,可以被分配一个LocalStorage实例,此组件的所有子组件实例将自动获得对该LocalStorage实例的访问权限;
  • 被@Component装饰的组件最多可以访问一个LocalStorage实例和AppStorage,未被@Entry装饰的组件不可被独立分配LocalStorage实例,只能接受父组件通过@Entry传递来的LocalStorage实例。一个LocalStorage实例在组件树上可以被分配给多个组件。
  • LocalStorage中的所有属性都是可变的。

        应用程序决定LocalStorage对象的生命周期。当应用释放最后一个指向LocalStorage的引用时,比如销毁最后一个自定义组件,LocalStorage将被JS Engine垃圾回收。

LocalStorage根据与@Component装饰的组件的同步类型不同,提供了两个装饰器:

  • @LocalStorageProp:@LocalStorageProp装饰的变量和与LocalStorage中给定属性建立单向同步关系。
  • @LocalStorageLink:@LocalStorageLink装饰的变量和在@Component中创建与LocalStorage中给定属性建立双向同步关系。
  • LocalStorage创建后,命名属性的类型不可更改。后续调用Set时必须使用相同类型的值。
  • LocalStorage是页面级存储,GetShared接口仅能获取当前Stage通过windowStage.loadContent传入的LocalStorage实例,否则返回undefined。

1、@LocalStorageProp

        在上文中已经提到,如果要建立LocalStorage和自定义组件的联系,需要使用@LocalStorageProp和@LocalStorageLink装饰器。使用@LocalStorageProp(key)/@LocalStorageLink(key)装饰组件内的变量,key标识了LocalStorage的属性。

        当自定义组件初始化的时候,@LocalStorageProp(key)/@LocalStorageLink(key)装饰的变量会通过给定的key,绑定LocalStorage对应的属性,完成初始化。本地初始化是必要的,因为无法保证LocalStorage一定存在给定的key(这取决于应用逻辑是否在组件初始化之前在LocalStorage实例中存入对应的属性)。

        @LocalStorageProp(key)是和LocalStorage中key对应的属性建立单向数据同步,我们允许本地改变的发生,但是对于@LocalStorageProp,本地的修改永远不会同步回LocalStorage中,相反,如果LocalStorage给定key的属性发生改变,改变会被同步给@LocalStorageProp,并覆盖掉本地的修改。

  • 从LocalStorage的对应属性到组件的状态变量。组件本地的修改是允许的,但是LocalStorage中给定的属性一旦发生变化,将覆盖本地的修改。
  • 被@LocalStorageProp装饰的变量必须指定初值,如果LocalStorage实例中不存在属性,则作为初始化默认值,并存入LocalStorage中。
  • @LocalStorageProp不支持从父节点初始化,只能从LocalStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化。

        框架行为说明:

  • 当@LocalStorageProp(key)装饰的数值改变被观察到时,修改不会被同步回LocalStorage对应属性键值key的属性中。
  • 当前@LocalStorageProp(key)单向绑定的数据会被修改,即仅限于当前组件的私有成员变量改变,其他的绑定该key的数据不会同步改变。
  • 当@LocalStorageProp(key)装饰的数据本身是状态变量,它的改变虽然不会同步回LocalStorage中,但是会引起所属的自定义组件的重新渲染。
  • 当LocalStorage中key对应的属性发生改变时,会同步给所有@LocalStorageProp(key)装饰的数据,@LocalStorageProp(key)本地的修改将被覆盖。

        如果我们需要将自定义组件的状态变量的更新同步回LocalStorage,就需要用到@LocalStorageLink。

        @LocalStorageLink(key)是和LocalStorage中key对应的属性建立双向数据同步:

  1. 本地修改发生,该修改会被写回LocalStorage中;
  2. LocalStorage中的修改发生后,该修改会被同步到所有绑定LocalStorage对应key的属性上,包括单向(@LocalStorageProp和通过prop创建的单向绑定变量)、双向(@LocalStorageLink和通过link创建的双向绑定变量)变量。
  •  从LocalStorage的对应属性到自定义组件,从自定义组件到LocalStorage对应属性。
  • 被装饰变量的初始值必须指定,如果LocalStorage实例中不存在属性,则作为初始化默认值,并存入LocalStorage中。
  • @LocalStorageLink不支持从父节点初始化,只能从LocalStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化。

         框架行为说明:

  1. 当@LocalStorageLink(key)装饰的数值改变被观察到时,修改将被同步回LocalStorage对应属性键值key的属性中。
  2. LocalStorage中属性键值key对应的数据一旦改变,属性键值key绑定的所有的数据(包括双向@LocalStorageLink和单向@LocalStorageProp)都将同步修改;
  3. 当@LocalStorageLink(key)装饰的数据本身是状态变量,它的改变不仅仅会同步回LocalStorage中,还会引起所属的自定义组件的重新渲染。

3、LocalStorage的使用

let storage = new LocalStorage({ 'PropA': 47 }); // 创建新实例并使用给定对象初始化
let propA = storage.get('PropA') // propA == 47
let link1 = storage.link('PropA'); // link1.get() == 47
let link2 = storage.link('PropA'); // link2.get() == 47
let prop = 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

4、从UI内部使用LocalStorage

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

本示例以@LocalStorage为例,展示了:

  • 使用构造函数创建LocalStorage实例storage;
  • 使用@Entry装饰器将storage添加到CompA顶层组件中;
  • @LocalStorageLink绑定LocalStorage对给定的属性,建立双向数据同步。
    // 创建新实例并使用给定对象初始化
    let storage = new LocalStorage({ 'PropA': 47 });@Component
    struct Child {// @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定@LocalStorageLink('PropA') storLink2: number = 1;build() {Button(`Child from LocalStorage ${this.storLink2}`)// 更改将同步至LocalStorage中的'PropA'以及Parent.storLink1.onClick(() => this.storLink2 += 1)}
    }
    // 使LocalStorage可从@Component组件访问
    @Entry(storage)
    @Component
    struct CompA {// @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定@LocalStorageLink('PropA') storLink1: number = 1;build() {Column({ space: 15 }) {Button(`Parent from LocalStorage ${this.storLink1}`) // initial value from LocalStorage will be 47, because 'PropA' initialized already.onClick(() => this.storLink1 += 1)// @Component子组件自动获得对CompA LocalStorage实例的访问权限。Child()}}
    }

    5、@LocalStorageProp和LocalStorage单向同步的简单场景


// 创建新实例并使用给定对象初始化
let storage2 = new LocalStorage({'PropA' : 47 });// 使LocalStorage可从@Component组件访问
@Entry(storage2)
@Component
struct LocalStorageDemo2Page {// @LocalStorageProp变量装饰器与LocalStorage中的'PropA'属性建立单向绑定@LocalStorageProp('PropA') storeProp1: number = 1;build() {Column({ space: 15 }) {// 点击后从47开始加1,只改变当前组件显示的storeProp1,不会同步到LocalStorage中Button(`Change from LocalStorageProp ${this.storeProp1}`).onClick(() => {this.storeProp1 += 1})Button(`Change LocalStorage + 1`).onClick(() => {//直接修改LocalStorage,会同步回@LocalStorageProp标记的属性let value: number = storage2.get('PropA')console.log(`value = ${value}`)storage2.set('PropA', value + 1)})LocalStorage2Child()}}
}@Component
struct LocalStorage2Child {// @LocalStorageProp变量装饰器与LocalStorage中的'PropA'属性建立单向绑定@LocalStorageProp('PropA') storeProp2: number = 2;build() {Column({ space: 15 }) {// 当LocalStorageDemo2Page改变时,当前storeProp2不会改变,显示47Text(`Change from child LocalStorageProp ${this.storeProp2}`).onClick(() => {this.storeProp2 += 1})}}
}

        允许结果如下:

         

        按钮Change LocalStorage会直接修改LocalStorage对象的值,因此该修改会同步回@LocalStorageProp,也就是图中的第一个、第三个按钮在第二个按钮点击的时候会更新UI显示,而单独点击第一个、第三个按钮只是修改了@LocalStorageProp装饰的变量,由于变量同步时单向的因此,不会触发其他按钮的UI更新。也就证明了数据只能从LocalStorage -> @LocalStorageProp的更新。

6、@LocalStorageLink和LocalStorage双向同步的简单场景


// 创建新实例并使用给定对象初始化
let storage = new LocalStorage({'PropA' : 47 });// 使LocalStorage可从@Component组件访问
@Entry(storage)
@Component
struct LocalStorageDemo1Page {// @LocalStorageProp变量装饰器与LocalStorage中的'PropA'属性建立单向绑定@LocalStorageLink('PropA') storeLink1: number = 1;build() {Column({ space: 15 }) {// 点击后从47开始加1,只改变当前组件显示的storeProp1,不会同步到LocalStorage中Button(`Change from LocalStorageProp ${this.storeLink1}`).onClick(() => {this.storeLink1 += 1})Button(`Change LocalStorage + 1`).onClick(() => {//直接修改LocalStorage,会同步回@LocalStorageProp标记的属性let value: number = storage.get('PropA')console.log(`value = ${value}`)storage.set('PropA', value + 1)})LocalStorageChild()}}
}@Component
struct LocalStorageChild {// @LocalStorageProp变量装饰器与LocalStorage中的'PropA'属性建立单向绑定@LocalStorageLink('PropA') storeLink: number = 2;build() {Column({ space: 15 }) {// 当LocalStorageDemo1Page改变时,当前storeProp不会改变,显示47Text(`Change from child LocalStorageProp ${this.storeLink}`).onClick(() => {this.storeLink += 1})}}
}

        运行结果如下: 

        

        按钮Change LocalStorage会直接修改LocalStorage对象的值,因此该修改会同步回@LocalStorageLink,也就是图中的第一个、第三个按钮在第二个按钮点击的时候会更新UI显示,单独点击第一个、第三个按钮会修改@LocalStorageLink装饰的变量,由于变量同步是双向的,因此会触发其他按钮的UI更新。也就证明了数据从LocalStorage <----> @LocalStorageLink的更新双向的。 

7、兄弟节点之间同步状态变量

        下面的示例展示了通过@LocalStorageLink双向同步兄弟节点之间的状态。

let storage4 = new LocalStorage({ countStorage: 1 });/*** 兄弟节点之间同步状态变量*/
@Component
struct LocalStorageChild4 {// 子组件实例的名字label: string = 'no name';// 和LocalStorage中“countStorage”的双向绑定数据@LocalStorageLink('countStorage') playCountLink: number = 0;build() {Row() {Text(this.label).width(50).height(60).fontSize(12)Text(`playCountLink ${this.playCountLink}: inc by 1`).onClick(() => {this.playCountLink += 1;}).width(200).height(60).fontSize(12)}.width(300).height(60)}
}@Entry(storage4)
@Component
struct LocalStorageDemo4Page {@LocalStorageLink('countStorage') playCount: number = 0;build() {Column() {Row() {Text('Parent').width(50).height(60).fontSize(12)Text(`playCount ${this.playCount} dec by 1`).onClick(() => {this.playCount -= 1;}).width(250).height(60).fontSize(12)}.width(300).height(60).margin({top: 48})Row() {Text('LocalStorage').width(50).height(60).fontSize(12)Text(`countStorage ${this.playCount} incr by 1`).onClick(() => {storage4.set<number>('countStorage', 1 + storage4.get<number>('countStorage'));}).width(250).height(60).fontSize(12)}.width(300).height(60)LocalStorageChild4({ label: 'ChildA' })LocalStorageChild4({ label: 'ChildB' })Text(`playCount in LocalStorage for debug ${storage4.get<number>('countStorage')}`).width(300).height(60).fontSize(12)}}
}

        运行结果如下:

先看Parent自定义组件中发生的变化:

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

Child自定义组件中的变化:

  1. playCountLink的刷新会同步回LocalStorage,并且引起兄弟组件和父组件相应的刷新。

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

        上面的实例中,LocalStorage的实例仅仅在一个@Entry装饰的组件和其所属的子组件(一个页面)中共享,如果希望其在多个视图中共享,可以在所属UIAbility中创建LocalStorage实例,并调用windowStage.loadContent。

// EntryAbility.ts
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
let para:Record<string,number> = { 'PropA': 47 };
let localStorage: LocalStorage = new LocalStorage(para);
export default class EntryAbility extends UIAbility {storage: LocalStorage = localStorageonWindowStageCreate(windowStage: window.WindowStage) {windowStage.loadContent('pages/Index', this.storage);}
}

        在UI页面通过GetShared接口获取在通过loadContent共享的LocalStorage实例。

// 通过GetShared接口获取stage共享的LocalStorage实例
let storage = LocalStorage.GetShared()@Entry(storage)
@Component
struct CompA {// can access LocalStorage instance using // @LocalStorageLink/Prop decorated variables@LocalStorageLink('PropA') varA: number = 1;build() {Column() {Text(`${this.varA}`).fontSize(50)}}
}

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

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

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

相关文章

Python中__getitem__的奇妙应用

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 理解 __getitem__ 方法 1 基本概念 在Python中&#xff0c;__getitem__ 是一个重要的魔法方法&#xff0c;用于实现对象的索引访问。当使用类似 obj[index] 的方式访问对象时&#xff0c;Python 解释器会自动调…

【toolschain algorithm cpp ros】cpp工厂模式实现--后续填充具体规划算法,控制器版的已填充了算法接入了仿真器

写在前面 现在局势危机&#xff0c;于是想复习一下之前写的设计模式&#xff0c;之前提到&#xff0c;做过一个闭环仿真器&#xff08;借用ros&#xff09;&#xff0c;见https://blog.csdn.net/weixin_46479223/article/details/134864123我的控制器的建立遵循了工厂模式&…

Uniapp 开发 BLE

BLE 低功耗蓝牙&#xff08;Bluetooth Low Energy&#xff0c;或称Bluetooth LE、BLE&#xff0c;旧商标Bluetooth Smart&#xff09;&#xff0c;用于医疗保健、运动健身、安防、工业控制、家庭娱乐等领域。在如今的物联网时代下大放异彩&#xff0c;扮演者重要一环&#xff…

threejs中修改鼠标cursor不生效的问题修复

需求&#xff1a; 当鼠标hover一个元素时&#xff0c;cursor为自定义的图标 问题描述&#xff1a; threejs中修改canvas的鼠标cursor为自定义的图标不生效。 问题原因&#xff1a; 引入了dragcontrols&#xff0c;查看dragControls的代码&#xff0c;可以看到代码中有对cur…

世微AP5101C高压线性LED恒流驱动芯片 3D打印机LED指示灯驱动IC

产品描述 AP5101C 是一款高压线性 LED 恒流 芯片 &#xff0c; 简单 、 内置功率管 &#xff0c; 适用于 6- 100V 输入的高精度降压 LED 恒流驱动 芯片。电流2.0A。 AP5101C 可实现内置MOS 做 2.0A, 外置MOS 可做 3.0A 的。 AP5101C 内置温度保护功能 &#xff0c;温度保 护点…

3DMAX英文版怎么切换到中文版?

3DMAX英文换到中文版的方法 3dMax是专业三维建模、渲染和动画软件&#xff0c;它使你能够创建广阔的真实世界和各种高级设计。 -使用强大的建模工具为环境和景观注入活力。 -使用直观的纹理和着色工具创建精细的细节设计和道具。 -迭代并制作具有完全艺术控制的专业级渲染图…

深眸科技以AI+3D视觉技术引领技术创新,赋予工业自动化新的活力

随着工业4.0和智能制造时代的到来&#xff0c;3D机器视觉在工业各领域的应用越来越重要。这种技术改变了传统工业的生产方式&#xff0c;为现代工业带来了更高的生产效率和更精确的质量控制&#xff0c;广泛涉及物体识别、产品检测、尺寸测量、视觉引导定位等环节。 在工业领域…

【CMake保姆级教程】定义变量、指定C++标准、指定输出路径

文章目录 前言一、变量1.1 为什么需要变量&#xff1f;1.2 set的使用1.3 使用变量 二、指定C标准2.1 为什么需要指定C标准&#xff1f;2.2 指定使用的C标准 三、指定输出路径3.1 为什么需要指定输出路径&#xff1f;3.2 设置输出路径 总结 前言 CMake是一个强大的构建工具&…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之TextInput输入框组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之TextInput输入框组件 一、操作环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、TextInput 接口 TextInput(value?:{placeholder?: ResourceStr, tex…

[每周一更]-(第38期):Go常见的操作消息队列

在Go语言中&#xff0c;常见的消息队列有以下几种&#xff1a; RabbitMQ&#xff1a;RabbitMQ是一个开源的AMQP&#xff08;高级消息队列协议&#xff09;消息代理软件&#xff0c;用于支持多种编程语言&#xff0c;包括Go语言。RabbitMQ提供了可靠的消息传递机制和灵活的路由…

列举mfc140u.dll丢失的解决方法,常见的mfc140u.dll问题

在使用电脑的过程中&#xff0c;有时会遇到mfc140u.dll文件丢失的问题&#xff0c;导致一些应用程序无法正常启动。本文将介绍mfc140u.dll丢失的常见原因&#xff0c;并提供相应的解决办法。同时&#xff0c;还会列举一些与mfc140u.dll丢失相关的常见问题和解答。 第一部分&…

冬至前后,安身静体

今天&#xff0c;本“人民体验官”推广人民日报官方微博文化产品《今日&#xff0c;#冬至#》。 图&#xff1a;来源“人民体验官”推广平台 冬至这一天&#xff0c;是一年中白昼时间最短、黑夜时间最长的一天&#xff0c;也是离春天不远的最严峻的一道关隘&#xff0c;所以有古…