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

举报
yd_215151764 发表于 2025/06/30 10:22:03 2025/06/30
【摘要】 ## **技术栈**Appgallery connect## **开发准备**上一节我们实现了商品详情页面,并且成功在页面上展示了商品的图片、商品规格、活动详情等信息,要知道同一种商品大多数都是有多种型号跟规格的,所以这一节我们来实现商品的规格弹窗。这节的要点是自定义弹窗的运用。## **功能分析**规格弹窗,我们的数据源需要根据当前商品的specid当条件去规格表里查询对应的数据,需要我们...


## **技术栈**

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=data
      hilog.error(0x0000, 'testTag', `Failed to query data, code: ${this.specList}`);

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

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


@CustomDialog
export  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()
执行代码看看效果

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

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。