当前位置: 首页 > news >正文

【OpenHarmony/HarmonyOs 】化学学习 App 收藏夹功能实践:AppStorage 本地持久化与响应式刷新

【OpenHarmony/HarmonyOs 】化学学习 App 收藏夹功能实践:AppStorage 本地持久化与响应式刷新

收藏夹是学习类 App 中非常重要的功能。用户遇到常用元素、难记方程式、重点知识点时,都希望能一键保存,后续快速复习。本文结合我的「化学视界」项目,聊聊我是如何开发收藏功能的。⭐

一、为什么收藏功能不能只做一个按钮?

刚开始做收藏时,很容易以为只要在详情页放一个爱心按钮就够了。但真正开发后会发现,收藏系统至少要解决几个问题:

  • 用户能收藏哪些内容?
  • 收藏后如何持久保存?
  • 多个页面之间如何同步收藏状态?
  • 收藏夹如何分类展示?
  • 取消收藏后列表如何刷新?
  • 点击收藏项如何回到详情页?

我的项目里,收藏对象包括三类:

  • ⚛️ 元素。
  • ⚗️ 方程式。
  • 📚 知识点。

所以我先设计了统一的收藏数据结构,而不是给每种内容单独写一套逻辑。

二、收藏数据结构设计

收藏项定义如下:

exporttypeFavoriteType='element'|'equation'|'knowledge';exportinterfaceFavoriteItem {id:string;type:FavoriteType;title:string;subtitle:string;dateAdded:string; }

这里的几个字段分别解决不同问题:

  • id:定位原始内容。
  • type:区分元素、方程式、知识点。
  • title:收藏夹列表主标题。
  • subtitle:辅助说明,比如元素符号、方程式内容、知识标签。
  • dateAdded:记录收藏时间。

我开发时的一个经验是:收藏夹列表不要只存 id。只存 id 虽然最干净,但列表展示时还要反查原始数据。适当冗余titlesubtitle,可以让收藏夹展示更直接。

三、使用 AppStorage 保存收藏数据

收藏数据写入本地状态:

functionwriteFavorites(items: FavoriteItem[]): void {AppStorage.setOrCreate(STORAGE_KEY, JSON.stringify(items)); const marker = (AppStorage.get<number>(STORAGE_VERSION_KEY) ??0) +1;AppStorage.setOrCreate(STORAGE_VERSION_KEY,marker); }

这里有一个关键点:我除了保存收藏数组,还额外维护了一个刷新标记。

原因是收藏可能发生在多个页面:

  • 元素详情页点击收藏。
  • 方程式详情页点击收藏。
  • 知识详情页点击收藏。
  • 收藏夹里取消收藏。

如果没有统一刷新机制,某个页面的收藏状态很容易滞后。

四、添加收藏:先去重再写入

添加收藏时,我先读取已有收藏,再判断是否已经收藏过:

exportfunctionaddFavorite(type: FavoriteType,id:string,title:string): boolean { const items = readFavorites();if(items.some(item => item.type===type&&item.id===id)) { returnfalse; } items.push({ id,type, title, subtitle: getSubtitle(type,id), dateAdded: formatDate(newDate()) }); writeFavorites(items); returntrue; }

这里我用type + id判断唯一性,因为元素、方程式、知识点可能都有数字 id,单独用 id 不够安全。

五、切换收藏状态:详情页最常用

详情页里一般不需要关心“添加”还是“删除”,只要调用切换函数:

exportfunctiontoggleFavorite(type: FavoriteType,id:string,title:string): boolean { const items = readFavorites(); const idx = items.findIndex(item=>item.type===type&&item.id===id);if(idx >=0) { removeFavorite(type,id); returnfalse; }else{ addFavorite(type,id,title); returntrue; } }

元素详情页中就是这样使用的:

handleFavoriteClick() {if(this.elementLocal) { constnewState= toggleFavorite('element',String(this.elementLocal.number),this.elementLocal.name ); animateTo({ duration:300, curve:Curve.EaseOut }, () => {this.isFavorite =newState; }); } }

这样详情页逻辑就很清楚:点击按钮 → 切换状态 → 更新 UI。

六、收藏夹页面:用 StorageLink 自动响应变化

收藏夹页面使用刷新标记监听收藏变化:

@StorageLink(FAVORITES_VERSION_KEY)@Watch('onVersionChange')version: number =0;

当收藏数据变化时,页面重新加载收藏列表:

onVersionChange() {this.watchVersionChange(); }watchVersionChange() {this.allFavorites=getAllFavorites();this.updateFilteredFavorites(); }

我当时这样设计,是为了避免在每个页面之间手动传递事件。收藏数据变化后,只要刷新标记变化,收藏夹自然更新。

七、收藏夹分类展示

收藏夹顶部有四个分类:

  • 全部。
  • 元素。
  • 方程式。
  • 知识。

过滤逻辑如下:

