HarmonyOS5 购物商城app(二):购物车与支付(附代码)
鸿蒙应用购物车模块开发实践:从代码解析到功能实现
一、引言
在鸿蒙(HarmonyOS)应用生态中,购物车功能是电商类应用的核心组成部分,它承担着整合用户选购商品、计算总价、支撑支付流程等关键职责。本文将深入剖析一段鸿蒙应用购物车功能的实现代码,详细解读从商品数据管理、界面交互到支付流程衔接的完整逻辑,为鸿蒙应用开发者提供实践参考。
二、数据模型搭建:构建购物车基石
(一)商品类 ShopClass
定义
class ShopClass {img: string = ''name: string = ''attributes: string = ''price: number = 0id: number = 0quantity: number = 0constructor(img: string, name: string, attributes: string, price: number, id: number, quantity: number) {this.img = imgthis.name = namethis.attributes = attributesthis.price = pricethis.id = idthis.quantity = quantity}
}
ShopClass
作为购物车商品的数据载体,清晰定义了商品图片路径、名称、属性描述、价格、唯一标识及数量等核心属性 。通过构造函数,能便捷地初始化商品信息,为后续购物车功能实现提供基础数据模型,让每个商品在购物车流程中都有明确的“身份”与“特征”。
(二)支付信息接口 pays
设计
interface pays{pay: numbershopDel: Array<ShopClass>
}
pays
接口用于规范购物车结算时传递的支付相关数据结构,其中 pay
存储结算总金额,shopDel
存放已选中待支付的商品集合,确保购物车页面与支付页面间数据传递的准确性与规范性,是衔接购物车结算和支付流程的关键数据桥梁。
三、主页面 Index
:购物车核心交互载体
(一)状态与数据管理
@Entry
@Component
struct Index {@Provide ('shopArray') ShopArray: Array<ShopClass> = [new ShopClass('app.media.shop_01', '华为家居小户科技布', '蓝色 尺寸L', 3600, 1, 1),new ShopClass('app.media.shop_02', '简约现代餐桌椅组合', '白色 一套', 8999, 2, 1),new ShopClass('app.media.shop_03', '智能无线吸尘器', '星空灰', 1499, 3, 1)]@State ShopDel: Array<ShopClass> = []@State flag: boolean = false@State priceSum: number = 0@Provide('mainStarIndex') mainStarIndex: NavPathStack = new NavPathStack();//...
}
@Provide
与@State
装饰器:@Provide('shopArray')
共享商品列表数据,方便子组件访问;@State
分别管理已选中商品集合ShopDel
、全选状态flag
以及总价priceSum
,实现组件内部状态的响应式更新。NavPathStack
:借助其实现页面导航功能,搭建购物车主页与支付页的跳转逻辑,让用户在购物流程中能顺畅切换页面。
(二)界面构建与交互逻辑
1. 标题栏设计
Row() {Row({ space: 10 }) {Image($r('app.media.shopcar')) .width(50).height(50)Text('购物车').fontSize(24).fontWeight(FontWeight.Bold)}.width('100%').justifyContent(FlexAlign.SpaceBetween).alignItems(VerticalAlign.Center).padding({ top: 10, bottom: 15 })
}
通过 Row
组件搭建购物车标题栏,整合购物车图标与标题文本。设置布局属性,让标题栏在界面上美观且布局合理,为用户提供清晰的功能入口标识。
2. 商品列表展示
Scroll() {Column() {List() {ForEach(this.ShopArray, (item: ShopClass, index) => {ListItem() {shops({item: item,ShopDel: this.ShopDel,priceSum: this.priceSum,ShopArray: this.ShopArray})}.margin({ top: 10 })})}.lanes(1, 10)}.height('100%').justifyContent(FlexAlign.Start).backgroundColor('#fff5f5f5')
}
.layoutWeight(1)
.width('100%')
.padding(10)
利用 Scroll
、List
、ForEach
等组件构建商品滚动列表。shops
子组件负责渲染单个商品条目,实现商品展示、选中状态切换及数量调整等交互功能,让用户能直观浏览和操作购物车中的商品。
3. 结算栏交互
Row({ space: 8 }) {Checkbox().onChange((val) => {this.flag = valif (val) {this.ShopArray.forEach((item) => {if (!this.ShopDel.some(delItem => delItem.id === item.id)) {this.ShopDel.push(item);}})} else {this.ShopDel = []}this.updateTotalPrice()})Text('全选').layoutWeight(1)Text('合计:')Text(`¥${this.priceSum}`)Button('结算').backgroundColor(Color.Orange).onClick(() => {const pay:pays = { pay: this.priceSum, shopDel: this.ShopDel }this.mainStarIndex.pushPathByName('pay', pay)})
}
.height(60)
.width('100%')
.padding(16)
- 全选功能:复选框
Checkbox
结合onChange
事件,实现全选或取消全选逻辑。全选时遍历商品列表,将未选中商品加入ShopDel
;取消全选则清空ShopDel
,并调用updateTotalPrice
更新总价。 - 结算流程:结算按钮点击时,构建支付数据
pays
,通过NavPathStack
的pushPathByName
方法跳转至支付页面,开启支付流程。
四、商品条目 shops
组件:精细化商品交互
@Reusable
@Component
struct shops {@Prop item: ShopClass@Link ShopDel: Array<ShopClass>@Link priceSum: number@Link ShopArray: Array<ShopClass>@State checkboxif: boolean = false build() {Row({ space: 10 }) {Checkbox().onChange((value) => {if (value) {if (!this.ShopDel.some(delItem => delItem.id === this.item.id)) {this.checkboxif = truethis.ShopDel.push(this.item);}} else {this.ShopDel = this.ShopDel.filter((delItem) => delItem.id !== this.item.id);this.checkboxif = false}this.updateTotalPrice()this.checkboxif = this.ShopDel.length === this.ShopArray.length}).width(20)// 商品图片、信息列、数量控制区域等构建逻辑}.width('100%').height(80).backgroundColor(Color.White).borderRadius(8) .shadow({ color: '#1de9b6', radius: 4 }) }updateTotalPrice(): void {let total = 0this.ShopDel.forEach((shopItem) => {total += shopItem.price * shopItem.quantity})this.priceSum = total}
}
- 交互逻辑:作为商品列表子组件,通过
@Prop
、@Link
接收数据并实现双向绑定。复选框实现商品选中/取消选中功能,同步更新ShopDel
、总价及全选状态;数量控制区域的 “-”“+” 按钮,调整商品数量并实时更新总价,让用户能精细化操作单个商品。 - 界面美化:设置组件背景色、圆角及阴影效果,提升商品条目的视觉呈现,优化用户体验。
五、支付页面 pay
组件:完成购物闭环
@Component
struct pay {@Consume('mainStarIndex') mainStarIndex: NavPathStack;@Consume ('shopArray') shopArray: Array<ShopClass>@Prop pay: paysbuild() {NavDestination(){Column() {// 金额展示、支付方式选择、按钮等构建逻辑}.width('100%').height('100%').justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Center)}}onClickPay() {AlertDialog.show({message: '是否支付!',buttons: [{value: '确定',action: () => {this.shopArray = this.shopArray.filter((item) => !this.pay.shopDel.some(delItem => delItem.id === item.id))this.mainStarIndex.pop(); prompt.showToast({ message: '支付成功!' });}},{value: '取消',action: () => {}}]});}
}
- 支付流程:接收支付数据与商品列表,展示支付金额及支付宝、微信等支付方式选项。确认支付按钮点击后,弹出对话框询问用户,确认则从商品列表移除已结算商品,通过
mainStarIndex.pop()
返回购物车主页并提示支付成功;取消则终止支付流程,完成购物闭环的最后一环。 - 用户反馈:利用
prompt.showToast
提供支付结果反馈,增强用户对操作的感知。
六、附:代码
import { prompt } from '@kit.ArkUI'// 商品类定义
class ShopClass {img: string = ''name: string = ''attributes: string = ''price: number = 0id: number = 0quantity: number = 0constructor(img: string, name: string, attributes: string, price: number, id: number, quantity: number) {this.img = imgthis.name = namethis.attributes = attributesthis.price = pricethis.id = idthis.quantity = quantity}
}
interface pays{pay: numbershopDel: Array<ShopClass>
}@Entry
@Component
struct Index {// 购物车商品列表数据源@Provide ('shopArray') ShopArray: Array<ShopClass> = [new ShopClass('app.media.shop_01', '华为家居小户科技布', '蓝色 尺寸L', 3600, 1, 1),new ShopClass('app.media.shop_02', '简约现代餐桌椅组合', '白色 一套', 8999, 2, 1),new ShopClass('app.media.shop_03', '智能无线吸尘器', '星空灰', 1499, 3, 1)]// 已选中商品集合@State ShopDel: Array<ShopClass> = []// 全选状态标志@State flag: boolean = false// 总价@State priceSum: number = 0@Provide('mainStarIndex') mainStarIndex: NavPathStack = new NavPathStack();@BuildershopPage(name: string, params: pays) {if (name === 'pay') {pay({pay: params,})}}build() {Navigation(this.mainStarIndex){Column() {// 购物车标题栏Row() {Row({ space: 10 }) {Image($r('app.media.shopcar')) // 使用合适的购物车图标资源.width(50).height(50)Text('购物车').fontSize(24).fontWeight(FontWeight.Bold)}.width('100%').justifyContent(FlexAlign.SpaceBetween).alignItems(VerticalAlign.Center).padding({ top: 10, bottom: 15 })}Divider()// 商品滚动列表Scroll() {Column() {// 商品列表容器List() {ForEach(this.ShopArray, (item: ShopClass, index) => {ListItem() {shops({item: item,ShopDel: this.ShopDel,priceSum: this.priceSum,ShopArray: this.ShopArray})}.margin({ top: 10 })})}.lanes(1, 10)}.height('100%').justifyContent(FlexAlign.Start).backgroundColor('#fff5f5f5')}.layoutWeight(1).width('100%').padding(10)Divider()// 结算栏Row({ space: 8 }) {Checkbox().onChange((val) => {// 全选/取消全选逻辑this.flag = valif (val) {this.ShopArray.forEach((item) => {if (!this.ShopDel.some(delItem => delItem.id === item.id)) {this.ShopDel.push(item);}})} else {// 取消全选时清空ShopDelthis.ShopDel = []}// 更新总价this.updateTotalPrice()})Text('全选').layoutWeight(1)// 计算总价Text('合计:')Text(`¥${this.priceSum}`)Button('结算').backgroundColor(Color.Orange).onClick(() => {// 模拟结算操作const pay:pays = { pay: this.priceSum, shopDel: this.ShopDel }this.mainStarIndex.pushPathByName('pay', pay)})}.height(60).width('100%').padding(16)}.width('100%').height('100%')}.hideTitleBar(true).mode(NavigationMode.Stack).navDestination(this.shopPage)}// 单独提取更新总价的函数,便于维护和调用updateTotalPrice(): void {this.priceSum = this.ShopDel.reduce((sum, item) => sum + item.price * item.quantity, 0)}
}// 商品项构建器
@Reusable
@Component
struct shops {@Prop item: ShopClass@Link ShopDel: Array<ShopClass>@Link priceSum: number@Link ShopArray: Array<ShopClass>@State checkboxif: boolean = false // shop状态build() {Row({ space: 10 }) {// 复选框 - 用于选择商品Checkbox().onChange((value) => {if (value) {// 如果 value 为 true,将 item 添加到 this.ShopDel 中if (!this.ShopDel.some(delItem => delItem.id === this.item.id)) {this.checkboxif = truethis.ShopDel.push(this.item);}} else {// 如果 value 为 false,从 this.ShopDel 中移除当前的 itemthis.ShopDel = this.ShopDel.filter((delItem) => delItem.id !== this.item.id);this.checkboxif = false}// 更新总价this.updateTotalPrice()// 更新全选状态this.checkboxif = this.ShopDel.length === this.ShopArray.length}).width(20)// 商品图片Image($r(this.item.img)).width(80)// 商品信息列Column() {// 商品名称Text(this.item.name).width('100%').maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })// 商品属性Text(this.item.attributes).width('100%')// 商品价格Text(`¥${this.item.price}`).width('100%').fontColor('#ff527fb') // 修正颜色值格式}.width(100)// 数量控制区域Column({ space: 5 }) {Text('数量:').fontSize(12).textAlign(TextAlign.Center)Row({ space: 5 }) {Text('-').width(25).height(25).onClick(() => {if (this.item.quantity > 1) {this.item.quantity--this.updateTotalPrice()}})Text(`${this.item.quantity}`).width(25).textAlign(TextAlign.Center)Text('+').width(25).height(25).onClick(() => {this.item.quantity++this.updateTotalPrice()})}.justifyContent(FlexAlign.SpaceAround)}.width(80)// 详情箭头图标Image($r('app.media.black')).width(10).onClick(() => {// TODO 模拟跳转详情页})}.width('100%').height(80).backgroundColor(Color.White).borderRadius(8) // 添加圆角效果.shadow({ color: '#1de9b6', radius: 4 }) // 添加阴影效果}// 提取公共方法来更新总价updateTotalPrice(): void {let total = 0this.ShopDel.forEach((shopItem) => {total += shopItem.price * shopItem.quantity})this.priceSum = total}
}@Component
struct pay {@Consume('mainStarIndex') mainStarIndex: NavPathStack;@Consume ('shopArray') shopArray: Array<ShopClass>@Prop pay: paysbuild() {NavDestination(){Column() {Row(){Text('合计:').fontSize(30).fontWeight(FontWeight.Bold)Text(`¥${this.pay.pay}`).fontSize(30).fontWeight(FontWeight.Bold)}// 支付方式标题Text('选择支付方式').fontSize(20).fontWeight(FontWeight.Bold).padding({ top: 20, bottom: 10 })Divider()// 支付宝支付选项Row({ space: 15 }) {Image($r('app.media.alipay')) // 假设已有支付宝图标资源.width(30).height(30)Text('支付宝').fontSize(16)Checkbox().onChange((value) => {if (value) {// 可以添加相关逻辑,如记录用户选择了支付宝支付console.log("用户选择了支付宝支付")}})}.width('90%').padding({ left: 20, right: 20 }).justifyContent(FlexAlign.SpaceBetween).alignItems(VerticalAlign.Center).margin({ top: 10 })Divider()// 微信支付选项Row({ space: 15 }) {Image($r('app.media.wechatpay')) // 假设已有微信支付图标资源.width(30).height(30)Text('微信').fontSize(16)Checkbox().onChange((value) => {if (value) {// 可以添加相关逻辑,如记录用户选择了微信支付console.log("用户选择了微信支付")}})}.width('90%').padding({ left: 20, right: 20 }).justifyContent(FlexAlign.SpaceBetween).alignItems(VerticalAlign.Center).margin({ top: 10 })Divider()// 提交支付按钮Button('确认支付').onClick(() => {// 跳转·到支付页面this.onClickPay()}).backgroundColor(Color.Orange).width('80%').margin({ top: 30 })}.width('100%').height('100%').justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Center)}}// 支付点击事件处理函数onClickPay() {// 模拟支付成功提示AlertDialog.show({message: '是否支付!',buttons: [{value: '确定',action: () => {// 移除已选商品并返回首页// this.pay.ShopDel = this.ShopDel.filter((delItem) => delItem.id !== item.id);this.shopArray = this.shopArray.filter((item) => !this.pay.shopDel.some(delItem => delItem.id === item.id));this.mainStarIndex.pop(); // 返回首页// 提示支付成功prompt.showToast({ message: '支付成功!' });}},{value: '取消',action: () => {// 取消支付操作}}]});}
}