ArkUI简单外卖页面

前言

这个页面主要是布局,和数据的传递,当然不是标准

UI

1.整体布局为Stack布局,因为底部的那一栏始终要展示在最上面。
2.确定好了布局之后,第一层是商品列表,第二层我做了一个像美团外卖那样的像弹窗,点击底部金额可以调出,点击已选择的商品外的区域或者底部金额就可以让它回去
3.对于商品卡片和已经购买的商品卡片都选择定义组件,列表都选择List组件
4.使用Text和Spen组件配合使部分文字个性化(不太明显,就是货币单位)

JS

1.声明一个Good类为商品类型
2.做了一个假的数据库goods,考虑到子组件也要对【已经购买的商品】列表进行操作,所以将【已经购买的商品】列表声明在全局
3.数组只有删除和新增,都是使用了数组的基本方法push和splice
4.数据传递方面,对于总金额使用了Link,对于Good类加上来Observed,对于其实例加上了ObjectLink,这个是为了数据的双向同步

功能

1.可以在商品列表中将商品加入至购物车
2.点击金额后可以查看【已经购买的商品】列表以及金额
3.在商品列表中将数量减为0后,从【已经购买的商品】列表中移除

BUG

本来有一个bug,index索引来删除【已经购买商品列表】的问题,索引会冲突,所以我用filter用name属性值来过滤掉,然后重新复制给【已经购买的商品列表】。
所有的代码其实都可以分成很多个模块,然后在主页面中进行引入,这样更具有规范性

效果

在这里插入图片描述
在这里插入图片描述

代码

import { curves } from '@kit.ArkUI';
@Observed
class Good{
  //名称
  name:string
  //存货数量
  leftNum:number
  //已卖出多少
  soldNum:number
  //用户已选择多少
  selectedNum:number
  //价格
  price:number
  //折扣
  discount:number
  //图片
  pictureSrc:Resource

  constructor(name:string,leftNum:number,soldNum:number,selectedNum:number,price:number,discount:number,pictureSrc:Resource) {
    this.name = name
    this.leftNum = leftNum
    this.soldNum = soldNum
    this.selectedNum = selectedNum
    this.price = price
    this.discount = discount
    this.pictureSrc = pictureSrc
  }
}
let selectedGoods:Good[] = []

