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

news2024/12/23 17:11:49

文章目录

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

一、购物车逻辑

1.1 购物车及加减菜

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

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,如下:

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实现数据动态展示:

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

1.3 菜品的加减—方案二

使用事件总线实现事件的发布和订阅。
CartStore.ets中增加事件发布:

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

MeiTuanPage.ets中注册订阅:

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

1.4 购物车View完善

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

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

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中增加清空方法:

static clearCart() {
  AppStorage.set('cartStore', [])
  getContext().eventHub.emit('changeCart')
}

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

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

1.5 购物车数量和价格

在这里插入图片描述

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

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应用
  • 加减菜逻辑
  • 购物车逻辑
  • 事件总线

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1662357.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dubbo2.x迁移3.x过程及原理

Dubbo2.x迁移3.x过程及原理 1.Dubbo2.x迁移3.x1.1 快速升级步骤1.2 Provider 端升级过程详解1.2.1 双注册带来的资源消耗 1.3 Consumer 端升级过程1.3.1 APPLICATION_FIRST策略1.3.2 双订阅带来的资源消耗1.3.3 消费端更细粒度的控制 1.4 迁移状态的收敛1.4.1 不同的升级策略影…

一键局域网共享工具

一键局域网共享工具&#xff1a;实现文件快速共享的新选择 在数字化时代&#xff0c;文件共享已成为我们日常工作和生活中的重要需求。无论是在家庭还是在办公环境中&#xff0c;我们经常需要在不同的设备之间传输文件。为了满足这一需求&#xff0c;一键局域网共享工具应运而…

Leetcode—239. 滑动窗口最大值【困难】

2024每日刷题&#xff08;132&#xff09; Leetcode—239. 滑动窗口最大值 算法思想 用vector会超时的&#xff0c;用deque最好&#xff01; 实现代码 class Solution { public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {deque<int> …

AI绘画的基本原理是什么?

目录 一、AI绘画的基本原理是什么&#xff1f; 二、Python中有几个库可以用于AI绘画&#xff1f; 三、OpenCV画一个人形 四、AI画的红苹果 一、AI绘画的基本原理是什么&#xff1f; AI绘画的原理基于机器学习和人工智能技术&#xff0c;通过这些技术模型能够理解文本描述并…

物联网D3——按键控制LED、光敏传感蜂鸣器

按键控制LED 按键抖动&#xff0c;电平发生变化&#xff0c;可用延时函数抵消按键抖动对系统的影响 传感器电路图 按键电路图 c语言对应类型 “_t”后缀表示使用typedef重命名的数据类型 枚举类型 #include<iostream> using namespace std; //定义枚举类型 typedef enu…

Ranger 面试题及答案整理,最新面试题

Ranger 的安全模型是如何设计的&#xff1f; Ranger的安全模型设计主要基于访问控制和安全策略的管理&#xff0c;它通过以下几个关键组件实现&#xff1a; 1、策略管理&#xff1a; Ranger 提供了一个中央管理平台&#xff0c;用于定义、更新和管理安全策略。这些策略根据资…

单链表经典oj题(2)

前言 这次将要把剩下的oj题将以图解和自己的理解把它讲解完&#xff0c;希望对大家有所帮助&#xff0c;这次的讲解也是干货 第一题 21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; ok这次就简单点&#xff0c;大家自己去看题目了 将两个升序链表合并为一个…

如何使用 ERNIE 千帆大模型基于 Flask 搭建智能英语能力评测对话网页机器人(详细教程)

ERNIE 千帆大模型 ERNIE-3.5是一款基于深度学习技术构建的高效语言模型&#xff0c;其强大的综合能力使其在中文应用方面表现出色。相较于其他模型&#xff0c;如微软的ChatGPT&#xff0c;ERNIE-3.5不仅综合能力更强&#xff0c;而且在训练与推理效率上也更高。这使得ERNIE-3…

玩游戏专用远程控制软件

玩游戏专用远程控制软件&#xff1a;实现远程游戏的新体验 随着网络技术的不断发展和创新&#xff0c;远程控制软件已经逐渐渗透到我们生活的方方面面&#xff0c;尤其是在游戏领域。玩游戏专用远程控制软件&#xff0c;作为这一趋势下的产物&#xff0c;为玩家提供了全新的游…

Ubuntu安装库 版本问题,错误E: Unable to correct problems, you have held broken packages.

