在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

鸿蒙 Next 碎片时间学习 App 开发实战:知识卡片 + 学习追踪

作者:duluo
SDK 版本:HarmonyOS API 24 (Next)
开发工具:DevEco Studio
语言框架:ArkTS + ArkUI
字数:约 11000 字


目录

  1. 引言
  2. 产品概念与知识体系设计
  3. 三 Tab 架构回顾
  4. 知识卡片系统设计
  5. 学习追踪与连续天数算法
  6. 收藏系统实现
  7. 数据持久化与记录管理
  8. 编译错误全记录
  9. 六款 App 架构模式汇总
  10. HarmonyOS 开发的六个阶段
  11. 结语

1. 引言

1.1 微学习:利用碎片时间

“微学习”(Micro-learning)是一种通过短小精悍的学习单元,在零碎时间内获取知识的学习方式。研究表明,每次 5-10 分钟的微学习,其知识 retention rate(留存率)比传统长时学习高出 20%——因为短时专注更容易保持注意力。

“碎片时间学习” App 正是基于这一理念设计:每条知识卡片约 150-250 字,可在 1-2 分钟内读完。用户可以利用通勤、排队、午休等碎片时间,每天学习几条有趣的知识。

1.2 本 App 的定位

这是本系列的第六款应用。与前五款不同,本 App 将重点放在了内容设计学习激励机制上:

维度 前五款 碎片时间学习
核心驱动力 功能工具 内容消费 + 学习激励
内容来源 用户生成/静态预设 精心设计的 16 条知识
激励设计 游戏化评分 连续学习天数 + 鼓励语
用户粘性 按需使用 每日打开的习惯养成

1.3 六款 App 回顾

# App 核心技术点 代码行数
1 沉浸式白噪音 多媒体 + 动画 ~767
2 时间胶囊 Preferences + Builder 约束 ~955
3 冰箱剩菜大作战 Tab 架构 + 游戏化 ~1320
4 尴尬粉碎机 静态数据 + 模式复用 ~953
5 老年人防骗训练 适老化设计 + 情景训练 ~1038
6 碎片时间学习 知识卡片 + 学习追踪 ~851

2. 产品概念与知识体系设计

2.1 功能需求

用户故事 1:每天的碎片时间,我想学到一条有趣的新知识
用户故事 2:我想看到自己的学习记录和连续天数
用户故事 3:遇到喜欢的知识,我想收藏起来以后再看
用户故事 4:我想按分类浏览所有知识

功能清单:
├── F1: 今日知识卡片(随机展示,可换一个)
├── F2: 标记已学(记录学习进度)
├── F3: 收藏/取消收藏
├── F4: 分类浏览(6 大类)
├── F5: 连续学习天数计算
├── F6: 学习统计数据
├── F7: 收藏夹弹窗查看
└── F8: 数据持久化

2.2 知识体系

16 条知识卡片覆盖 6 大分类,每类 2-3 条:

分类 知识数量 设计意图
历史 3 条 满足对过去的好奇心
科学 3 条 培养科学素养
文学 3 条 提升人文底蕴
生活 3 条 实用生活技巧
哲学 2 条 启发思考
艺术 2 条 培养审美

2.3 数据模型

interface KnowledgeCard {
  id: number;
  category: string;    // 分类
  title: string;       // 标题
  content: string;     // 正文(150-250 字)
  source: string;      // 来源
  color: string;       // 主题色
}

interface StudyRecord {
  learnedIds: number[];    // 已学的卡片 ID
  favoriteIds: number[];   // 收藏的卡片 ID
  totalSessions: number;   // 总学习次数
  currentStreak: number;   // 当前连续天数
  lastStudyDate: string;   // 最后学习日期
  longestStreak: number;   // 最长连续纪录
}

3. 三 Tab 架构回顾

3.1 Tab 概览

@State activeTab: number = 0;

buildTabContent() {
  if (this.activeTab === 0) this.buildLearnPage()     // 今日学习
  else if (this.activeTab === 1) this.buildBrowsePage() // 分类浏览
  else this.buildStatsPage()                           // 学习统计
}

3.2 Tab 0:今日学习

核心交互:展示知识卡片 + 底部操作按钮

