HarmonyOS鸿蒙Next 6 如何使用 AppStorage+LocalStorage 实现跨组件 / 跨页面数据共享?

HarmonyOS鸿蒙Next 6 如何使用 AppStorage+LocalStorage 实现跨组件 / 跨页面数据共享?

问题描述

在鸿蒙 6 Stage 模型应用中,需要实现:1. 全局数据共享(如用户登录状态、主题配置);2. 页面间数据传递(如列表页选中项传递到详情页);3. 组件间数据同步(如设置页修改主题,首页实时更新)。尝试用@State@Link但跨页面无效,如何通过AppStorageLocalStorage实现高效、响应式的数据共享?关键字:鸿蒙 6、AppStorage、LocalStorage、数据共享、跨组件、跨页面、Stage 模型、响应式


更多关于HarmonyOS鸿蒙Next 6 如何使用 AppStorage+LocalStorage 实现跨组件 / 跨页面数据共享?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

一、原理解析

鸿蒙 6 的状态管理核心是「存储容器 + 装饰器」,两种存储容器分工明确:

存储容器 作用范围 持久化 核心装饰器
AppStorage 全局(整个应用) @StorageProp/@StorageLink
LocalStorage 局部(页面 / 组件树) 可选 @LocalStorageProp/@LocalStorageLink
  • Prop:单向绑定(只读,父组件修改后子组件同步);
  • Link:双向绑定(父子组件修改后相互同步);
  • 持久化:LocalStorage可通过persist方法持久化到沙箱,AppStorage需手动结合fs存储。

二、完整实现代码

1. 全局数据共享(AppStorage)

步骤 1:初始化全局数据(EntryAbility.ts)

import UIAbility from '@ohos.app.ability.UIAbility';
import AppStorage from '@ohos.app.ability.AppStorage';

export default class EntryAbility extends UIAbility {
  onCreate(want, launchParam) {
    // 初始化全局数据(应用启动时执行)
    AppStorage.SetOrCreate('userInfo', {
      userId: '',
      userName: '游客',
      isLogin: false
    });
    AppStorage.SetOrCreate('themeMode', 'light'); // 主题模式:light/dark
  }
}

步骤 2:组件中使用全局数据(首页)

import AppStorage from '@ohos.app.ability.AppStorage';
import router from '@ohos.router';

@Entry
@Component
struct HomePage {
  // 双向绑定全局主题模式
  @StorageLink('themeMode') themeMode: string = 'light';
  // 单向绑定用户信息(只读)
  @StorageProp('userInfo') userInfo: { userId: string; userName: string; isLogin: boolean } = {
    userId: '',
    userName: '游客',
    isLogin: false
  };

  build() {
    Column({ space: 20 })
      .width('100%')
      .height('100%')
      .backgroundColor(this.themeMode === 'dark' ? '#1E1E1E' : '#FFFFFF')
      .padding(20)
      .justifyContent(FlexAlign.Center) {
      Text(`当前用户:${this.userInfo.userName}`)
        .fontSize(20)
        .fontColor(this.themeMode === 'dark' ? '#FFFFFF' : '#000000')

      Button(this.userInfo.isLogin ? '退出登录' : '去登录')
        .onClick(() => {
          if (this.userInfo.isLogin) {
            // 退出登录:修改全局数据
            AppStorage.Set('userInfo', {
              userId: '',
              userName: '游客',
              isLogin: false
            });
          } else {
            router.pushUrl({ url: 'pages/LoginPage' });
          }
        })
        .width('80%')

      Button(`切换${this.themeMode === 'light' ? '深色' : '浅色'}主题`)
        .onClick(() => {
          // 切换主题:双向绑定,所有使用themeMode的组件会同步更新
          this.themeMode = this.themeMode === 'light' ? 'dark' : 'light';
        })
        .width('80%')
    }
  }
}

步骤 3:登录页修改全局数据

import AppStorage from '@ohos.app.ability.AppStorage';
import router from '@ohos.router';

@Entry
@Component
struct LoginPage {
  @State userName: string = '';

  build() {
    Column({ space: 20 })
      .width('100%')
      .height('100%')
      .padding(20)
      .justifyContent(FlexAlign.Center) {
      TextInput({
        placeholder: '请输入用户名',
        text: this.userName
      })
        .width('80%')
        .onChange((value) => {
          this.userName = value;
        })

      Button('登录')
        .onClick(() => {
          // 登录成功:修改全局用户信息
          AppStorage.Set('userInfo', {
            userId: '10086',
            userName: this.userName || '鸿蒙用户',
            isLogin: true
          });
          router.back(); // 返回首页,首页会自动同步数据
        })
        .width('80%')
    }
  }
}