updateFilteredFavorites(): void {if(this.selectedTab ===0) {this.filteredFavorites =this.allFavorites; }elseif(this.selectedTab ===1) {this.filteredFavorites =this.allFavorites.filter( (f: FavoriteItem) => f.type ==='element'); }elseif(this.selectedTab ===2) {this.filteredFavorites =this.allFavorites.filter( (f: FavoriteItem) => f.type ==='equation'); }else{this.filteredFavorites =this.allFavorites.filter( (f: FavoriteItem) => f.type ==='knowledge'); } }

这部分我没有做复杂抽象,因为分类只有几种,直接写清楚反而更容易维护。

八、从收藏夹跳回详情页

收藏夹不能只是一个静态列表,点击收藏项后应该回到对应详情页:

navigateToDetail(item:FavoriteItem) {if(item.type=== 'element') {router.pushUrl({url: 'pages/periodic/ElementDetail',params: {elementNumber:Number(item.id) }}); }elseif(item.type=== 'equation') {router.pushUrl({url: 'pages/equations/EquationDetail',params: {equationId:Number(item.id) }}); }elseif(item.type=== 'knowledge') {router.pushUrl({url: 'pages/knowledge/KnowledgeDetail',params: {knowledgeId:Number(item.id) }}); } }

这也是我前面统一收藏结构的好处:一个type就能决定跳转目标。

九、开发中遇到的关键点

1. 收藏状态要跨页面一致

如果只在当前页面维护isFavorite,收藏夹不会自动刷新。所以我用了刷新标记做全局同步。

2. 收藏项要有展示字段

只保存 id 会让收藏夹很难展示,所以我保存了titlesubtitle

3. 删除收藏要走统一方法

无论是在详情页取消收藏,还是收藏夹里删除,都调用同一套工具函数,避免数据不一致。

十、总结

收藏功能看起来简单,但要做完整,需要处理数据结构、持久化、状态同步、分类展示和详情跳转。

我的实现思路是:

  • ⭐ 用统一结构保存不同类型内容。
  • 💾 用本地状态保存收藏列表。
  • 🔄 用刷新标记驱动页面自动更新。
  • 🧭 用type + id实现详情跳转。
  • 🎨 用分类和图标提升可读性。

对于学习类 App 来说,收藏夹不只是“保存喜欢的内容”,更是用户复习路径的一部分。把收藏功能做扎实,整个学习闭环才会更完整。

http://www.cnnetsun.cn/news/3211751.html

相关文章:

  • 音视频编解码:VP8 / VP9 / H.264 / Opus
  • 2026降AIGC革命:AI率92%暴降至5%!实测10款AI智能降重工具!10款工具深度解析!
  • 3分钟搞定网易云插件安装:BetterNCM-Installer终极解决方案
  • spring通过方法注入,针对多实例的Bean
  • 2026年7月探寻四川信誉优良的GEO优化运营商
  • AutoJS6 + Shizuku 实战:淘金币自动签到与任务脚本
  • 如何一次性解决所有Visual C++运行库问题:终极AIO安装指南
  • Typeahead 2.0 智能搜索体验升级实战
  • 阿里面试:如果Agent 挂100个 Skill ,如何提升召回率、准确度、F1综合值?尼恩 《Skills调优圣经》,来一次 泰山压顶 式的 降维打击
  • rust 学习 闭包
  • 第4章:Linux系统重点复习
  • AI 看不懂老项目?先用“项目说明书 + 目录树”把上下文交给它
  • [特殊字符]《京东宙斯迁移公告解读:老接口 360buy.ware.get→ jingdong.ware.read.get平滑切换(附Python源码)》
  • 从零搭建工业物联网监控大屏:Node-RED + 有人云 零代码方案
  • HRD进化论04讲:战略解码
  • PostgreSQL高级特性应用
  • PyTorch DDP 多机多卡配置:2节点8卡集群部署与通信瓶颈分析
  • Models-学习指南_小白版
  • Mermaid终极指南:用代码快速创建专业图表,彻底告别文档滞后问题
  • Windows 证书管理:3种存储位置(个人/根/中间)的导入策略与安全影响
  • AD7175-8与PIC18F4610高精度信号采集方案解析
  • 2026年AI写作辅助平台实测认证:5款神器从文献到降重一站式避坑指南
  • 15个实用的代码审查工具,自动化检查
  • 如何快速精通猫抓资源嗅探:进阶用户终极配置指南
  • 15个实用的代码版本控制工具,Git替代品
  • 《B4071 [GESP202412 五级] 武器强化》
  • GHelper终极指南:轻松掌控华硕笔记本性能的轻量级神器
  • 兰州兰银官话语义角色标注数据采集公司
  • FFmpeg 入门:命令行的 20 个常用场景
  • OpenCV 相机标定与3D可视化:8张棋盘格图像标定,内参误差低于0.5像素