news 2026/6/24 22:58:56

HarmonyOS 6商城开发学习:商品浏览记录本地存储——PersistentStorage+AppStorage驱动去重与上限截断

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS 6商城开发学习:商品浏览记录本地存储——PersistentStorage+AppStorage驱动去重与上限截断

在HarmonyOS 6购物比价或电商类应用中,"最近浏览"是高频场景:用户进入商品详情页,自动将商品追加到浏览记录列表(去重、上限保留如20条),我的-浏览历史页按时间倒序展示,支持清空。记录只需存本地,不需要账号云同步。

官方行业实践推荐用PersistentStorage 持久化 + AppStorage 响应式驱动,本文将完整实现这一方案——含数据模型、去重截断、历史列表展示与清空。


一、需求拆解与数据模型

1. 功能点

  • 进入商品详情 → 调用addBrowseRecord(goods)→ 同ID去重后置顶、超上限截断 → 自动落盘

  • 浏览历史页 → 从 AppStorage 读取数组 →ForEach渲染卡片

  • 清空 → 置空数组 → 自动同步 PersistentStorage

2. 数据模型

// model/BrowseRecord.ets export interface BrowseGoods { id: string; name: string; price: string; // "¥199" img: Resource; // 缩略图 browseTime: number; // Date.now() 时间戳 } export const MAX_BROWSE = 20; // 最多保留条数 export const STORE_KEY = 'browse_history';

二、持久化初始化(关键一步)

必须在UIAbility 的onWindowStageCreate​ 或入口页aboutToAppear最早时机调用,将 key 与 AppStorage 双向绑定:

// 在 EntryAbility.ets 或首个 Page aboutToAppear 中 import { PersistentStorage } from '@ohos.arkui.node'; // 初始化:若磁盘无值则用 '[]' PersistentStorage.persistProp('browse_history', '[]');

⚠️persistProp(key, defaultValue)只需调用一次/应用生命周期,后续直接用AppStorage.get/set即可自动读写磁盘。


三、浏览记录管理工具类

// utils/BrowseStore.ets import { BrowseGoods, MAX_BROWSE, STORE_KEY } from '../model/BrowseRecord'; /** 读取当前浏览记录(解析JSON) */ export function loadBrowseList(): BrowseGoods[] { try { const raw = AppStorage.get<string>(STORE_KEY) ?? '[]'; return JSON.parse(raw) as BrowseGoods[]; } catch { return []; } } /** 写入并自动持久化 */ function save(list: BrowseGoods[]) { AppStorage.setOrCreate(STORE_KEY, JSON.stringify(list)); // PersistentStorage 监听 AppStorage 变化自动 flush,无需手动调 } /** 添加浏览记录(去重→置顶→截断) */ export function addBrowseRecord(goods: BrowseGoods) { let list = loadBrowseList(); // 去重:移除旧相同ID list = list.filter(i => i.id !== goods.id); // 置顶 list.unshift({ ...goods, browseTime: Date.now() }); // 上限截断 if (list.length > MAX_BROWSE) { list = list.slice(0, MAX_BROWSE); } save(list); } /** 清空浏览记录 */ export function clearBrowseHistory() { save([]); }

四、商品详情页——触发记录(示例)

// pages/GoodsDetailPage.ets import { addBrowseRecord } from '../utils/BrowseStore'; import { BrowseGoods } from '../model/BrowseRecord'; @Entry @Component struct GoodsDetailPage { // 模拟当前商品 private goods: BrowseGoods = { id: 'G007', name: 'HarmonyOS 6 旗舰耳机', price: '¥599', img: $r('app.media.ic_headphone'), browseTime: 0 }; aboutToAppear() { // 进入详情即记录浏览 addBrowseRecord(this.goods); } build() { Column() { Image(this.goods.img).width(200).height(200).objectFit(ImageFit.Contain) .margin(24) Text(this.goods.name).fontSize(18).fontWeight(FontWeight.Bold) Text(this.goods.price).fontSize(16).fontColor('#FF5722').margin(8) Text('已加入浏览记录').fontSize(12).fontColor('#999').margin(40) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) .backgroundColor(Color.White) } }

五、浏览历史页——列表展示与清空

