对LocalStorage的浅显认识

191 阅读4分钟

LocalStorage是ArkTS为构建页面级别状态变量提供存储的内存内的“数据库”。LocalStorage可以实现同一个UIAbility下页面之间以及同一页面下组件之间的数据共享与同步。

LocalStorage初始化理解(重点)

当自定义组件初始化的时候,@LocalStorageProp(key)/@LocalStorageLink(key)装饰的变量会通过给定的key,绑定LocalStorage对应的属性,完成初始化。如果LocalStorage实例对象中存在该key,则通过@LocalStorageProp(key)/@LocalStorageLink(key)装饰的变量的初始值会被忽略。

 class Person {
   name: string = ''
   age: number = 0
 ​
   constructor(name: string, age: number) {
     this.name = name
     this.age = age
   }
 ​
 }
 ​
 let para: Record<string, Person> = {
   'p1' : new Person('', 18)
 };
 ​
 let storage: LocalStorage = new LocalStorage(para);
 ​
 @Entry(storage)
 @Component
 struct Index {
   // 当storage实例中存在键值对{'p1' : new Person('', 18)}, 所以下面的初始化会被忽略
   @LocalStorageLink('p1') pa: Person = new Person('小李', 20); 
   @State count: number = 0;
 ​
   build() {
     Row() {
       Column() {
         Text(this.pa.name)
           .fontSize(50)
           .fontWeight(FontWeight.Bold)
           .backgroundColor(Color.Gray)
       }
       .width('100%')
     }
     .height('100%')
   }
 }

本地初始化是必要的,因为无法保证LocalStorage一定存在给定的key。因此,如果LocalStorage实例中不存在属性,则编译器用该初始值初始化该属性,并存入LocalStorage中。下面的情况很好说明了这一点。

 let storage: LocalStorage = new LocalStorage();
 ​
 @Entry(storage)
 @Component
 struct Index {
   // 由于storage实例中不存在键值对,所以编译器会用下面的初始值{'p1': {'小李', 20}}存入storage实例对象中
   @LocalStorageLink('p1') pa: Person = new Person('小李', 20); 
   @State count: number = 0;
 ​
   build() {
     Row() {
       Column() {
         Text(this.pa.name)
           .fontSize(50)
           .fontWeight(FontWeight.Bold)
           .backgroundColor(Color.Gray)
       }
       .width('100%')
     }
     .height('100%')
   }
 }

此外,LocalStorage可以通过方法setOrCreate设置或修改键值对。

具体接口为:setOrCreate<T>(propName: string, newValue: T): boolean

如果propName已经在LocalStorage中存在,并且newValue和propName对应属性的值不同,则设置propName对应属性的值为newValue,否则状态变量不会通知UI刷新propName对应属性的值。

可以通过此方法为LocalStorage创建多个键值对

同一页面下组件间的数据共享与同步

使用步骤

一、使用构造函数创建LocalStorage实例对象storage

LocalStorage的构造函数接口如下:constructor(initializingProperties?: Object)

通常使用泛型工具类Record<string, T>来构造Object类型。initializingProperties需要包含一个string类型的键用于标识LocalStorage实例以及一个指定类型的实例对象。

被@Component装饰的组件最多可以访问一个LocalStorage实例和AppStorage,未被@Entry装饰的组件不可被独立分配LocalStorage实例,只能接受父组件通过@Entry传递来的LocalStorage实例。一个LocalStorage实例在组件树上可以被分配给多个组件。

因此,实例化LocalStorage对象的代码通常写在组件外。

 class Person {
   name: string = ''
   age: number = 0
 ​
   constructor(name: string, age: number) {
     this.name = name
     this.age = age
   }
 ​
 }
 ​
 let para: Record<string, Person> = {
   'p1' : new Person('测试员-小王', 18)
 };
 ​
 let storage: LocalStorage = new LocalStorage(para);

二、用@Entry(LocalStorage实例对象名称)装饰组件

