HarmonyOS7 购物车看着简单最容易翻车:增删改、全选、价格计算一篇讲透
文章目录前言购物车数据模型全选与反选逻辑数量步进器滑动删除价格计算完整页面拼装一些实用建议前言购物车这个页面看着简单做起来坑真不少。增删改查、全选反选、滑动删除、实时价格计算——每个功能单独拎出来都不难凑一块儿状态管理就容易乱。今天把鲜选商城的购物车完整跑通顺便聊聊我踩过的那些坑。购物车数据模型先把数据结构定好后面所有逻辑都围绕它转。购物车里的每一条商品需要记录商品基本信息、选中状态和购买数量。// CartItem 数据模型ObservedclassCartItem{id:stringgoodsId:stringname:stringcoverUrl:stringspecText:string// 规格描述如红色/XLprice:number// 单价分originalPrice:number// 原价quantity:numberchecked:booleanstock:number// 库存上限shopId:stringconstructor(partial:PartialCartItem){this.idpartial.id??this.goodsIdpartial.goodsId??this.namepartial.name??this.coverUrlpartial.coverUrl??this.specTextpartial.specText??this.pricepartial.price??0this.originalPricepartial.originalPrice??0this.quantitypartial.quantity??1this.checkedpartial.checked??falsethis.stockpartial.stock??99this.shopIdpartial.shopId??}}有个经验价格用分而不是元存储。浮点数加减乘除会出精度问题比如0.1 0.2 0.30000000000000004用整数算完再除以 100 显示稳得多。全选与反选逻辑全选按钮的状态分三种全不选、部分选、全选。我用一个计算属性来搞定// 全选状态三种态getcheckedState():CheckboxState{constcheckedItemsthis.cartList.filter(itemitem.checked)if(checkedItems.length0)returnCheckboxState.Uncheckedif(checkedItems.lengththis.cartList.length)returnCheckboxState.CheckedreturnCheckboxState.Indeterminate// 半选态}// 全选/取消全选toggleAll(){constnewCheckedthis.checkedState!CheckboxState.Checkedthis.cartList.forEach(itemitem.checkednewChecked)}这里容易犯的错误是直接拿布尔值做判断忽略了半选状态。鸿蒙的Checkbox支持CheckboxState.Indeterminate用上它全选按钮才有那味儿。数量步进器鸿蒙自带Stepper组件但它默认样式比较朴素购物车里通常需要自定义。我包了一层Componentstruct QuantityStepper{PropWatch(onValueChange)value:number1min:number1max:number99onValueChange?:(val:number)voidbuild(){Row(){Button(-).fontSize(16).width(28).height(28).backgroundColor(#F5F5F5).enabled(this.valuethis.min).opacity(this.valuethis.min?1:0.4).onClick((){if(this.valuethis.min)this.value--})Text(${this.value}).fontSize(14).width(40).textAlign(TextAlign.Center)Button().fontSize(16).width(28).height(28).backgroundColor(#F5F5F5).enabled(this.valuethis.max).opacity(this.valuethis.max?1:0.4).onClick((){if(this.valuethis.max)this.value})}}}Watch装饰器是关键——外部传入onValueChange回调数量变了自动通知父组件更新购物车数据和价格。滑动删除鸿蒙的ListItem配合swipeAction属性滑动删除几行代码就搞定ForEach(this.cartList,(item:CartItem){ListItem(){CartItemCard({item:item})}.swipeAction({end:this.buildDeleteAction(item)})},(item:CartItem)item.id)// 滑出来的删除按钮BuilderbuildDeleteAction(item:CartItem){Row(){Button(删除).backgroundColor(#FF4D4F).fontColor(#FFFFFF).height(100%).width(80).onClick((){this.removeItem(item.id)})}}批量删除也不复杂底部栏加个删除按钮点击时把checked true的全干掉。记得加个确认弹窗不然用户误操作就炸了。价格计算价格计算我抽成独立方法所有需要总价的地方都调它// 计算选中商品总价calcSelectedTotal():PriceBreakdown{constselectedthis.cartList.filter(itemitem.checked)consttotalOriginalselected.reduce((sum,item)sumitem.originalPrice*item.quantity,0)consttotalSaleselected.reduce((sum,item)sumitem.price*item.quantity,0)constdiscounttotalOriginal-totalSaleconstcountselected.reduce((sum,item)sumitem.quantity,0)return{totalAmount:totalSale,// 实付金额totalOriginal:totalOriginal,discount:discount,// 优惠金额selectedCount:count}}这里有个细节Observed修饰的CartItem内部属性变化能触发 UI 刷新。但如果你的数组很深比如嵌套了店铺分组得注意Observed只监听第一层属性深层嵌套需要用ObjectLink传递。完整页面拼装把上面的模块拼到一起页面结构大概是这样的Componentstruct CartPage{StatecartList:CartItem[][]StatepriceBreakdown:PriceBreakdownnewPriceBreakdown()build(){Column(){// 顶部导航NavBar({title:购物车})// 商品列表按店铺分组List(){ForEach(this.groupByShop(),(group:ShopGroup){ListItemGroup({header:this.buildShopHeader(group)})ForEach(group.items,(item:CartItem){ListItem(){CartItemCard({item:item})}.swipeAction({end:this.buildDeleteAction(item)})})})}.width(100%).layoutWeight(1).scrollBar(BarState.Off)// 底部结算栏BottomBar({checkedState:this.checkedState,onToggleAll:()this.toggleAll(),breakdown:this.priceBreakdown,onCheckout:()this.goCheckout()})}.width(100%).height(100%).backgroundColor(#F5F5F5)}}购物车页面状态比较多我一开始想着全用State管理结果发现状态之间互相影响——改了数量要更新总价改了选中要更新底部栏。后来改成用ObservedObjectLink的方式每个CartItem自己管理自己的状态总价通过计算方法实时算清爽很多。一些实用建议空状态别忘了。购物车为空的时候显示个占位图 去逛逛按钮别让用户看到一个空白页面。本地缓存很重要。用户加购了商品、改过数量突然杀进程再进来发现购物车空了体验极差。用Preferences或者relationalStore做个本地持久化数据回来体验好很多。步进器的库存校验。用户点的时候不仅要判断不超过max还要跟库存stock对比。库存不足的时候弹个 Toast 提示比让用户到结算页才发现买不了强。购物车这个页面就是细节多每个小功能都不难但状态流转一多就容易出 bug。我的建议是先把数据模型和状态流转图画清楚再动手写代码效率反而更高。下一篇我们搞 SKU 选择器那个规格矩阵算法才是真的烧脑不过搞懂了会觉得挺有意思。