┌─────────────────────────────┐
│    🏷️ 历史       ❤️         │  ← 分类标签 + 收藏按钮
│                             │
│    万里长城的长度            │  ← 标题(20sp 加粗)
│    ─────────────────        │
│    中国万里长城的总长度      │  ← 内容(16sp,26sp 行距)
│    超过21,000公里...         │
│                             │
│    📖 中国文化遗产研究院      │  ← 来源
│                             │
├─────────────────────────────┤
│  ✅ 学会了    🔄 换一个       │  ← 操作按钮
└─────────────────────────────┘

3.3 Tab 1:分类浏览

按 6 个分类分组展示所有知识卡片:

📖 分类浏览
按主题浏览所有知识卡片

🏛️  历史
│ 01 万里长城的长度        ✅ 已学
│ 02 唐朝的"外卖"服务     ⏳ 未学
│ 03 铅笔的"铅"不是铅     ✅ 已学

🔬 科学
│ 04 光的传播速度          ⏳ 未学
│ 05 人体内的细菌数量      ✅ 已学
│ 06 蜜蜂的"8字舞"        ⏳ 未学
...

3.4 Tab 2:学习统计

📊 学习统计
记录你的每一次学习

┌── 🔥 连续学习 ──┐
│      7 天        │
│  🌟 太棒了!     │
└────────────────┘

┌──────┐ ┌──────┐ ┌──────┐
│ 📚   │ │ ❤️  │ │ 📅  │
│ 12   │ │  5  │ │ 30天│
│ 已学 │ │ 收藏 │ │ 最长│
└──────┘ └──────┘ └──────┘

❤️ 查看收藏的知识卡片  >

4. 知识卡片系统设计

4.1 卡片组件结构

// 分类标签
Row() {
  Text(card.category)
    .fontSize(13).fontColor(Color.White)
    .padding({ left: 10, right: 10, top: 4, bottom: 4 })
    .backgroundColor(card.color)
    .borderRadius(10)

  Blank()

  Text('\u{2665}')  // 收藏按钮
    .fontColor(this.isFavorited(card.id) ? favorite : textHint)
    .onClick(() => { this.toggleFavorite(card.id); })
}

// 标题
Text(card.title)
  .fontSize(20).fontWeight(FontWeight.Bold)
  .lineHeight(28)

// 分隔线 + 正文
Divider()
Text(card.content)
  .fontSize(16).lineHeight(26)

// 来源
Text(card.source)
  .fontSize(12).fontColor(textHint)

4.2 卡片视觉参数

元素 参数 效果
卡片背景 #FFFFFF 纯白 干净阅读体验
圆角 20px 柔和现代
边框 主题色 + 33(20% 透明度) 分类色彩暗示
阴影 主题色 + 12(7% 透明度) 浮起感
高度 420px 固定高度,一屏可见

4.3 卡片操作按钮

Row() {
  // ✅ 学会了
  Row() {
    Text('\u{2705}').fontSize(16)
    Text('学会了').fontSize(15)
      .fontColor(ALL_COLORS.learned)
  }
  .padding({ left: 16, right: 16, top: 10, bottom: 10 })
  .backgroundColor(ALL_COLORS.learned + '15')
  .borderRadius(16)
  .borderWidth(1)
  .borderColor(ALL_COLORS.learned + '33')
  .onClick(() => { this.markLearned(card.id); })

  Blank()

  // 🔄 换一个
  Row() {
    Text('\u{1F500}').fontSize(16)
    Text('换一个').fontSize(15)
      .fontColor(ALL_COLORS.primary)
  }
  .padding({ left: 16, right: 16, top: 10, bottom: 10 })
  .backgroundColor(ALL_COLORS.primary + '12')
  .borderRadius(16)
  .onClick(() => { this.nextCard(); })
}

"学会了"按钮使用绿色主题色,周围有 10% 透明度的背景和 20% 透明度的边框——层次丰富但不抢眼。

4.4 卡片轮换

@State currentCardIndex: number = 0;

nextCard(): void {
  this.currentCardIndex = (this.currentCardIndex + 1) % CARDS.length;
}

使用取模运算实现循环轮换。16 张卡片循环展示,不会重复。

4.5 5 种分类颜色

const CARDS: KnowledgeCard[] = [
  { id: 1, category: '历史', color: '#E53935' },    // 红
  { id: 2, category: '科学', color: '#1E88E5' },    // 蓝
  { id: 3, category: '文学', color: '#8E24AA' },    // 紫
  { id: 4, category: '生活', color: '#FB8C00' },    // 橙
  { id: 5, category: '哲学', color: '#43A047' },    // 绿
  { id: 6, category: '艺术', color: '#F4511E' },    // 深橙
  // ...
]