2. 页面局部数据共享(LocalStorage + 持久化)

import LocalStorage from '@ohos.app.ability.LocalStorage';
import fs from '@ohos.file.fs';
import common from '@ohos.app.ability.common';

// 初始化LocalStorage(页面级)
const pageStorage = new LocalStorage({
  searchHistory: [] // 搜索历史
});

@Entry(storage: pageStorage)
@Component
struct SearchPage {
  private context = getContext(this) as common.UIAbilityContext;
  @State searchText: string = '';
  // 双向绑定LocalStorage的searchHistory
  @LocalStorageLink('searchHistory') searchHistory: string[] = [];

  build() {
    Column({ space: 20 })
      .width('100%')
      .height('100%')
      .padding(20) {
      TextInput({
        placeholder: '请输入搜索内容',
        text: this.searchText
      })
        .width('100%')
        .onChange((value) => {
          this.searchText = value;
        })

      Button('搜索')
        .onClick(() => {
          if (this.searchText && !this.searchHistory.includes(this.searchText)) {
            // 添加搜索历史(双向绑定,LocalStorage自动更新)
            this.searchHistory.unshift(this.searchText);
            // 持久化到沙箱(可选)
            this.persistSearchHistory();
          }
        })
        .width('100%')

      // 展示搜索历史
      List() {
        ForEach(this.searchHistory, (item) => {
          ListItem() {
            Text(item)
              .width('100%')
              .height(40)
              .lineHeight(40)
          }
        })
      }
      .width('100%')
    }
  }

  // 持久化搜索历史到沙箱
  private async persistSearchHistory() {
    const filePath = `${this.context.filesDir}/searchHistory.json`;
    await fs.writeFile(filePath, JSON.stringify(this.searchHistory));
  }

  // 页面加载时读取持久化数据
  aboutToAppear() {
    this.loadPersistedHistory();
  }

  private async loadPersistedHistory() {
    const filePath = `${this.context.filesDir}/searchHistory.json`;
    if (await fs.access(filePath)) {
      const content = await fs.readFile(filePath, 'utf-8');
      this.searchHistory = JSON.parse(content) || [];
    }
  }
}

三、避坑点

  1. 全局数据初始化:AppStorage的初始化需在EntryAbilityonCreate中执行,确保应用启动时数据已就绪;
  2. 类型一致性:SetOrCreate和组件中绑定的变量类型必须一致,否则会导致数据同步失败;
  3. 持久化差异:AppStorage不支持自动持久化,需手动结合fs存储;LocalStorage可通过persist方法自动持久化;
  4. 跨页面传递:AppStorage适合全局共享(如用户状态),LocalStorage适合页面内组件共享(如搜索历史);
  5. 性能优化:避免存储过大数据(如图片),建议存储 URL 或 ID,通过其他方式加载。

更多关于HarmonyOS鸿蒙Next 6 如何使用 AppStorage+LocalStorage 实现跨组件 / 跨页面数据共享?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next 6中,使用AppStorage和LocalStorage实现数据共享。AppStorage是全局单例,用于应用级状态共享,通过AppStorage.SetOrCreateAppStorage.Get访问。LocalStorage是页面级存储,通过LocalStorage实例在页面内组件间共享数据。跨页面共享时,可在页面UI中创建LocalStorage实例并绑定到子组件,或通过windowStage.loadContent传入。AppStorage支持与LocalStorage双向同步,使用@StorageLink@StorageProp装饰器建立关联。

在HarmonyOS Next Stage模型中,AppStorageLocalStorage是解决跨组件/跨页面数据共享的核心方案。你的场景可以这样实现:

1. 全局数据共享(AppStorage)