相关新闻

实用小工具上线!BlockSec USDT拉黑查询网站,一键核验地址冻结状态

实用小工具上线!BlockSec USDT拉黑查询网站,一键核验地址冻结状态

在USDT交易中,地址冻结、解冻状态查询是用户高频刚需,却长期受困于传统渠道短板——TronScan、Etherscan 无相关展示功能,个别企业级KYT工具又缺乏便捷查询入口。下面就为大家详细拆解网站四个页面。 1. Overview:全局数据一键预…

2026/7/1 18:06:24阅读更多 →
AMD 显卡跑大模型,vLLM 加 ROCm 7.x 环境配置避坑指南

AMD 显卡跑大模型,vLLM 加 ROCm 7.x 环境配置避坑指南

从零搭建:AMD Instinct GPU 上的 vLLM 推理环境 手里拿到 AMD Instinct MI300X 这类加速卡,想跑大模型推理,第一道坎往往不是算法,而是环境配置。ROCm 生态虽然进步飞快,但细节上的“坑”依然不少。很多开发者卡在驱动…

2026/7/1 18:06:24阅读更多 →
高精度计时系统:CS2200-CP与PIC18F2620硬件设计与实现

高精度计时系统:CS2200-CP与PIC18F2620硬件设计与实现

1. 精确计时系统的硬件选型与架构设计在工业控制、科学实验和物联网设备中,精确计时往往是系统可靠性的基石。CS2200-CP作为一款高性能时钟频率合成器,与PIC18F2620微控制器的组合,为需要纳秒级精度的时间敏感型应用提供了经济高效的解决方案…

2026/7/1 18:06:24阅读更多 →
Day10 AQS框架:ReentrantLock与CountDownLatch的共同秘密

Day10 AQS框架:ReentrantLock与CountDownLatch的共同秘密

专栏《Java后端工程师进阶之路》工作日每日一更。欢迎关注老梁。 一、AQS 是什么:并发包的"底层操作系统" 如果把 JUC 并发包看作一座大厦,AQS 就是地基和承重墙。它提供了一个模板框架: 维护一个 volatile int state 表示同步状…

2026/7/1 19:26:42阅读更多 →
抖音下载器专业方案:高效解决音频视频批量下载与管理的自动化系统

抖音下载器专业方案:高效解决音频视频批量下载与管理的自动化系统

抖音下载器专业方案:高效解决音频视频批量下载与管理的自动化系统 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fal…

2026/7/1 19:26:42阅读更多 →
如何用WiFi热图绘制工具快速优化家庭网络覆盖:终极指南

如何用WiFi热图绘制工具快速优化家庭网络覆盖:终极指南

如何用WiFi热图绘制工具快速优化家庭网络覆盖:终极指南 【免费下载链接】wifi-heat-mapper whm also known as wifi-heat-mapper is a Python library for benchmarking Wi-Fi networks and gather useful metrics that can be converted into meaningful easy-to-u…

2026/7/1 19:26:42阅读更多 →
苹果 macOS 图标改进:从糟糕到出色,何时释放图标形状限制?

苹果 macOS 图标改进:从糟糕到出色,何时释放图标形状限制?

应用程序与相关链接名字奇特,软件出色。这里有一系列应用程序,如 Airfoil、Audio Hijack、Farrago、Fission、Loopback、Piezo、Soundsource 等。还有商店、支持、公司、博客等相关链接。释放图标:苹果应取消对 macOS 应用图标形状的限制作者…

2026/7/1 19:26:42阅读更多 →
【毕业设计】信息化在线教学平台 SpringBoot+Vue 完整源码(含论文+数据库,可运行)

【毕业设计】信息化在线教学平台 SpringBoot+Vue 完整源码(含论文+数据库,可运行)

🧑‍💻 博主介绍 & 诚邀关注 作者:专注于 Java、Python、前端开发的技术博主 | 全网粉丝 30 万 在校期间协助导师完成毕业设计课题分类、论文格式初审及代码整理工作;工作后持续分享毕设思路,助力毕业生顺利完成…

2026/7/1 19:26:42阅读更多 →
C++ 模板初阶:从重复代码到泛型编程

C++ 模板初阶:从重复代码到泛型编程

C 模板初阶:从重复代码到泛型编程 快速跳转: 前言 为什么需要模板 函数模板 模板原理 实例化 匹配规则 类模板 小结 前言 刚开始写 C 时,我们很容易遇到一种尴尬情况:逻辑明明一模一样,只是类型不同,代码却…

2026/7/1 19:21:41阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/7/1 4:42:14阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/7/1 5:19:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/1 0:01:44阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/1 0:01:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/1 0:01:44阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/1 0:01:44阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/1 0:01:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/1 0:01:44阅读更多 →