每种分类有对应的主题色,贯穿卡片标签、边框和阴影。


5. 学习追踪与连续天数算法

5.1 连续天数算法

markLearned(cardId: number): void {
  if (this.record.learnedIds.indexOf(cardId) >= 0) return; // 去重

  this.record.learnedIds = this.record.learnedIds.concat([cardId]);
  this.record.totalSessions++;

  let today = this.getDateStr();
  if (this.record.lastStudyDate === today) {
    // 今天已经学过了,只增加学习次数
  } else if (this.record.lastStudyDate === this.getYesterdayStr()) {
    this.record.currentStreak++;  // 连续学习
  } else {
    this.record.currentStreak = 1;  // 中断,重新开始
  }

  this.record.lastStudyDate = today;
  if (this.record.currentStreak > this.record.longestStreak) {
    this.record.longestStreak = this.record.currentStreak;
  }

  this.record = this.copyRecord(this.record);
  this.saveRecord();
}

算法流程

标记已学
  ├─ 已存在 learnedIds 中 → 跳过(去重)
  └─ 新学习 →
      ├─ lastStudyDate === today → 今日多次学习,不改变连续天数
      ├─ lastStudyDate === yesterday → 连续天数 +1
      └─ 其他 → 连续天数重置为 1
      然后 → 更新最长纪录

5.2 日期工具方法

getDateStr(): string {
  let d = new Date();
  return d.getFullYear() + '-' +
    (d.getMonth()+1).toString().padStart(2,'0') + '-' +
    d.getDate().toString().padStart(2,'0');
}

getYesterdayStr(): string {
  let d = new Date(Date.now() - 24*60*60*1000);
  return d.getFullYear() + '-' +
    (d.getMonth()+1).toString().padStart(2,'0') + '-' +
    d.getDate().toString().padStart(2,'0');
}

日期格式为 YYYY-MM-DD 的字符串比较,避免了时区问题和 Date 对象比较的复杂性。

5.3 连续天数可视化

Text('连续学习 ' + this.record.currentStreak + ' 天' +
  (this.record.currentStreak >= 7 ? ' \u{1F31F}' : ''))

当连续天数 >= 7 天时,在文字末尾显示星星 Emoji 🌟,作为正向激励。

5.4 今日学习次数的追踪

@State todayLearned: number = 0;

// 启动时
if (this.record.lastStudyDate === this.getDateStr()) {
  this.todayLearned = this.record.learnedIds.length;
}

// 标题栏显示
Text('已学 ' + this.todayLearned)

通过 todayLearned 状态变量,在标题栏右上角显示"已学 N"的实时计数。


6. 收藏系统实现

6.1 收藏/取消收藏

toggleFavorite(cardId: number): void {
  let idx = this.record.favoriteIds.indexOf(cardId);
  if (idx >= 0) {
    // 已收藏 → 取消
    this.record.favoriteIds = this.record.favoriteIds.filter(id => id !== cardId);
  } else {
    // 未收藏 → 添加
    this.record.favoriteIds = this.record.favoriteIds.concat([cardId]);
  }
  this.record = this.copyRecord(this.record);
  this.saveRecord();
}

6.2 收藏状态判断

isFavorited(cardId: number): boolean {
  return this.record.favoriteIds.indexOf(cardId) >= 0;
}

6.3 收藏按钮视觉反馈

Text('\u{2665}')  // ♥ 心形符号
  .fontSize(20)
  .fontColor(this.isFavorited(card.id) ?
    ALL_COLORS.favorite :    // 收藏态:红色 #E53935
    ALL_COLORS.textHint)     // 未收藏态:灰色 #BDBDBD
  .onClick(() => { this.toggleFavorite(card.id); })

视觉反馈:点击后心形从灰色变为红色,给用户即时的操作确认。

6.4 收藏夹弹窗

@Builder
buildFavoriteList() {
  // 蒙层 + 弹窗
  let favorites = CARDS.filter(c => this.isFavorited(c.id));
  if (favorites.length === 0) {
    Text('还没有收藏的知识卡片~')
  } else {
    ForEach(favorites, (card) => {
      Row() { /* 卡片标题 + 分类 + 右箭头 */ }
      .onClick(() => {
        // 跳转到该卡片的学习页面
        this.currentCardIndex = CARDS.indexOf(card);
        this.showFavoriteList = false;
        this.activeTab = 0;
      })
    })
  }
}

