在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一、引言
在 HarmonyOS 应用开发中,状态管理 是构建流畅、可维护 UI 的核心挑战之一。当用户在一个页面切换了主题色,跳转到另一个页面后颜色却恢复了默认 —— 这种体验显然不够"原生"。

鸿蒙 ArkTS 提供了三层级的状态管理方案:

层级 存储方案 生命周期 适用场景
组件级 @State / @Prop 组件销毁即释放 局部 UI 状态
页面级 @LocalStorage / @LocalStorageProp 页面销毁即释放 页面内的临时偏好
应用级 AppStorage / @StorageProp / @StorageLink 应用进程级别 全局主题、用户信息
本文将围绕 应用级持久化 这一主题,深入剖析 @StorageProp + @LocalStorage + AppStorage 三者的配合方式,并通过一个完整的主题配置 Demo 展示其工程落地。

二、三者的角色与关系
2.1 AppStorage — 应用的"全局数据中心"
AppStorage 是一个 应用级单例,所有 UIAbility 和 Page 共享同一份数据。它的核心特征:

全局唯一: 整个进程中只有一个 AppStorage 实例
响应式: 任何一方修改数据,所有绑定该 key 的 UI 自动刷新
进程级生命周期: 数据随应用进程存在,即使用户从 A 页面跳转到 B 页面再返回,状态保持不变
⚠️ 注意: AppStorage 仅在应用进程存活期间有效。进程被系统回收后,数据会丢失。如需永久持久化(跨进程重启),应配合 PersistentStorage 使用。

2.2 @StorageProp — 组件的"AppStorage 窗口"
@StorageProp(key) 将组件属性与 AppStorage 中指定 key 建立 单向同步 + 组件可写 的关系:

┌──────────────┐ 读/写 ┌──────────────────┐
│ 组件属性 │ ◄─────────► │ AppStorage(key) │
│ @StorageProp │ └──────────────────┘
└──────────────┘
组件初始化时,从 AppStorage 读取对应 key 的值
组件内修改该属性,自动写回 AppStorage
其他绑定了同一 key 的组件,自动收到变更通知并刷新
与 @StorageLink 的区别:@StorageLink 是双向同步且会覆盖本地默认值;@StorageProp 优先使用 AppStorage 的值,若 key 不存在则使用组件声明的默认值。

2.3 @LocalStorage 与 @LocalStorageProp — 页面的"临时工作台"
@LocalStorage 是 页面级存储,生命周期与页面一致:

┌─────────────────────────┐
│ Page A │
│ ┌───────────────────┐ │
│ │ LocalStorage │ │ ← 仅 Page A 可见
│ │ @LocalStorageProp │ │
│ └───────────────────┘ │
└─────────────────────────┘
页面销毁时,LocalStorage 自动释放,无需手动清理
适合存储"仅当前页面需要"的临时状态(如表单草稿、滚动位置)
@LocalStorageProp 绑定方式与 @StorageProp 完全一致,只是数据源不同
2.4 三者的协作关系图
┌─────────────────────────────────────────────────┐
│ 应用进程 │
│ │
│ ┌──────────┐ AppStorage ┌──────────┐ │
│ │ Page A │ ◄──────────► │ Page B │ │
│ │ @StorageProp │ │ @StorageProp │ │
│ │ @LocalStorage │ │ │ │
│ └──────────┘ └──────────┘ │
│ │ │
│ │ LocalStorage(页面级) │
│ ▼ │
│ ┌──────────┐ │
│ │ Component│ │
│ │ @State │ │
│ └──────────┘ │
└─────────────────────────────────────────────────┘
三、Demo 项目架构解析
3.1 项目结构
entry/src/main/ets/
├── entryability/
│ └── EntryAbility.ets ← AppStorage 初始化入口
└── pages/
├── Index.ets ← 首页(含导航按钮)
└── StoragePropDemo.ets ← 持久化布局演示页(435行)
3.2 应用启动时的数据初始化
在 EntryAbility.ets 的 onCreate 中,我们通过 AppStorage.SetOrCreate() 预置了 4 个全局 key:

// EntryAbility.ets — 应用级数据预置
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// …
AppStorage.SetOrCreate(‘themeColor’, ‘#007AFF’);
AppStorage.SetOrCreate(‘fontSize’, 16);
AppStorage.SetOrCreate(‘isDarkMode’, false);
AppStorage.SetOrCreate(‘userName’, ‘HarmonyOS 用户’);
}
SetOrCreate 的语义是:如果 key 不存在则创建并赋值,已存在则忽略。这使得:

首次安装时,使用代码中的默认值
后续启动时,保留用户上次修改的值(配合 PersistentStorage 可实现永久保持)
⚠️ HarmonyOS NEXT 注意: SetOrCreate 在新版 SDK 中已标记为废弃,推荐使用 AppStorage.setOrCreate() 替代(驼峰命名)。Demo 代码中仍保留旧 API 以兼容 API 12 以下版本。

3.3 页面模块级别的 AppStorage 初始化
除了在 EntryAbility 中初始化,演示页 StoragePropDemo.ets 在文件模块作用域也做了一次相同的初始化:

// StoragePropDemo.ets — 文件模块级初始化
AppStorage.SetOrCreate(‘themeColor’, ‘#007AFF’);
AppStorage.SetOrCreate(‘fontSize’, 16);
AppStorage.SetOrCreate(‘isDarkMode’, false);
AppStorage.SetOrCreate(‘userName’, ‘HarmonyOS 用户’);
这是一种 防御性初始化策略:即使 EntryAbility 的初始化因某些原因延迟或失败,页面被加载时也能确保 AppStorage 中的 key 已就绪。这是编写健壮的鸿蒙应用的一个重要技巧。

3.4 组件中的 @StorageProp 声明
@Entry
@Component
struct StoragePropDemo {
// ---- AppStorage 绑定 ----
@StorageProp(‘themeColor’) themeColor: string = ‘#007AFF’;
@StorageProp(‘fontSize’) fontSize: number = 16;
@StorageProp(‘isDarkMode’) isDarkMode: boolean = false;
@StorageProp(‘userName’) userName: string = ‘HarmonyOS 用户’;

// ---- LocalStorage 绑定 ----
@LocalStorageProp(‘pageTitle’) pageTitle: string = ‘AppStorage 持久化布局演示’;

// ---- 组件级状态 ----
@State currentColorIndex: number = 0;
}
关键区分:

themeColor、fontSize、isDarkMode、userName 使用 @StorageProp — 它们在所有页面间共享
pageTitle 使用 @LocalStorageProp — 它只在这个页面有效
currentColorIndex 使用 @State — 纯组件局部状态,仅用于 UI 交互记录
四、六大交互模块逐行解读
4.1 📌 状态总览 — 读操作的演示
@Builder
buildStatusOverview() {
Column({ space: 8 }) {
this.buildInfoRow(‘主题色’, this.themeColor)
this.buildInfoRow(‘字体大小’, this.fontSize + ‘fp’)
this.buildInfoRow(‘暗黑模式’, this.isDarkMode ? ‘已开启’ : ‘已关闭’)
this.buildInfoRow(‘用户名’, this.userName)
}
}
要点: 这是最简单的使用场景 —— 读取 AppStorage 中的值。所有 4 个 @StorageProp 变量被直接用于 UI 展示,无需手动从 AppStorage 取值。

4.2 🎨 主题色选择器 — 写入并触发联动
@Builder
buildColorPicker() {
// …
ForEach(COLOR_PRESETS, (color: string) => {
Circle()
.width(40).height(40).fill(color)
.onClick(() => {
this.themeColor = color; // ← 这一行是关键
promptAction.showToast({
message: '主题色已切换为 ’ + color
});
})
if (this.themeColor === color) {
// 显示选中标记
}
})
}
数据流: onClick → this.themeColor = color → AppStorage(‘themeColor’) 更新 → 所有绑定组件刷新

选中标记通过 if (this.themeColor === color) 条件渲染,这是响应式编程的典型模式:状态驱动 UI,而非命令式修改 UI。

4.3 🔤 字体大小滑块 — 连续写入
Slider({
value: this.fontSize, min: 12, max: 24, step: 1
})
.onChange((value: number) => {
this.fontSize = value; // 每次拖动都写回 AppStorage
})
要点: 滑块拖动产生的连续事件,每一次都会触发 @StorageProp 的写入。由于 @StorageProp 的底层实现是高效的脏检查机制,这种高频写入不会造成性能问题。

4.4 🌙 暗黑模式开关 — Toggle 组件联动
Toggle({ type: ToggleType.Switch, isOn: this.isDarkMode })
.onChange((isOn: boolean) => {
this.isDarkMode = isOn;
promptAction.showToast({
message: isOn ? ‘已切换到暗黑模式’ : ‘已切换到亮色模式’
});
})
整体 UI 响应: 暗黑模式不仅仅改变 Toggle 本身的状态,整个页面的背景色、文字颜色、卡片颜色全部随之变化 —— 因为它们都读取了 this.isDarkMode:

.backgroundColor(this.isDarkMode ? ‘#1A1A1A’ : ‘#FFFFFF’)
// 每个 Card:
.bgColor(this.isDarkMode ? ‘#2C2C2C’ : ‘#F5F5F7’)
// 每个 Text:
.fontColor(this.isDarkMode ? ‘#CCCCCC’ : ‘#666666’)
这就是 响应式持久化布局 的核心优势:一处修改,全局联动。

4.5 👤 用户名编辑 — TextInput 双向绑定
TextInput({ placeholder: ‘请输入用户名’, text: this.userName })
.onChange((value: string) => {
this.userName = value; // 写回 AppStorage
})
要点: 用户在输入框中键入的每个字符,都会实时同步到 AppStorage。当用户跳转到其他页面时,其他页面通过同名 @StorageProp(‘userName’) 读取到最新的值。

4.6 ✨ 实时效果预览 — 综合展示
@Builder
buildPreviewPane() {
Column({ space: 8 }) {
Text('Hello, ’ + this.userName + ‘!’)
.fontSize(this.fontSize) // 从 AppStorage 读取字号
.fontColor(this.themeColor) // 从 AppStorage 读取颜色
.fontWeight(FontWeight.Bold)
}
.border({ width: 2, color: this.themeColor }) // 边框颜色跟随主题
}
这一区域集成了所有 4 个 @StorageProp 变量,形成一个 实时预览面板,让用户直观地看到所有设置的综合效果。

五、@BuilderParam 组件复用模式
Demo 中抽取了一个可复用的 Card 组件,展示了鸿蒙中 组件插槽(Slot) 的实现方式:

@Component
struct Card {
@Prop title: string = ‘’;
@BuilderParam content: () => void = this.emptyContent;
@Prop bgColor: string = ‘#F5F5F7’;

@Builder
emptyContent() {}

build() {
    Column() {
        Text(this.title)
            .fontSize(16).fontWeight(FontWeight.Bold)
            .fontColor('#1A1A1A').margin({ bottom: 12 })
            .width('100%')
        this.content()   // ← @BuilderParam 占位, 由父组件填充
    }
    .width('100%').padding(16)
    .backgroundColor(this.bgColor)
    .borderRadius(12).margin({ bottom: 12 })
}

}
父组件通过 尾随闭包 传入内容:

Card({ title: ‘🎨 主题色’, bgColor: ‘#F5F5F7’ }) {
this.buildColorPicker() // ← 闭包内容自动赋值给 @BuilderParam content
}
这种模式的优势:

关注点分离: Card 只负责容器样式,内容由调用方决定
高复用性: 一个 Card 组件可以承载任何 @Builder 内容
类型安全: 编译期即检查闭包是否符合 () => void 签名
六、生命周期与数据流深度剖析
6.1 @StorageProp 的完整生命周期
应用启动


AppStorage.SetOrCreate(‘themeColor’, ‘#007AFF’) ← 初始化


@StorageProp(‘themeColor’) themeColor: string ← 组件读取


用户在 UI 中修改 themeColor

├──→ 组件本地状态更新 → UI 重新渲染

└──→ AppStorage 更新 → 通知所有监听者

├──→ Page A 的 @StorageProp 更新 → UI 刷新
├──→ Page B 的 @StorageProp 更新 → UI 刷新
└──→ 任意 @StorageLink 更新 → UI 刷新
6.2 与其他装饰器的对比
装饰器 存储层级 生命周期 可写范围 典型用途
@State 组件私有 组件销毁 仅本组件 局部表单输入、展开/折叠
@Prop 父传子 组件销毁 仅子组件读 接收父组件数据
@Link 父传子 组件销毁 双向同步 父子组件联动
@Provide/@Consume 组件树 组件树销毁 双向同步 跨多层组件通信
@StorageProp 应用级 进程级 全局写 主题、登录态、全局设置
@StorageLink 应用级 进程级 全局写 同 @StorageProp,但双向性更强
@LocalStorageProp 页面级 页面销毁 仅本页面 页面临时偏好
@LocalStorageLink 页面级 页面销毁 仅本页面 页面级双向同步
6.3 @StorageProp 的底层实现原理(简化版)
// 伪代码:理解 @StorageProp 的工作机制
class AppStorageManager {
private static store: Map<string, any> = new Map();
private static watchers: Map<string, Set> = new Map();

static setOrCreate(key: string, value: any): void {
    if (!this.store.has(key)) {
        this.store.set(key, value);
    }
}

static set(key: string, value: any): void {
    this.store.set(key, value);
    // 通知所有监听该 key 的组件
    this.watchers.get(key)?.forEach(callback => callback(value));
}

static get(key: string): any {
    return this.store.get(key);
}

}
@StorageProp 装饰器在编译期会注入 getter/setter,setter 中自动调用 AppStorage.set(key, newValue),从而触发所有监听者的刷新。

七、最佳实践与陷阱规避
7.1 ✅ 最佳实践

  1. 统一在 EntryAbility 中初始化:

onCreate(want, launchParam) {
AppStorage.setOrCreate(‘key1’, defaultValue1);
AppStorage.setOrCreate(‘key2’, defaultValue2);
// … 集中管理所有全局 key
}
2. 使用常量管理 key 名称:

// AppStorageKeys.ets
export const AppStorageKeys = {
THEME_COLOR: ‘themeColor’,
FONT_SIZE: ‘fontSize’,
IS_DARK_MODE: ‘isDarkMode’,
USER_NAME: ‘userName’,
} as const;
3. 配合 PersistentStorage 实现跨进程持久化:

// 在 Ability 中
PersistentStorage.persistProp(‘themeColor’, ‘#007AFF’);
// 应用关闭后重新打开,themeColor 保持用户上次设置的值
7.2 ⚠️ 常见陷阱
陷阱 1:在非 @Component 文件中访问 AppStorage

// ❌ 错误:工具类中直接访问
class ThemeUtil {
static getColor(): string {
return AppStorage.get(‘themeColor’); // 可能为 undefined
}
}

// ✅ 正确:使用 AppStorage.get 前先确保 key 存在
class ThemeUtil {
static getColor(): string {
return AppStorage.get(‘themeColor’) ?? ‘#007AFF’;
}
}
陷阱 2:key 名称拼写不一致

// 页面 A
@StorageProp(‘themeColor’) themeColor: string = ‘#007AFF’;
// 页面 B — 不小心多写了一个空格
@StorageProp('themeColor ') themeColor: string = ‘#000000’; // ❌ 不同 key!
陷阱 3:忘记默认值声明

@StorageProp(‘fontSize’) fontSize: number; // ❌ 需要默认值
// 运行时可能报 undefined 错误

@StorageProp(‘fontSize’) fontSize: number = 16; // ✅
陷阱 4:@StorageProp 不支持复杂对象(某些版本)

// ⚠️ 某些版本限制:只支持 string / number / boolean
@StorageProp(‘userProfile’) userProfile: UserProfile = {}; // 可能不支持
// 建议用 JSON 序列化
@StorageProp(‘userProfileJSON’) userProfileJSON: string = ‘{}’;
7.3 性能考量
按需绑定: 不要把所有 AppStorage key 都绑定到每个页面,只绑定当前页面需要的
避免高频写入: 如果每秒需要写入数十次(如实时绘图坐标),考虑用 @State + 防抖,最后一次性写入 AppStorage
合理分层: @StorageProp 适合低频变化的全局状态(主题、语言、登录态);高频 UI 动画状态用 @State
八、扩展场景
8.1 多 Tab 页共享主题
// TabPageA.ets
@StorageProp(‘themeColor’) themeColor: string = ‘#007AFF’;
// TabPageB.ets
@StorageProp(‘themeColor’) themeColor: string = ‘#007AFF’;
// 在 TabPageA 切换颜色 → TabPageB 自动刷新
8.2 登录态管理
// 登录成功时
AppStorage.setOrCreate(‘isLoggedIn’, true);
AppStorage.setOrCreate(‘userToken’, ‘xxx-xxx-xxx’);
AppStorage.setOrCreate(‘userInfo’, JSON.stringify({ name: ‘张三’, role: ‘admin’ }));

// 任何页面
@StorageProp(‘isLoggedIn’) isLoggedIn: boolean = false;
// 根据 isLoggedIn 控制 UI 显示
8.3 多语言切换
// 设置语言
AppStorage.setOrCreate(‘locale’, ‘zh-CN’);

// 任意页面
@StorageProp(‘locale’) locale: string = ‘zh-CN’;

// 配合资源管理,实现全局语言切换
getText(key: string): string {
return i18n.get(key, this.locale);
}
九、完整代码清单
9.1 StoragePropDemo.ets
/**

  • StoragePropDemo.ets
  • @StorageProp + @LocalStorage + AppStorage 持久化布局演示
    */

import { promptAction } from ‘@kit.ArkUI’;

// AppStorage 初始化(文件模块级防御性初始化)
AppStorage.SetOrCreate(‘themeColor’, ‘#007AFF’);
AppStorage.SetOrCreate(‘fontSize’, 16);
AppStorage.SetOrCreate(‘isDarkMode’, false);
AppStorage.SetOrCreate(‘userName’, ‘HarmonyOS 用户’);

const COLOR_PRESETS: string[] = [
‘#007AFF’, ‘#FF3B30’, ‘#34C759’,
‘#FF9500’, ‘#AF52DE’, ‘#5AC8FA’,
];

@Entry
@Component
struct StoragePropDemo {
/* ---- @StorageProp:与 AppStorage 双向绑定 ---- */
@StorageProp(‘themeColor’) themeColor: string = ‘#007AFF’;
@StorageProp(‘fontSize’) fontSize: number = 16;
@StorageProp(‘isDarkMode’) isDarkMode: boolean = false;
@StorageProp(‘userName’) userName: string = ‘HarmonyOS 用户’;

/* ---- @LocalStorageProp:页面级存储 ---- */
@LocalStorageProp(‘pageTitle’) pageTitle: string = ‘AppStorage 持久化布局演示’;

@State currentColorIndex: number = 0;

build() {
Scroll() {
Column() {
// 标题区
Text(this.pageTitle)
.fontSize(22).fontWeight(FontWeight.Bold)
.fontColor(this.isDarkMode ? ‘#FFFFFF’ : ‘#1A1A1A’)
.margin({ top: 24, bottom: 8 }).width(‘100%’).textAlign(TextAlign.Center)

    Text('@StorageProp + @LocalStorage + AppStorage')
      .fontSize(13).fontColor('#888888').margin({ bottom: 20 })
      .width('100%').textAlign(TextAlign.Center)

    // 状态总览
    Card({ title: '📌 当前状态总览',
           bgColor: this.isDarkMode ? '#2C2C2C' : '#F5F5F7' }) {
      this.buildStatusOverview()
    }
    // 主题色选择器
    Card({ title: '🎨 主题色(AppStorage 持久化)',
           bgColor: this.isDarkMode ? '#2C2C2C' : '#F5F5F7' }) {
      this.buildColorPicker()
    }
    // 字体大小
    Card({ title: '🔤 字体大小(AppStorage 持久化)',
           bgColor: this.isDarkMode ? '#2C2C2C' : '#F5F5F7' }) {
      this.buildFontSizeSlider()
    }
    // 暗黑模式
    Card({ title: '🌙 暗黑模式(AppStorage 持久化)',
           bgColor: this.isDarkMode ? '#2C2C2C' : '#F5F5F7' }) {
      this.buildDarkModeToggle()
    }
    // 用户名
    Card({ title: '👤 用户名(AppStorage 持久化)',
           bgColor: this.isDarkMode ? '#2C2C2C' : '#F5F5F7' }) {
      this.buildUserNameEditor()
    }
    // 实时预览
    Card({ title: '✨ 实时效果预览',
           bgColor: this.isDarkMode ? '#2C2C2C' : '#F5F5F7' }) {
      this.buildPreviewPane()
    }

    Text('💡 提示:页面内的所有设置都通过 @StorageProp 绑定到 AppStorage。\n返回后重新进入或跳转其他页面,这些设置仍然保持。')
      .fontSize(12).fontColor('#999999').margin({ top: 16, bottom: 32 })
      .lineHeight(20).padding({ left: 16, right: 16 }).width('100%')
  }.width('100%').padding({ left: 16, right: 16, bottom: 32 })
}.width('100%').height('100%')
 .backgroundColor(this.isDarkMode ? '#1A1A1A' : '#FFFFFF')

}

@Builder
buildStatusOverview() {
Column({ space: 8 }) {
this.buildInfoRow(‘主题色’, this.themeColor)
this.buildInfoRow(‘字体大小’, this.fontSize + ‘fp’)
this.buildInfoRow(‘暗黑模式’, this.isDarkMode ? ‘已开启’ : ‘已关闭’)
this.buildInfoRow(‘用户名’, this.userName)
}.padding({ top: 8, bottom: 8 })
}

@Builder
buildInfoRow(label: string, value: string) {
Row() {
Text(label + ‘:’).fontSize(14)
.fontColor(this.isDarkMode ? ‘#CCCCCC’ : ‘#666666’)
Text(value).fontSize(14).fontColor(this.themeColor)
.fontWeight(FontWeight.Medium)
}.width(‘100%’).justifyContent(FlexAlign.SpaceBetween)
}

@Builder
buildColorPicker() {
Column({ space: 12 }) {
Text(‘当前选中色:’ + this.themeColor).fontSize(14)
.fontColor(this.isDarkMode ? ‘#CCCCCC’ : ‘#333333’)
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Center }) {
ForEach(COLOR_PRESETS, (color: string) => {
Column() {
Circle().width(40).height(40).fill(color).margin(6)
.onClick(() => {
this.themeColor = color;
promptAction.showToast({ message: ‘主题色已切换为 ’ + color });
})
if (this.themeColor === color) {
Circle().width(8).height(8).fill(’#FFFFFF’)
.stroke(this.themeColor).strokeWidth(2)
}
}.padding({ left: 4, right: 4 })
})
}.width(‘100%’).padding({ top: 8, bottom: 8 })
}
}

@Builder
buildFontSizeSlider() {
Column({ space: 8 }) {
Row() {
Text(‘A’).fontSize(12)
.fontColor(this.isDarkMode ? ‘#CCCCCC’ : ‘#666666’)
Slider({ value: this.fontSize, min: 12, max: 24, step: 1,
style: SliderStyle.OutSet })
.blockColor(this.themeColor)
.trackColor(this.isDarkMode ? ‘#444444’ : ‘#E0E0E0’)
.selectedColor(this.themeColor)
.onChange((value: number) => { this.fontSize = value; })
.layoutWeight(1)
Text(‘A’).fontSize(24)
.fontColor(this.isDarkMode ? ‘#CCCCCC’ : ‘#666666’)
}.width(‘100%’)
Text(‘当前字号:’ + this.fontSize + ‘fp’).fontSize(13)
.fontColor(this.isDarkMode ? ‘#AAAAAA’ : ‘#888888’)
.textAlign(TextAlign.Center).width(‘100%’)
}.padding({ top: 4, bottom: 4 })
}

@Builder
buildDarkModeToggle() {
Row() {
Text(this.isDarkMode ? ‘🌑 暗黑模式已开启’ : ‘☀️ 亮色模式’)
.fontSize(16)
.fontColor(this.isDarkMode ? ‘#FFFFFF’ : ‘#333333’)
.layoutWeight(1)
Toggle({ type: ToggleType.Switch, isOn: this.isDarkMode })
.selectedColor(this.themeColor).switchPointColor(‘#FFFFFF’)
.onChange((isOn: boolean) => {
this.isDarkMode = isOn;
promptAction.showToast({
message: isOn ? ‘已切换到暗黑模式’ : ‘已切换到亮色模式’
});
})
}.width(‘100%’).padding({ top: 8, bottom: 8 })
}

@Builder
buildUserNameEditor() {
Column({ space: 8 }) {
TextInput({ placeholder: ‘请输入用户名’, text: this.userName })
.fontSize(16).fontColor(this.isDarkMode ? ‘#FFFFFF’ : ‘#333333’)
.backgroundColor(this.isDarkMode ? ‘#3C3C3C’ : ‘#FFFFFF’)
.placeholderColor(this.isDarkMode ? ‘#888888’ : ‘#CCCCCC’)
.borderRadius(8).border({ width: 1, color: this.isDarkMode ? ‘#555555’ : ‘#E0E0E0’ })
.onChange((value: string) => { this.userName = value; }).height(44)
Text(‘按回车或点击空白处确认修改’).fontSize(12).fontColor(‘#999999’)
}.padding({ top: 4, bottom: 4 })
}

@Builder
buildPreviewPane() {
Column({ space: 12 }) {
Column({ space: 8 }) {
Text(‘Hello, ’ + this.userName + ‘!’)
.fontSize(this.fontSize).fontColor(this.themeColor)
.fontWeight(FontWeight.Bold).textAlign(TextAlign.Center).width(‘100%’)
Text(‘当前主题色:’ + this.themeColor + ’ · 字号:’ + this.fontSize + ‘fp’)
.fontSize(13).fontColor(this.isDarkMode ? ‘#AAAAAA’ : ‘#666666’)
.textAlign(TextAlign.Center).width(‘100%’)
}.padding(16).backgroundColor(this.isDarkMode ? ‘#333333’ : ‘#F0F8FF’)
.borderRadius(12).border({ width: 2, color: this.themeColor }).width(‘100%’)

  Text('【底层原理】').fontSize(14).fontWeight(FontWeight.Bold)
    .fontColor(this.isDarkMode ? '#CCCCCC' : '#333333').margin({ top: 4 })
  Text('@StorageProp(\'themeColor\') 将 themeColor 绑定到 AppStorage。\n'
      + '每次修改 themeColor,AppStorage自动更新,所有监听该key的页面同步刷新。\n\n'
      + 'AppStorage 生命周期 = 应用进程生命周期。即使用户切换到其他页面再返回,所有状态保持不变。')
    .fontSize(12).fontColor(this.isDarkMode ? '#999999' : '#666666').lineHeight(20)
}.padding({ top: 8, bottom: 8 })

}
}

@Component
struct Card {
@Prop title: string = ‘’;
@BuilderParam content: () => void = this.emptyContent;
@Prop bgColor: string = ‘#F5F5F7’;

@Builder emptyContent() {}

build() {
Column() {
Text(this.title).fontSize(16).fontWeight(FontWeight.Bold)
.fontColor(‘#1A1A1A’).margin({ bottom: 12 }).width(‘100%’)
this.content()
}.width(‘100%’).padding(16).backgroundColor(this.bgColor)
.borderRadius(12).margin({ bottom: 12 })
}
}
9.2 EntryAbility.ets 中的初始化
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// …
AppStorage.SetOrCreate(‘themeColor’, ‘#007AFF’);
AppStorage.SetOrCreate(‘fontSize’, 16);
AppStorage.SetOrCreate(‘isDarkMode’, false);
AppStorage.SetOrCreate(‘userName’, ‘HarmonyOS 用户’);
}
十、运行效果预览
启动应用后,从首页点击导航按钮进入演示页,可以看到:

状态总览卡片 — 实时显示所有 AppStorage 中的当前值
主题色选择器 — 6 色环点击切换,主题色即刻生效并持久化
字体大小滑块 — 12~24fp 可调,拖动即生效
暗黑模式开关 — 一键切换暗黑/亮色,整个页面 UI 自适应
用户名输入 — 实时同步到 AppStorage
实时预览卡片 — 集成展示所有设置的综合效果
切换到其他页面再返回,所有设置 保持不变 — 这就是 AppStorage 持久化的威力。

十一、总结
@StorageProp + @LocalStorage + AppStorage 构成了鸿蒙 ArkTS 中 应用级状态管理 的完整方案:

AppStorage 提供全局数据总线,跨越页面边界
@StorageProp 将组件属性与 AppStorage 响应式绑定,实现零模板代码的状态同步
@LocalStorage 补充页面级存储,避免滥用全局 key
三者的组合适用于:

✅ 主题/换肤系统
✅ 多语言切换
✅ 用户登录态管理
✅ 全局设置面板
✅ 任何需要跨页面共享状态的场景
下一篇文章将深入探讨如何将 PersistentStorage 与 AppStorage 配合,实现 应用重启后仍保持 的真正"持久化"方案。

本文对应的完整源代码位于 Demo0626/ 项目目录,可直接在 DevEco Studio 中打开并运行。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