一、问题描述&#xff1a; Ubuntu系统指令安装 : sudo apt install -y build-essential提示&#xff1a; Reading package lists... Done Building dependency tree... Done Reading state information... Done Some packages could not be installed. This may mean that y…

win10 miniconda始终无法在指定的位置创建虚拟环境,原来是管理员权限问题

当我想用conda创建虚拟环境时 envs_dirs: F:\miniconda3\envsC:\Users\fengx.conda\envsC:\Users\fengx\AppData\Local\conda\conda\envs 创建的虚拟环境始终在C:\Users\fengx.conda\envs\xxxx这个位置下&#xff0c; 我已经明显指定了位置是在F:\miniconda3\envs下&#xff…

Java面试——MyBatis

优质博文&#xff1a;IT-BLOG-CN 一、MyBatis 与 JDBC 的区别 【1】JDBC 是 Java 提供操作数据库的 API&#xff1b;MyBatis 是一个持久层 ORM 框架&#xff0c;底层是对 JDBC 的封装。 【2】使用 JDBC 需要连接数据库&#xff0c;注册驱动和数据库信息工作量大&#xff0c;每…

【Java难点】多线程-高级

悲观锁和乐观锁 悲观锁 synchronized关键字和Lock的实现类都是悲观锁。 它很悲观&#xff0c;认为自己在使用数据的时候一定有别的线程来修改数据&#xff0c;因此在获取数据的时候会一不做二不休的先加锁&#xff0c;确保数据不会被别的线程修改。 适合写操作多的场景&…

无线收发模块家电控制实验

zkhengyang可申请加入数字音频系统研究开发交流答疑群(课题组) 当然可以先用固定电平发送&#xff0c;可以实现&#xff0c;0/1数据发送&#xff0c;接收。 可以使用51单片机来编码码&#xff0c;解码&#xff0c;或者任何MCU或者SOC&#xff0c;DSP&#xff0c;FPGA。 注意G…

【全开源】酷柚易汛ERP 源码部署/售后更新/上线维护

一款基于FastAdminThinkPHPLayui开发的ERP管理系统&#xff0c;帮助中小企业实现ERP管理规范化&#xff0c;此系统能为你解决五大方面的经营问题&#xff1a;1.采购管理 2.销售管理 3.仓库管理 4.资金管理 5.生产管理&#xff0c;适用于&#xff1a;服装鞋帽、化妆品、机械机电…

QX---mini51单片机学习---(6)独立键盘

目录 1键盘简绍 2按键的工作原理 3键盘类型 4独立键盘与矩阵键盘的特点 5本节相关原理图 6按键特性 7实践 1键盘简绍 2按键的工作原理 内部使用轻触按键&#xff0c;常态按下按键触点才闭合 3键盘类型 编码键盘与非编码键盘 4独立键盘与矩阵键盘的特点 5本节相关原理…

Python 全栈系列242 踩坑记录:租用算力机完成任务

说明 记一次用算力机分布式完成任务的坑。 内容 1 背景 很早的时候&#xff0c;做了一个实体识别模型。这个模型可以识别常见的PER、ORG、LOC和TIME几种类型实体。 后来&#xff0c;因为主要只用来做PER、ORG的识别&#xff0c;于是我根据业务数据&#xff0c;重新训练了模…

一个可以同时使用USB和WIFI传输文件到电脑的软件

双轨快传 结合USB2.0和WIFI6技术&#xff0c;通过1000Mbps网口实现每秒高达150MB的传输速率&#xff08;理论上可达40MB/s通过USB和110MB/s通过WIFI&#xff09;。 使用 模式 支持普通模式和Root模式&#xff0c;Root模式可访问~/Android/data/与/data/data/目录下的文件。 …

web安全之登录框渗透骚姿势,新思路

不管漏洞挖掘还是挖SRC&#xff0c;登录框都是重点关注对象&#xff0c;什么漏洞都有可能出现&#xff0c; 本篇文章做个总结&#xff0c;后面发现新思路后会继续更新 万能密码 or 弱口令 SQL注入 水平越权 垂直越权 逻辑漏洞 短信轰炸 邮箱轰炸 信息泄露 验证码DOS XSS万能密…

搭建本地yum仓库

步骤 找个地方存你的rpm包 #我创建了一个rpm文件夹存放我的rpm包 makdir -p /opt/repo/rpmcreaterepo 这个很重要&#xff0c;一定要安装 # 我的能连外网&#xff0c;所以直接yum安装&#xff0c;你的自己想办法 yum install createrepo -y创建repodata 安装了createrepo后…