交互细节:点击收藏夹中的条目后,自动跳转到"今日学习"Tab 并显示该卡片。这个"跳转"的细节让收藏夹不只是静态列表,而是学习路径的快捷入口。


7. 数据持久化与记录管理

7.1 单键值存储

const STORAGE_KEY = 'study_records';

只存储 StudyRecord 一个对象,知识卡片数据是静态常量。

7.2 完整的持久化方法

async loadRecord(): Promise<void> {
  try {
    let context = getContext(this);
    this.dataPreferences = await preferences.getPreferences(context, 'study_db');
    let val = await this.dataPreferences.get(STORAGE_KEY, '');
    if (val !== '') {
      let data = JSON.parse(val as string) as StudyRecord;
      if (data) this.record = data;
    }
    // 检查今天的学习状态
    if (this.record.lastStudyDate === this.getDateStr()) {
      this.todayLearned = this.record.learnedIds.length;
    }
  } catch (err) {
    console.error(`Failed to load: ${JSON.stringify(err)}`);
  }
}

async saveRecord(): Promise<void> {
  try {
    if (this.dataPreferences) {
      await this.dataPreferences.put(STORAGE_KEY, JSON.stringify(this.record));
      await this.dataPreferences.flush();
    }
  } catch (err) {
    console.error(`Failed to save: ${JSON.stringify(err)}`);
  }
}

7.3 复制对象方法

由于 ArkTS 不支持展开运算符 { ...obj },我们需要手动实现复制:

copyRecord(source: StudyRecord): StudyRecord {
  return {
    learnedIds: source.learnedIds.concat([]),
    favoriteIds: source.favoriteIds.concat([]),
    totalSessions: source.totalSessions,
    currentStreak: source.currentStreak,
    lastStudyDate: source.lastStudyDate,
    longestStreak: source.longestStreak
  };
}

每次修改 record 后调用此方法创建新引用,触发 @State 的变更检测。

7.4 生命周期管理

aboutToAppear(): void {
  this.loadRecord();
}

aboutToDisappear(): void {
  this.saveRecord();
}

8. 编译错误全记录

8.1 错误概览

本 App 出现 12 个编译错误,类型分布:

类型 数量 占比
ALL_COLORS 无类型 1 8%
@Builder 中 let 声明 7 59%
属性不存在(card 变量未定义) 2 17%
Scroll 多子组件 1 8%
Row 属性不存在(borderBottomWidth) 1 8%

8.2 关键错误修复

错误类型 1:变量引用错误

'card' is possibly 'null'

场景:在 buildLearnPage 的 @Builder 中,原代码使用 let card = this.getCurrentCard() 后访问 card.titlecard.content 等。移除 let 后,这些引用变成了未定义变量。

修复:将所有 card.property 替换为 this.getCurrentCard()!.property

注意:buildBrowsePagebuildFavoriteList 中的 cardForEach 循环变量,不需要修改。只有 buildLearnPage 中的 card 是之前 let 定义的。

错误类型 2:ForEach + if + Column 嵌套结构

The comma operator "," is supported only in "for" loops

场景:在 buildBrowsePage 中,ForEach 回调内使用 if (condition) { Column() { ... } } 结构时,编译器的解析顺序导致了误报。

修复:将结构从:

ForEach(items, (item) => {
  Column() {
    if (condition) { /* children */ }
  }
})

改为:

ForEach(items, (item) => {
  if (condition) {
    Column() { /* children */ }
  }
})

即在 ForEach 回调中先判断条件,再创建 Column。

错误类型 3:borderBottomWidth 在 Row 上不存在

Property 'borderBottomWidth' does not exist on type 'RowAttribute'

场景:在 buildFavoriteList 中,尝试给 Row 组件设置底部分隔线。

修复:移除 borderBottomWidthborderBottomColor 属性,使用 Divider 组件或其他方式替代。ArkUI 的 Row 组件不支持单独的边框方向设置。

8.3 六款 App 错误纵向对比

App 错误数 Builder 类型 属性 其他
白噪音 16 8 1 0 7
时间胶囊 17 9 1 2 5
冰箱剩菜 22 15 1 6 0
尴尬粉碎机 1 0 1 0 0
防骗训练 12 6 1 5 0
碎片学习 12 7 1 4 0

趋势分析

  • Builder 错误始终是最大类别的错误,占总错误的 50-70%
  • 类型错误(对象字面量无接口)每次必出现——因为每个 App 都有新的颜色常量
  • 属性错误与代码量正相关——代码越多,越容易用错 API