@Entry
@Component
struct TakeOutPage {
  @State message: string = 'Hello World';
  @State isShow: boolean = false
  @State index: number = 20
  //商品列表数据库
  @State goods:Good[] = [
  new Good('珍珠奶茶',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('泷珠奶茶',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('薄荷奶绿',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('桃桃乌龙',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('杨枝甘露',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('柠檬茶',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('百香果',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('草莓啵啵',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('柠檬红茶',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('柠檬绿茶',10,20,0,7.0,0.95,$r('app.media.head')),
  new Good('三拼霸霸奶茶',10,20,0,9.0,0.95,$r('app.media.head')),
  new Good('椰果奶茶',10,20,0,9.0,0.95,$r('app.media.head')),
  new Good('芋圆奶茶',10,20,0,9.0,0.95,$r('app.media.head')),
  new Good('布丁奶茶(大杯)',10,20,0,9.0,0.95,$r('app.media.head')),
  new Good('茉莉奶茶',10,20,0,5.0,0.95,$r('app.media.head')),
]
  @State spend:number = 0
  //生成数据库-已经选好的商品

  private effect:TransitionEffect =
    TransitionEffect.translate({y:150}).animation({curve:curves.springMotion()})
      .combine(TransitionEffect.move(TransitionEdge.BOTTOM))
  build() {

    Column() {
      Stack({
        alignContent: Alignment.Bottom
      })
      {
        //商品列表
        List() {
          ForEach(this.goods,(item:Good,index)=>{
            ListItem(){
              GoodItem({good:item,index:index,spend:this.spend})
            }
          })
          ListItem(){
            Text('到底了···')
              .fontSize(40)
              .height(100)
          }
          .width('90%')
        }
        .width('100%')
        .height('100%')

        //底部外卖栏
        Row() {
          Text('外卖logo')
            .width('20%')
            .height('100%')
            .backgroundColor(Color.Yellow)
            .borderRadius({ topLeft: 10 })
          Text(`${this.spend.toFixed(2)}`)
            .layoutWeight(1)
            .backgroundColor(Color.Gray)
            .textAlign(TextAlign.Center)
            .height('100%')
            .onClick(() => {
              // 点击弹出已选择的商品列表页面
              this.isShow = !this.isShow
            })
          Text('选好了')
            .width('25%')
            .backgroundColor(Color.Orange)
            .height('100%')
            .borderRadius({ topRight: 10 })
            .onClick(() => {
              // 点击去结算页面
            })
        }
        .width('95%')
        .height('10%')
        .zIndex(999)

        //点击底部外卖栏后弹出已经购买的商品列表
        if (this.isShow) {
          Column() {
            Row()
              .width('100%')
              .layoutWeight(1)
              .onClick(() => {
                this.isShow = false
              })
              .backgroundColor(Color.Gray)
              .opacity(0.5)
            Column() {
              List({space:6}) {
                ForEach(selectedGoods,(item:Good,index)=>{
                  ListItem() {
                    //已经购买的商品
                    SelectedGoodItem({selectedGoodItem:item})
                  }.width('90%')
                  .borderRadius(10)
                })

              }
              .alignListItem(ListItemAlign.Center)
              .height('50%')
            }
            .transition(this.effect)
            .backgroundColor(Color.White)

          }
          .width('100%')
          .height('100%')
          .zIndex(this.index)
        }
      }
      .height('100%')
    }
    .height('100%')
    .width('100%')
  }
}
//设置自定义的商品卡片组件
@Component
struct GoodItem {
  //判断是否购买了
  index:number = -1
  @ObjectLink good:Good
  @Link spend:number

  sum(){
    this.spend = selectedGoods.reduce((accumulator:number,item:Good)=>{
      return accumulator+(item.selectedNum*item.price)
    },0)
  }
  build() {
    Row(){
      //picture
      Image(this.good.pictureSrc)
        .width(200)
      //goodInfo
      Column({space:20}){
        //名称
        Text(this.good.name)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
        //已售数量
        Text(`已售${this.good.soldNum}`)
        //价格+购买按钮
        Row(){
          Text(){
            Span('¥')
              .fontSize(14)
            Span(`${this.good.price}`)
              .fontSize(20)
          }
          .width(35)
          .layoutWeight(1)
          //购买按钮
          if (this.good.selectedNum>0){
            //- 数量 +
            Row({space:3}){
              Button('-')
                .onClick(() => {
                  this.good.selectedNum--
                  if(this.good.selectedNum==0){
                    selectedGoods = selectedGoods.filter(selectedGood=>selectedGood.name!==this.good.name)
                  }
                  this.sum()
                })
              Text(`${this.good.selectedNum}`)
                .width(20)
                .textAlign(TextAlign.Center)
              if (this.good.selectedNum == this.good.leftNum) {
                Button('+',{stateEffect:false})
                  .backgroundColor('#ccc')
              }else{
                Button('+')
                  .onClick(() => {
                    this.good.selectedNum++
                    this.sum()
                  })
              }
            }


          }else {
            Button('购买')
              .backgroundColor(Color.Orange)
              .onClick(() => {
                selectedGoods.push(this.good)
                this.good.selectedNum++
                this.sum()
              })
          }
        }
        .width('45%')
        .justifyContent(FlexAlign.SpaceAround)
      }
    }
    .justifyContent(FlexAlign.SpaceAround)
    .width('95%')
    .padding(3)
  }
}
//自定义已经购买的组件
@Component
struct SelectedGoodItem {
  @ObjectLink selectedGoodItem:Good
  build() {
    Row({space:5}){
      //图片
      Image(this.selectedGoodItem.pictureSrc)
        .width('50%')
      // price
      Column({space:10}){
        Text(`${this.selectedGoodItem.name}`)
          .width('100%')
          .fontSize(20)
          .fontWeight(400)

          Text(`数量:${this.selectedGoodItem.selectedNum}`)
            .width('100%')
          Text(`金额:${this.selectedGoodItem.selectedNum*this.selectedGoodItem.price}`)
            .width('100%')
      }
      .alignItems(HorizontalAlign.Center)
      .width('50%')

    }
    .width('100%')
    .height(80)
  }
}

这个是自己手搓的,就是丑了点

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值