ITPub博客

首页 > 移动开发 > HTML5 > 《仿盒马》app开发技术分享-- 商品规格弹窗(11)

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

原创 HTML5 作者:鸿蒙小林 时间:2025-06-26 10:03:16 0 删除 编辑


## **技术栈**


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()

执行代码看看效果


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




来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70046889/viewspace-3088988/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2025-06-26

  • 博文量
    90
  • 访问量
    67502