9. 六款 App 架构模式汇总

9.1 数据模型演变

白噪音       : SoundItem[](6 预设)          → 无持久化
时间胶囊     : TimeCapsule[](用户生成)      → 单键值 Preferences
冰箱剩菜     : FoodItem[] + BattleStats       → 3 键值 Preferences
尴尬粉碎机   : 静态 TopicCard[] + 用户日记    → 单键值 Preferences
防骗训练     : 静态 ScamScenario[] + 进度     → 单键值 Preferences
碎片学习     : 静态 KnowledgeCard[] + 记录    → 单键值 Preferences

趋势:从纯动态 → 纯静态 → 动态+静态混合 → 静态为主+轻量记录。

9.2 架构复杂度趋势

白噪音   时间胶囊   冰箱剩菜   尴尬粉碎机   防骗训练   碎片学习
 767行    955行     1320行     953行       1038行     851行

冰箱剩菜达到峰值(1320 行)后有意控制,稳定在 850-1050 行之间。

9.3 编译错误趋势

白噪音   时间胶囊   冰箱剩菜   尴尬粉碎机   防骗训练   碎片学习
  16       17         22         1          12         12

呈现"升→降→稳"的趋势,反映了从探索到成熟的完整学习周期。

9.4 设计模式清单

经过六款 App 的实践,以下是经过验证的 ArkUI 设计模式:

模式 1:Stack 三层结构

Stack() {
  buildBackground()     // 背景层
  Column() { /* UI */ } // 内容层
  if (dialog) { ... }   // 弹窗层
}

模式 2:@Builder 数据获取

@Builder
buildXxx() {
  // 只写 UI,不写 let
  Text(this.getData())
}
getData(): string { return '...'; }

模式 3:数组引用更新

this.list = [newItem].concat(this.list);       // 插入
this.list = this.list.concat([]);              // 触发渲染
this.list = this.list.filter(predicate);       // 删除

模式 4:条件渲染 vs 提前返回

// ✅ 正确:if 包裹 UI
@Builder build() {
  if (condition) { Column() { /* UI */ } }
}
// ❌ 错误:if return
@Builder build() {
  if (!condition) return; // ❌
  Column() { /* UI */ }
}

模式 5:数据持久化三件套

aboutToAppear()loadData()
每次操作后         → saveData()
aboutToDisappear()saveData()

模式 6:Tab 切换

@State activeTab = 0;
buildTabContent() {
  if (activeTab === 0) buildTab0()
  else if (activeTab === 1) buildTab1()
  else buildTab2()
}

9.5 弹窗模式

@Builder
buildDialog() {
  if (this.showDialog) {
    Column() {
      // 蒙层
      Column()
        .width('100%').height('100%')
        .backgroundColor('rgba(0,0,0,0.5)')
        .onClick(() => { this.showDialog = false; })
      // 浮层
      Column() { /* 内容 */ }
        .width('88%')
        .position({ x: '6%', y: '18%' })
    }
    .width('100%').height('100%')
    .position({ x: 0, y: 0 })
  }
}

10. HarmonyOS 开发的六个阶段

基于六款 App 的开发经历,以下是 HarmonyOS 开发者可能经历的六个阶段:

10.1 阶段一:新手期(白噪音)

特征:16 个错误,基本语法不熟悉

学习重点

  • ArkTS 的基本类型系统(interface、type)
  • @State 和 @Builder 的基本用法
  • 组件的属性链式调用

挑战:理解声明式 UI 的思维方式——“UI 是状态的函数”

10.2 阶段二:探索期(时间胶囊)

特征:17 个错误,开始尝试新模式

学习重点

  • 数据持久化(Preferences)
  • 条件渲染和弹窗系统
  • 日期计算和格式化

挑战:学会在 @Builder 中避免 letreturn

10.3 阶段三:试错期(冰箱剩菜)

特征:22 个错误,最高峰

学习重点

  • Tab 架构
  • Grid 弹窗
  • 复杂的表单交互

挑战:不要用闭包参数给 @Builder 传内容——这是最大的一个坑

10.4 阶段四:成熟期(尴尬粉碎机)

特征:1 个错误,最低谷

学习重点

  • 模式复用
  • 静态数据管理
  • 仪式感交互设计

挑战:如何在新 App 中复用已总结的模式

10.5 阶段五:收敛期(防骗训练、碎片学习)