对于用户登录状态、主题配置等应用级全局数据,应使用AppStorage

  • 定义与初始化:在应用入口(如EntryAbility)或早期页面初始化全局数据。
    // 初始化AppStorage中的全局数据
    AppStorage.SetOrCreate<string>('userToken', '');
    AppStorage.SetOrCreate<boolean>('isDarkMode', false);
    AppStorage.SetOrCreate<string>('userName', '');
    
  • 组件内使用:在任意UI组件中,通过@StorageLink@StorageProp装饰器访问和响应数据变化。
    @Entry
    @Component
    struct HomePage {
      // @StorageLink:与AppStorage建立双向同步,修改会写回AppStorage
      @StorageLink('isDarkMode') isDarkMode: boolean = false;
      // @StorageProp:与AppStorage建立单向同步,本地修改不会写回
      @StorageProp('userName') userName: string = '';
    
      build() {
        Column() {
          Text(`当前主题: ${this.isDarkMode ? '深色' : '浅色'}`)
          Text(`用户名: ${this.userName}`)
          Button('切换主题')
            .onClick(() => {
              // 修改会同步到AppStorage,其他绑定此属性的组件将自动更新
              this.isDarkMode = !this.isDarkMode;
            })
        }
      }
    }
    

2. 页面间数据传递(LocalStorage)

对于页面级的数据共享(如列表页到详情页),使用LocalStorage。它通常与页面路由结合。

  • 列表页:在跳转前将数据存入LocalStorage,并传递存储实例的key。
    // 列表页 ListPage.ets
    @Component
    struct ListPage {
      private storage = new LocalStorage({ selectedItemId: '' });
    
      build() {
        Column() {
          List() {
            ForEach(this.itemList, item => {
              ListItem() {
                Text(item.name)
                  .onClick(() => {
                    // 1. 将选中项ID存入LocalStorage实例
                    this.storage.setOrCreate('selectedItemId', item.id);
                    // 2. 携带storage实例跳转
                    router.pushUrl({
                      url: 'pages/DetailPage',
                      params: { storageKey: this.storage.id } // 传递实例标识
                    });
                  })
              }
            })
          }
        }
      }
    }
    
  • 详情页:通过路由参数获取storageKey,并绑定到该LocalStorage实例。
    // 详情页 DetailPage.ets
    @Entry
    @Component
    struct DetailPage {
      private storageKey: string = '';
      // 通过@LocalStorageLink绑定到传入的LocalStorage实例
      @LocalStorageLink('selectedItemId') selectedItemId: string = '';
    
      aboutToAppear() {
        // 从路由参数中获取storageKey
        const params = router.getParams() as { storageKey: string };
        this.storageKey = params?.storageKey;
      }
    
      build() {
        Column() {
          // 使用LocalStorage实例
          Text(`选中项ID: ${this.selectedItemId}`)
            .localStorage(this.storageKey, this.storageKey) // 关键:绑定到指定实例
        }
      }
    }
    

3. 组件间数据同步(AppStorage + LocalStorage组合)

对于页面内组件间具有明确层级关系的组件树内的数据同步:

  • 父子/兄弟组件:优先使用@Provide@Consume装饰器,它们更轻量且类型安全。
  • 若组件树较复杂或需要持久化:可创建一个LocalStorage实例,在根组件创建并通过localStorage()修饰符逐级传递,子组件用@LocalStorageLink@LocalStorageProp绑定。
  • 全局性UI状态(如主题):直接使用AppStorage最为高效,确保任何组件修改都能全局响应。

关键区别与选择

  • AppStorage:应用单例,全局唯一。用于真正的全局状态(用户信息、主题、全局配置)。数据生命周期与应用一致。
  • LocalStorage:可创建多个实例。用于页面级或局部组件树的状态共享,数据生命周期与绑定它的UI组件树一致。常用于路由跳转时的数据传递。
  • @State/@Link:适用于单个组件内部直接父子组件间的状态管理,无法直接跨页面。

性能与最佳实践

  1. 按需使用:不要将所有数据都放入AppStorage,避免不必要的全局渲染更新。页面级数据优先用LocalStorage
  2. 类型安全:使用SetOrCreate<T>get<T>/set<T>方法时明确数据类型。
  3. 响应式装饰器选择
    • @StorageLink / @LocalStorageLink:需要双向同步时使用(组件可修改并写回存储)。
    • @StorageProp / @LocalStorageProp:仅需单向同步时使用(组件只读,或本地修改不写回存储)。
  4. 内存管理LocalStorage实例在绑定的UI组件卸载后会被垃圾回收。避免将长期需要的数据仅存储在临时页面的LocalStorage中。

通过AppStorage管理全局状态,结合LocalStorage处理页面级数据传递,可以清晰、高效地实现Stage模型下的跨组件/跨页面响应式数据共享。

回到顶部