@Entry装饰的自定义组件为页面的默认入口组件,需要给入口组件通过参数传递LocalStorage实例对象的名称。

 class Person {
   name: string = ''
   age: number = 0
 ​
   constructor(name: string, age: number) {
     this.name = name
     this.age = age
   }
 ​
 }
 ​
 let para: Record<string, Person> = {
   'p1' : new Person('测试员-小王', 18)
 };
 ​
 let storage: LocalStorage = new LocalStorage(para);
 ​
 @Entry(storage) 
 @Component
 struct Index {
   build() {
   ...
   }
 }

三、使用@LocalStorageProp或@LocalStorageLink装饰需要在组件间传递的变量

注意:@LocalStorageProp和@LocalStorageLink允许装饰的变量类型只有Object、class、string、number、boolean、enum类型,以及这些类型的数组。API12及以上支持Map、Set、Date类型。API12及以上支持上述支持类型的联合类型,比如string | number, string | undefined 或者 ClassA | null。

@LocalStorageProp和@LocalStorageLink都不支持从父节点初始化,只能从LocalStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化。

 class Person {
   name: string = ''
   age: number = 0
 ​
   constructor(name: string, age: number) {
     this.name = name
     this.age = age
   }
 ​
 }
 ​
 let param: Record<string, Person> = {
   'p1' : new Person('测试员小王', 0)
 };
 ​
 let storage: LocalStorage = new LocalStorage(param);
 ​
 @Entry(storage)
 @Component
 struct Index {
   @LocalStorageLink('p1') pa: Person = new Person('小李', 20);
   @State count: number = 0;
 ​
   build() {
     Row() {
       Column() {
         Text(this.pa.name)
           .fontSize(50)
           .fontWeight(FontWeight.Bold)
           .backgroundColor(Color.Gray)
           .onClick(() => {
             this.pa.name = '测试员-小红'
           })
         // 使用LocalStorage 实例localStorage2
         Child1({ count: this.count })
           .width('100')
           .backgroundColor(Color.Pink)
       }
       .width('100%')
     }
     .height('100%')
   }
 }
 ​
 ​
 @Component
 struct Child1 {
   @Link count: number;
   @LocalStorageLink('p1') pb: Person = new Person('小黎明', 20);
 ​
   build() {
     Text(this.pb.name)
       .fontSize(50)
       .fontWeight(FontWeight.Bold)
   }
 }

注意:未被@Entry装饰的组件不可被独立分配LocalStorage实例,只能接受父组件通过@Entry传递来的LocalStorage实例

同一UIAbility下页面间的数据共享与同步

方法一 将当前页面下LocalStorage实例对象导出

具体操作大致为:

 // page1.ets
 ....
 export let storage: LocalStorage = new LocalStorage(param);
 ....
 ​
 ​
 // page2.ets
 import {storage} from 'xx/page1'

方法二 通过getShared获取LocalStorage实例

具体步骤:

一、在在所属UIAbility中创建LocalStorage实例,并调用windowStage

注意需要将创建的LocalStorage实例传递给windowStage.loadContent的第二个参数。

 // EntryAbility.ets
 import { UIAbility } from '@kit.AbilityKit';
 import { window } from '@kit.ArkUI';
 ​
 export default class EntryAbility extends UIAbility {
 para:Record<string, number> = { 'PropA': 47 };
 storage: LocalStorage = new LocalStorage(this.para);
 ​
 onWindowStageCreate(windowStage: window.WindowStage) {
 windowStage.loadContent('pages/Index', this.storage);
 }
 }

LocalStorage.getShared()只在模拟器或者实机上才有效,在Previewer预览器中使用不生效。

LocalStorage.getShared()只在模拟器或者实机上才有效,在Previewer预览器中使用不生效。

LocalStorage.getShared()只在模拟器或者实机上才有效,在Previewer预览器中使用不生效。

二、在需求页面通过getShared获取storage实例

 // 例如index.ets需要用到storage实例
 // 通过getShared接口获取stage共享的LocalStorage实例
 let storage = LocalStorage.getShared()