特征:12 个错误,稳定

学习重点

  • 适老化设计
  • 学习激励机制
  • 代码量增长时的质量控制

挑战:当代码量超过 800 行时,如何保持 Builder 的整洁

10.6 六阶段的心得总结

阶段 App 关键教训
1. 新手期 白噪音 理解声明式思维
2. 探索期 时间胶囊 掌握 Builder 约束
3. 试错期 冰箱剩菜 不要用闭包抽象 UI
4. 成熟期 尴尬粉碎机 复用模式可以减少 90% 的错误
5. 收敛期 防骗训练 大代码量需要更严谨的结构
6. 收官期 碎片时间学习 内容设计和用户体验同样重要

11. 结语

11.1 六款 App 的技术覆盖

六款 App 覆盖了 HarmonyOS Next 应用开发的多个核心技术领域:

技术领域 相关 App
多媒体播放 白噪音
动画系统 白噪音、尴尬粉碎机
数据持久化 时间胶囊、冰箱剩菜、尴尬粉碎机、防骗训练、碎片学习
声明式 UI 全部六款
Tab 架构 冰箱剩菜、尴尬粉碎机、防骗训练、碎片学习
列表交互 时间胶囊、冰箱剩菜、尴尬粉碎机
弹窗系统 全部六款
适老化设计 防骗训练
学习激励 碎片时间学习

11.2 六篇博客的知识体系

本系列六篇博客构成了一个完整的 ArkUI 开发知识体系:

  1. 白噪音:初识 ArkUI + 多媒体 API
  2. 时间胶囊:数据持久化 + @Builder 语法
  3. 冰箱剩菜:Tab 架构 + 复杂交互
  4. 尴尬粉碎机:模式复用 + 静态数据
  5. 防骗训练:适老化 + 情景模拟
  6. 碎片时间学习:内容设计 + 学习追踪

11.3 给后来者的建议

  1. 从简单开始:第一款 App 不要超过 500 行,理解核心概念后再增加复杂度
  2. 记录错误模式:每次编译错误都是一个学习机会,记下来下次避免
  3. 先设计数据模型:写 UI 之前先定义好 interface
  4. 模式复用:新 App 优先使用已验证的模式
  5. Builder 不放逻辑:这是 ArkUI 最重要的规则

11.4 系列结语

从"沉浸式白噪音"到"碎片时间学习",六款 App、六篇博客、约 6000 行代码、约 80 个编译错误——这是一次完整的 ArkUI 学习之旅。

如果你是从第一篇一路读到这里的读者,恭喜你!你已经掌握了 HarmonyOS Next 应用开发的核心理念。现在,打开 DevEco Studio,开始你的第一个 ArkUI 项目吧。


附录 A:六款 App 数据全览

指标 白噪音 时间胶囊 冰箱剩菜 尴尬粉碎机 防骗训练 碎片学习
@State 数 8 8 14 10 11 10
@Builder 数 8 12 17 15 14 14
方法数 8 12 19 9 12 13
总行数 767 955 1320 953 1038 851
编译错误 16 17 22 1 12 12
修复轮次 2 2 3 1 2 2
Tab 数 1 1 3 3 3 3
持久化

附录 B:核心代码片段速查

弹窗模板

@Builder
buildDialog() {
  if (this.condition) {
    Column() {
      Column().width('100%').height('100%')
        .backgroundColor('rgba(0,0,0,0.5)')
        .onClick(() => { this.condition = false; })
      Column() { /* 内容 */ }
        .width('88%').backgroundColor(Color.White)
        .borderRadius(24).position({ x: '6%', y: '18%' })
    }
    .width('100%').height('100%').position({ x: 0, y: 0 })
  }
}

数组更新

this.list = [newItem].concat(this.list);     // 插入
this.list = this.list.concat([]);            // 触发渲染
this.list = this.list.filter(predicate);     // 删除

Tab 切换

@State activeTab: number = 0;
buildTabContent() {
  if (this.activeTab === 0) this.buildTab0()
  else if (this.activeTab === 1) this.buildTab1()
  else this.buildTab2()
}

数据持久化

async loadData() {
  let prefs = await preferences.getPreferences(ctx, 'my_db');
  let val = await prefs.get('key', '');
  if (val !== '') this.data = JSON.parse(val as string);
}
async saveData() {
  await this.prefs.put('key', JSON.stringify(this.data));
  await this.prefs.flush();
}

Logo

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

更多推荐