写点什么

《仿盒马》app 开发技术分享 -- 商品规格弹窗(11)

作者:鸿蒙小林
  • 2025-06-30
    浙江
  • 本文字数:3330 字

    阅读完需:约 11 分钟

技术栈

Appgallery connect

开发准备

上一节我们实现了商品详情页面,并且成功在页面上展示了商品的图片、商品规格、活动详情等信息,要知道同一种商品大多数都是有多种型号跟规格的,所以这一节我们来实现商品的规格弹窗。这节的要点是自定义弹窗的运用。

功能分析

规格弹窗,我们的数据源需要根据当前商品的 specid 当条件去规格表里查询对应的数据,需要我们针对 id 做一个查询。


弹窗的唤起逻辑是我们点击规格列表时,以及点击加入购物车时,这时候我们再去选择对应的规格

代码实现

先创建对应的表结构{"objectTypeName": "product_details_spec","fields": [{"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},{"fieldName": "spec_id", "fieldType": "Integer", "notNull": true, "defaultValue": 0},{"fieldName": "name", "fieldType": "String"},{"fieldName": "url", "fieldType": "String"},{"fieldName": "price", "fieldType": "Double"},{"fieldName": "original_price", "fieldType": "Double"},{"fieldName": "maxLoopAmount", "fieldType": "Integer"},{"fieldName": "loopAmount", "fieldType": "Integer"},{"fieldName": "coupon", "fieldType": "Double"}],"indexes": [{"indexName": "field1IndexId", "indexList": [{"fieldName":"id","sortType":"ASC"}]}],"permissions": [{"role": "World", "rights": ["Read"]},{"role": "Authenticated", "rights": ["Read", "Upsert"]},{"role": "Creator", "rights": ["Read", "Upsert", "Delete"]},{"role": "Administrator", "rights": ["Read", "Upsert", "Delete"]}]}然后我们填充几条数据进去,可以暂时不用管一致性{"cloudDBZoneName": "default","objectTypeName": "product_details_spec","objects": [{"id": 10,"spec_id": 10,"name": "红颜草莓","url": "在线图片链接","price": 23,"original_price": 27,"maxLoopAmount": 8,"loopAmount": 10,"coupon": 10},{"id": 20,"spec_id": 10,"name": "蓝颜草莓","url": "在线图片链接","price": 70,"original_price": 99,"maxLoopAmount": 20,"loopAmount": 20,"coupon": 20},{"id": 30,"spec_id": 10,"name": "紫颜草莓","url": "在线图片链接","price": 19,"original_price": 33,"maxLoopAmount": 10,"loopAmount": 10,"coupon": 10.5},{"id": 60,"spec_id": 11,"name": "麒麟","url": "在线图片链接","price": 20.5,"original_price": 20.5,"maxLoopAmount": 20,"loopAmount": 20,"coupon": 20.5},{"id": 70,"spec_id": 11,"name": "甜王","url": "在线图片链接","price": 10.5,"original_price": 10.5,"maxLoopAmount": 10,"loopAmount": 10,"coupon": 10.5},{"id": 80,"spec_id": 11,"name": "早春红玉","url": "在线图片链接","price": 20.5,"original_price": 20.5,"maxLoopAmount": 20,"loopAmount": 20,"coupon": 20.5},{"id": 90,"spec_id": 11,"name": "黑美人","url": "在线图片链接","price": 10.5,"original_price": 10.5,"maxLoopAmount": 10,"loopAmount": 10,"coupon": 10.5}]}


紧接着我们根据详情页的 id 查询出对应的规格集合


let databaseZone = cloudDatabase.zone('default');let condition = new cloudDatabase.DatabaseQuery(product_details_spec);condition.equalTo("spec_id",this.productParams.spec_id)let listData = await databaseZone.query(condition);let json = JSON.stringify(listData)let data:ProductDetailsSpec[]= JSON.parse(json)this.specList=datahilog.error(0x0000, 'testTag', Failed to query data, code: ${this.specList});


然后创建自定义弹窗,把查询的数据传入进去进行页面的绘制


import { ProductDetailsSpec } from "../entity/ProductDetailsSpec";import showToast from "../utils/ToastUtils";


@CustomDialogexport default struct SpecDialog{@State specList:ProductDetailsSpec[]=[];


controller: CustomDialogController@State productSpec?:ProductDetailsSpec|null=null@State @Watch("onChange") checkIndex:number=0@State selectedItem:number = -1; // 当前选中的位置 @State addNumber:number=1//商品默认添加数量 aboutToAppear(): void {this.productSpec=this.specList[this.checkIndex]}


onChange(){this.productSpec=this.specList[this.checkIndex]}


build(){Column({space:10}){Row(){Image(this.productSpec?.url).height(100).width(100)


  Column(){    Row(){      Text(){
Span("¥") .fontSize(16) .fontColor(Color.Red) Span(this.productSpec?.price+"") .fontSize(22) .fontWeight(FontWeight.Bold) .padding({top:10}) .fontColor(Color.Red)

} .margin({left:15})
Text("¥"+String(this.productSpec?.original_price)) .fontSize(16) .fontColor('#999') .decoration({ type: TextDecorationType.LineThrough, color: Color.Gray }) .margin({left:10}) } } Blank() Image($r('app.media.spec_dialog_close')) .height(20) .width(20)}.alignItems(VerticalAlign.Top).width('100%').justifyContent(FlexAlign.SpaceBetween)
Divider().width('90%').height(0.5)

List({space:10}){ ForEach(this.specList,(item:ProductDetailsSpec,index:number)=>{ ListItem(){ Text(item.name) .backgroundColor(Color.Green) .padding(3) .borderRadius(5) .backgroundColor(this.checkIndex==index?"#FCDB29":Color.Grey) .fontColor(this.checkIndex==index?"#000000":Color.White) .onClick(()=>{ this.checkIndex=index }) } })}.height(50).listDirection(Axis.Horizontal)
Row(){ Text("购买数量") .fontSize(16) .fontColor(Color.Black)
Blank()
Text(" - ") .textAlign(TextAlign.Center) .border({width:0.5,color:Color.Gray}) .fontSize(14) .height(20) .padding({left:7,right:7}) .fontColor(Color.Black) .onClick(()=>{ if (this.addNumber==1) { showToast("已经是最小数量了~") }else { this.addNumber-- } }) .borderRadius({topLeft:5,bottomLeft:5})
Text(this.addNumber+"") .textAlign(TextAlign.Center) .fontColor(Color.Black) .fontSize(14) .height(20) .padding({left:20,right:20}) .border({width:0.5,color:Color.Gray})

Text(" + ") .textAlign(TextAlign.Center) .fontColor(Color.Black) .fontSize(14) .height(20) .padding({left:7,right:7}) .onClick(()=>{ this.addNumber++ }) .border({width:0.5,color:Color.Gray}) .borderRadius({topRight:5,bottomRight:5})
}.width('100%').justifyContent(FlexAlign.SpaceBetween)

Row(){ Text("加入购物车") .width('70%') .borderRadius(30) .textAlign(TextAlign.Center) .fontColor(Color.Black) .margin({top:70}) .height(40) .fontSize(18) .fontWeight(FontWeight.Bold) .backgroundColor("#FCDB29")}.width('100%').justifyContent(FlexAlign.Center)
复制代码


}.alignItems(HorizontalAlign.Start).backgroundColor(Color.White).justifyContent(FlexAlign.Start).padding(15).height(400).width('100%')}}创建完成之后我们在详情页面初始化弹窗,把查询的数据传进去 specDialogController:CustomDialogController=new CustomDialogController({builder:SpecDialog({specList:this.specList}),alignment: DialogAlignment.Bottom,customStyle:true})调用弹窗


this.specDialogController.open()执行代码看看效果


到这里我们的弹窗就实现了

用户头像

鸿蒙小林

关注

还未添加个人签名 2025-06-20 加入

还未添加个人简介

评论

发布
暂无评论
《仿盒马》app开发技术分享-- 商品规格弹窗(11)_鸿蒙小林_InfoQ写作社区