HarmonyOS NEXT星河版之美团外卖点餐功能实战(下)

文章目录

    • 一、购物车逻辑
      • [1.1 购物车及加减菜](#1.1 购物车及加减菜)
      • [1.2 菜品的加减---方案一](#1.2 菜品的加减---方案一)
      • [1.3 菜品的加减---方案二](#1.3 菜品的加减---方案二)
      • [1.4 购物车View完善](#1.4 购物车View完善)
      • [1.5 清空购物车](#1.5 清空购物车)
      • [1.5 购物车数量和价格](#1.5 购物车数量和价格)
    • 二、小结

一、购物车逻辑

1.1 购物车及加减菜

utils目录下新建CartStore.ets文件,如下:

ts 复制代码
import { FoodItem } from '../models'

// 本地持久化购物车数据
PersistentStorage.persistProp<FoodItem[]>('cartStore', [])

export class CartStore {

  static getCarts() {
    return AppStorage.get<FoodItem[]>('cartStore') || [] as FoodItem[]
  }

  /**
   * 加菜or减菜
   * @param foodItem
   * @param type
   */
  static addOrCutFood(foodItem: FoodItem, type: 'add' | 'cut') {
    const cartList = CartStore.getCarts()
    const item = cartList.find((item) => item.id === foodItem.id)
    // 加菜
    if (type === 'add') {
      if (item) {
        item.count++
      } else {
        foodItem.count = 1
        cartList.unshift(foodItem)
      }
    } else { // 减菜
      if (item && item.count > 0) {
        item.count--
        if (item.count === 0) {
          const index = cartList.findIndex((item) => item.id === foodItem.id)
          cartList.splice(index, 1)
        }
      }
    }
    AppStorage.set<FoodItem[]>('cartStore', [...cartList])
  }
}

1.2 菜品的加减---方案一

实现如下效果,当选择数量大于0时展示-及数量

改造MTAddCutView,如下:

ts 复制代码
import { FoodItem } from '../models'
import { CartStore } from '../utils/CartStore'

@Preview
@Component
export struct MTAddCutView {
  // 当前菜品
  @Require @Prop foodItem: FoodItem = new FoodItem()
  // 购物车数据
  @Consume cartList: FoodItem[]

  // 当前选择数量
  getCount() {
    return this.cartList.find(obj => obj.id === this.foodItem.id)?.count || 0
  }

  build() {
    Row({ space: 8 }) {
      Row() {
        Image($r('app.media.ic_screenshot_line'))
          .width(10)
          .aspectRatio(1)
      }
      .width(16)
      .height(16)
      .justifyContent(FlexAlign.Center)
      .backgroundColor(Color.White)
      .borderRadius(4)
      .border({
        color: $r('app.color.main_color'),
        width: 0.5
      })
      // 如果为0,则取消展示
      .visibility(this.getCount() > 0 ? Visibility.Visible : Visibility.Hidden)
      // 减少菜品
      .onClick(() => {
        CartStore.addOrCutFood(this.foodItem, 'cut')
      })

      Text(this.getCount().toString())
        .fontSize(14)
        .visibility(this.getCount() > 0 ? Visibility.Visible : Visibility.Hidden)

      Row() {
        Image($r('app.media.ic_public_add_filled'))
          .width(10)
          .aspectRatio(1)
      }
      .width(16)
      .height(16)
      .justifyContent(FlexAlign.Center)
      .borderRadius(4)
      .backgroundColor($r('app.color.main_color'))
      // 添加菜品
      .onClick(() => {
        CartStore.addOrCutFood(this.foodItem, 'add')
      })
    }

  }
}

在主页面MeiTuanPage.ets中,通过WatchStorageProp实现数据动态展示:

ts 复制代码
// 方案一:使用StorageProp和Watch实现
@StorageProp('cartStore') @Watch('onCartChange') cartData: FoodItem[] = []
// 购物车数据变化发生回调
onCartChange() {
  this.cartList = CartStore.getCarts()
}

1.3 菜品的加减---方案二

使用事件总线实现事件的发布和订阅。

CartStore.ets中增加事件发布:

ts 复制代码
...
 AppStorage.set<FoodItem[]>('cartStore', [...cartList])
// 方案二:使用事件总线
getContext().eventHub.emit('changeCart')
...

MeiTuanPage.ets中注册订阅:

ts 复制代码
aboutToAppear(): void {
  this.categoryList = mockCategory
  this.cartList = CartStore.getCarts()
  // 方案二:使用事件总线
  getContext().eventHub.on('changeCart', () => {
    this.cartList = CartStore.getCarts()
  })
}

1.4 购物车View完善

购物车展示真实数据及加减菜品:
MTCartView

ts 复制代码
import { FoodItem } from '../models'
import { MTCartItemView } from './MTCartItemView'

@Preview
@Component
export struct MTCartView {
  @Consume cartList: FoodItem[]

  build() {
    Column() {
      Column() {
        // 头部
        Row() {
          Text('购物车')
            .fontSize(14)
          Text('清空购物车')
            .fontColor($r('app.color.search_font_color'))
            .fontSize(12)
        }
        .width('100%')
        .height(48)
        .justifyContent(FlexAlign.SpaceBetween)
        .padding({ left: 15, right: 15 })

        // 购物车列表
        List() {
          ForEach(this.cartList, (item: FoodItem) => {
            ListItem() {
              MTCartItemView({ foodItem: item })
            }
          })
        }
        .divider({ strokeWidth: 1, color: '#e5e5e5', startMargin: 20, endMargin: 20 })
      }
      .backgroundColor(Color.White)
      .padding({
        bottom: 88
      })
      .borderRadius({
        topLeft: 12,
        topRight: 12
      })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.End)
    .backgroundColor('rgba(0,0,0,0.5)')

  }
}

MTCartItemView

ts 复制代码
import { FoodItem } from '../models'
import { MTAddCutView } from './MTAddCutView'

@Preview
@Component
export struct MTCartItemView {
  foodItem: FoodItem = new FoodItem()

  build() {
    Row({ space: 6 }) {
      Image('https://bkimg.cdn.bcebos.com/pic/4d086e061d950a7bc94a331704d162d9f3d3c9e2')
        .width(42)
        .aspectRatio(1)
        .borderRadius(5)
      Column({ space: 3 }) {
        Text(this.foodItem.name)
        Row() {
          Text() {
            Span('¥')
              .fontSize(10)
            Span(this.foodItem.price.toString())
              .fontColor($r('app.color.main_color'))
              .fontSize(14)
              .fontWeight(600)
          }

          MTAddCutView({ foodItem: this.foodItem })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
      }
      .layoutWeight(1)
      .alignItems(HorizontalAlign.Start)
    }
    .height(60)
    .alignItems(VerticalAlign.Top)
    .width('100%')
    .padding({ top: 12, left: 15, right: 15, bottom: 12 })
  }
}

1.5 清空购物车

CartStore.ets中增加清空方法:

ts 复制代码
static clearCart() {
  AppStorage.set('cartStore', [])
  getContext().eventHub.emit('changeCart')
}

购物车View中增加点击事件:

ts 复制代码
...
Text('清空购物车')
  .fontColor($r('app.color.search_font_color'))
  .fontSize(12)
  .onClick(() => {
    CartStore.clearCart()
  })
...

1.5 购物车数量和价格

修改MTBottomView,计算购物车数量和价格:

ts 复制代码
import { FoodItem } from '../models'

@Component
export struct MTBottomView {
  @Consume
  showCart: boolean
  @Consume cartList: FoodItem[]

  // 获取总数量
  getTotalCount() {
    return this.cartList.reduce((pre: number, item: FoodItem) => {
      return pre + item.count
    }, 0)
  }

  // 获取总价格
  getTotalPrice() {
    return this.cartList.reduce((pre: number, item: FoodItem) => {
      return pre + item.count * item.price
    }, 0)
  }

  build() {
    Row() {
      // 小哥+角标
      Badge({ value: this.getTotalCount().toString(), style: { badgeSize: 18 }, position: BadgePosition.Right }) {
        Image($r('app.media.ic_public_cart'))
          .height(69)
          .width(47)
          .position({
            y: -20
          })
      }
      .margin({ left: 28, right: 12 })
      .onClick(() => {
        this.showCart = !this.showCart
      })

      // 金额+描述
      Column() {
        Text() {
          Span('¥')
            .fontColor(Color.White)
            .fontSize(12)
          Span(this.getTotalPrice().toString())
            .fontColor(Color.White)
            .fontSize(25)
        }

        Text('预估另需配送费¥5')
          .fontColor($r('app.color.search_font_color'))
          .fontSize(12)
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      // 去结算
      Text('去结算')
        .width(80)
        .height(50)
        .fontSize(16)
        .backgroundColor($r('app.color.main_color'))
        .textAlign(TextAlign.Center)
        .borderRadius({
          topRight: 25,
          bottomRight: 25
        })
    }
    .height(50)
    .width('88%')
    .margin({ bottom: 20 })
    .backgroundColor(Color.Black)
    .borderRadius(26)
  }
}

二、小结

  • cartStore应用
  • 加减菜逻辑
  • 购物车逻辑
  • 事件总线
相关推荐
- 羊羊不超越 -13 分钟前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
长弓三石2 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
SameX4 小时前
鸿蒙 Next 电商应用安全支付与密码保护实践
前端·harmonyos
SuperHeroWu75 小时前
【HarmonyOS】键盘遮挡输入框UI布局处理
华为·harmonyos·压缩·keyboard·键盘遮挡·抬起
sanzk9 小时前
华为鸿蒙应用开发
华为·harmonyos
SoraLuna13 小时前
「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现
macos·ui·harmonyos
ClkLog-开源埋点用户分析15 小时前
ClkLog企业版(CDP)预售开启,更有鸿蒙SDK前来助力
华为·开源·开源软件·harmonyos
mg66815 小时前
鸿蒙系统的优势 开发 环境搭建 开发小示例
华为·harmonyos
lqj_本人15 小时前
鸿蒙next选择 Flutter 开发跨平台应用的原因
flutter·华为·harmonyos
lqj_本人15 小时前
使用 Flutter 绘制一个棋盘
harmonyos