HarmonyOS 6.0 LocalStorage页面级存储
HarmonyOS NEXT有三层状态存储LocalStorage页面级、AppStorage全局级、PersistentStorage持久化级。LocalStorage是其中最轻量的——只在UIAbility内共享不跨进程不写磁盘。但它的双向绑定装饰器LocalStorageLink和单向绑定LocalStorageProp让它在组件树间共享状态时比手动传参方便得多。LocalStorage基础APIprivatestorage:LocalStoragenewLocalStorage();// 设置this.storage.set(key,value);this.storage.set(counter,42);// 获取(泛型)constval:string|undefinedthis.storage.getstring(key);constnum:number|undefinedthis.storage.getnumber(counter);// 判断存在constexists:booleanthis.storage.has(key);// 删除this.storage.delete(key);// 获取所有keyconstkeysIter:IterableIteratorstringthis.storage.keys();constkeys:string[][];letresult:IteratorResultstringkeysIter.next();while(!result.done){keys.push(result.value);resultkeysIter.next();}// 清空this.storage.clear();// 数量constsize:numberthis.storage.size();重点keys()返回的是IterableIterator不是string[]。不能直接赋值给数组变量必须手动迭代转成数组。这个坑很容易踩——写const keys: string[] this.storage.keys()编译报类型不匹配。get返回T | undefined不是T。所以取值后必须判undefinedconstsavedTheme:string|undefinedthis.storage.getstring(app_theme);if(savedTheme!undefined){this.themeModesavedTheme;}不判undefined直接用运行时可能crash。键值对CRUD实战interfaceKeyValue{key:string;value:string;}StatekvList:KeyValue[][];privatesaveKV():void{if(this.storageKey.length0||this.storageValue.length0){return;}this.storage.set(this.storageKey,this.storageValue);this.storageKey;this.storageValue;this.refreshList();}privaterefreshList():void{constkeysIter:IterableIteratorstringthis.storage.keys();constkeys:string[][];letresult:IteratorResultstringkeysIter.next();while(!result.done){keys.push(result.value);resultkeysIter.next();}constlist:KeyValue[][];for(leti0;ikeys.length;i){constval:string|undefinedthis.storage.getstring(keys[i]);list.push({key:keys[i],value:val!undefined?val:});}this.kvListlist;}privatedeleteKV(key:string):void{this.storage.delete(key);this.refreshList();}每次增删后refreshList重新构建kvList触发ForEach刷新。这种方式简单直接数据量小时性能完全够。LocalStorageLink — 双向绑定LocalStorageLink让组件属性和LocalStorage中的值双向同步// UIAbility或页面入口letstorage:LocalStoragenewLocalStorage();storage.setOrCreate(counter,0);Entry(storage)Componentstruct PageA{LocalStorageLink(counter)counter:number0;build(){Column(){Text(this.counter.toString())Button(1).onClick((){this.counter;// 自动同步回LocalStorage})}}}LocalStorageLink的参数是LocalStorage中的key名。组件内修改this.counter会自动写回LocalStorage其他绑定同一key的组件也会同步更新。默认值 0是LocalStorage中不存在该key时的初始值。如果key已存在用存储的值不存在用默认值创建。LocalStorageProp — 单向绑定LocalStorageProp是单向的——LocalStorage变化同步到组件但组件内修改不写回Componentstruct ChildComp{LocalStorageProp(theme)theme:stringlight;build(){Column(){Text(this.theme)// 可以读取}}// 修改this.theme不会影响LocalStorage中的值}单向绑定适合只读共享场景——比如主题色、全局配置子组件只需要读取不需要修改。双向vs单向选型装饰器LocalStorage→组件组件→LocalStorage适用场景LocalStorageLink同步同步计数器、开关、表单数据LocalStorageProp同步不同步主题、配置、只读状态计数器这种需要多组件协同修改的用Link。主题这种只有设置页改、其他页只读的用Prop。Entry接收LocalStorage要让LocalStorageLink/Prop生效Entry必须接收LocalStorage实例letstorage:LocalStoragenewLocalStorage();storage.setOrCreate(app_counter,0);storage.setOrCreate(app_theme,light);Entry(storage)Componentstruct MyPage{LocalStorageLink(app_counter)counter:number0;LocalStorageProp(app_theme)theme:stringlight;}Entry(storage)把storage实例注入组件树子组件的LocalStorageLink/Prop才能找到对应的key。三种存储对比特性LocalStorageAppStoragePersistentStorage作用域UIAbility内应用全局应用全局磁盘跨页面同UIAbility可以全应用可以全应用可以跨UIAbility不可以可以可以持久化否(进程退出丢失)否是(写磁盘)装饰器LocalStorageLink/PropStorageLink/PropStorageLink/Prop适合数据页面间共享的临时数据全局状态(登录/配置)需要持久化的设置创建方式new LocalStorage()自动创建PersistentStorage选型原则同一个UIAbility内多页面共享 → LocalStorage整个应用全局共享 → AppStorage应用重启后需要恢复 → PersistentStorage轻量键值持久化 → Preferences(kit.ArkData)计数器持久化示例LocalStorage本身不持久化但可以用Preferences做持久化启动时从Preferences恢复到LocalStorageimport{preferences}fromkit.ArkData;aboutToAppear():void{// 从Preferences恢复letprefs:preferences.Preferencespreferences.getSync(this.context,{name:app_data});constsavedCounter:number|undefinedprefs.getSync(counter,-1)asnumber;if(savedCounter0){this.countersavedCounter;this.storage.set(app_counter,this.counter);}this.refreshList();}aboutToDisappear():void{// 保存到Preferencesletprefs:preferences.Preferencespreferences.getSync(this.context,{name:app_data});prefs.putSync(counter,this.counter);prefs.flush();}这种LocalStoragePreferences的组合兼顾了响应式UI和持久化——UI层用LocalStorage驱动持久化层用Preferences兜底。主题切换示例用LocalStorage管理主题状态动态改变背景色StatethemeMode:stringlight;privatetoggleTheme():void{this.themeModethis.themeModelight?dark:light;this.storage.set(app_theme,this.themeMode);}build(){Column(){// ...}.backgroundColor(this.themeModedark?#1a1a2e:#f4f5f7)}主题状态存LocalStorage页面重载时从LocalStorage恢复。注意这不是真正的双向绑定(没用LocalStorageLink)而是手动get/set——这种方式更灵活可以在aboutToAppear里做初始化逻辑。clear的副作用this.storage.clear();clear会删除所有键值对包括其他组件通过LocalStorageLink绑定的数据。所有绑定了该storage的组件都会收到undefined值可能导致UI异常。更安全的做法是只delete需要清除的key。线程安全LocalStorage在UI线程内操作不需要考虑线程安全。但如果从TaskPool或其他线程访问需要用emitter或UIContext.postDelayed回调到UI线程操作。踩坑清单问题原因解决keys()类型报错返回IterableIterator不是string[]手动迭代转数组get返回undefinedkey不存在判undefined后使用LocalStorageLink不生效Entry没传storageEntry(storage)clear后UI异常所有绑定收到undefined改用逐个delete主题不切换手动get/set没刷新确保State变量也更新子组件拿不到值没用LocalStorageProp子组件声明装饰器重启后数据丢失LocalStorage不持久化配合PreferencesLocalStorage的使用哲学是够用就好——页面级共享、声明式绑定、轻量快速。不需要持久化的共享状态用LocalStorage最合适需要持久化就加Preferences需要全局就换AppStorage。三层存储各司其职别拿LocalStorage干AppStorage的活。