// pages/BrowseHistoryPage.ets import { loadBrowseList, clearBrowseHistory } from '../utils/BrowseStore'; import { BrowseGoods } from '../model/BrowseRecord'; import { promptAction } from '@kit.ArkUI'; @Entry @Component struct BrowseHistoryPage { // 用 @State 同步,实际项目可在 aboutToAppear 中 loadBrowseList 初始化 // 若想完全响应式可包装成 @StorageLink('browse_history') 自行解析,此处简化为 onShow 重载 @State list: BrowseGoods[] = []; onShow() { this.list = loadBrowseList(); } build() { Column() { // 标题栏 Row { Text('浏览记录') .fontSize(20) .fontWeight(FontWeight.Bold) Blank() if (this.list.length > 0) { Text('清空') .fontSize(13) .fontColor('#FF5722') .onClick(() => { clearBrowseHistory(); this.list = []; promptAction.showToast({ message: '已清空' }); }) } } .padding({ horizontal: 16, top: 16, bottom: 8 }) // 列表 if (this.list.length === 0) { Column() { Text('暂无浏览记录') .fontSize(14) .fontColor('#BBB') } .layoutWeight(1) .justifyContent(FlexAlign.Center) } else { List() { ForEach(this.list, (item: BrowseGoods) => { ListItem() { Row({ space: 12 }) { Image(item.img) .width(64).height(64).borderRadius(8).objectFit(ImageFit.Cover) Column() { Text(item.name).fontSize(15).fontColor('#333').maxLines(1) Text(item.price).fontSize(14).fontColor('#FF5722').margin({ top: 4 }) Text(formatTime(item.browseTime)) .fontSize(11) .fontColor('#AAA') .margin({ top: 2 }) }.layoutWeight(1).alignItems(HorizontalAlign.Start) } .padding(12) } }, (item: BrowseGoods) => item.id) } .layoutWeight(1) .padding(12) } } .width('100%') .height('100%') .backgroundColor('#F5F6F8') } } // 时间格式化辅助 function formatTime(ts: number): string { if (!ts) return ''; const d = new Date(ts); return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')} ${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`; }

六、避坑指南

问题

原因

修复

重启后记录丢失

未调PersistentStorage.persistProp()或调太晚(页面已mount)

EntryAbility.onWindowStageCreate最早调一次

存储值变[object Object]

直接AppStorage.set(STORE_KEY, list)JSON.stringify

存字符串化JSON:JSON.stringify(list)

历史页不刷新

onShow未重新loadBrowseList()

onShow中刷新@State list

ForEach key用index

列表重排可能UI异常

key用item.id(唯一商品ID)

超限不截断

unshiftslice(0,MAX)

添加后list = list.slice(0, MAX_BROWSE)


七、总结:浏览记录存储SOP

  1. 初始化PersistentStorage.persistProp('browse_history','[]')应用启动时执行一次

  2. 进入详情addBrowseRecord()→ 去重→置顶→截断→AppStorage.set(字符串化数组)

  3. 历史页onShowloadBrowseList()渲染;清空调clearBrowseHistory()。

  4. PersistentStorage自动落盘:AppStorage值变化即异步写磁盘,无需手动flush。

核心法则:HarmonyOS 6本地浏览记录 =PersistentStorage绑定AppStorage + JSON序列化数组 + 去重置顶截断,轻量、响应、无服务端依赖。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/8 15:59:37

基于NXP LPC5460x与TFTP的嵌入式OTA固件更新方案详解

1. 项目概述与核心价值在嵌入式产品&#xff0c;尤其是物联网设备的生命周期中&#xff0c;固件更新是一个绕不开的环节。想象一下&#xff0c;一个部署在工厂车间或偏远地区的传感器节点&#xff0c;如果发现了一个软件缺陷或需要增加新功能&#xff0c;难道要工程师带着电脑和…

作者头像 李华
网站建设 2026/6/8 15:56:25

CAN总线错误处理与MSCAN中断服务程序实战解析

1. 项目概述&#xff1a;从错误计数器到中断响应的CAN总线健壮性设计在汽车电子或工业控制领域摸爬滚打过的嵌入式工程师&#xff0c;对CAN总线一定不会陌生。它那两根看似简单的双绞线背后&#xff0c;是一套极其严谨的通信协议&#xff0c;而支撑其“高可靠”口碑的核心&…

作者头像 李华
网站建设 2026/6/8 15:56:13

C语言项目实战:用cJSON库读写配置文件,告别手写解析的烦恼

C语言项目实战&#xff1a;用cJSON库读写配置文件&#xff0c;告别手写解析的烦恼在嵌入式系统和物联网项目中&#xff0c;配置文件的管理往往是个令人头疼的问题。传统的手写解析代码不仅耗时耗力&#xff0c;还容易出错。而cJSON这个轻量级的C语言JSON解析库&#xff0c;正能…

作者头像 李华
网站建设 2026/6/8 15:55:35

3分钟免费解锁Grammarly Premium高级版:开源工具全指南

3分钟免费解锁Grammarly Premium高级版&#xff1a;开源工具全指南 【免费下载链接】autosearch-grammarly-premium-cookie 免费白嫖使用Grammarly Premium高级版 项目地址: https://gitcode.com/gh_mirrors/au/autosearch-grammarly-premium-cookie 你是否渴望使用Gram…

作者头像 李华