工程目录:
-pages
-MeiTuan
-api 请求
-components 组件
-models 类型
-utils 工具类
-MTIndex.ets(Page) 主页面
MTIndex
- import MTBottom from './components/MTBottom'
- import MTCart from './components/MTCart'
- import MTMain from './components/MTMain'
- import MTTop from './components/MTTop'
- import { FoodItem } from './models'
- import { CartStore } from './utils'
- import { promptAction } from '@kit.ArkUI'
- //主页面:
- @Entry
- @Component
- struct MTIndex {
- @Provide//判断购物车是否出来的一个变量
- showCart:boolean=false
- @Provide//接收CartStore.getCarts()传过来的购物车数据,然后传给MTAddCut,MTCart,MTBottom的consume
- userCart: FoodItem[] = []
- // @StorageProp("user_cart")//创建一个data来拿到utils的数据,watch监听utils的数据变化
- // @Watch("updateCart")
- // data:FoodItem[]=[]
- aboutToAppear(): void {//一打开页面就接收购物车,只执行一次
- this.userCart = CartStore.getCarts()
- getContext().eventHub.on("change_cart",()=>{ //监听线程间通信的更新
- this.userCart = CartStore.getCarts()//重新赋值给userCart
- })
- }
- // updateCart(){//监听到data变化,进行持久化数据的更新
- // this.userCart = CartStore.getCarts()
- // }
- build() {
- Column() {
- Stack({ alignContent: Alignment.Bottom }) {
- Column() {
- MTTop()
- MTMain()
- }
- .height("100%")
- if (this.showCart){ //如果showCart=1,打开购物车MTCart。
- MTCart()
- }
- MTBottom()//底层组件
- }.layoutWeight(1)
- }
- .width('100%')
- .height("100%")
- .backgroundColor($r("app.color.white"))
- }
- }
复制代码 API/index
- import { http } from '@kit.NetworkKit'
- import { promptAction } from '@kit.ArkUI'
- import { Category } from '../models'
- //发情网络请求方法 api/index.ets 使用 http 发送请求,获取数据
- export const getFoodData = async ()=>{
- const res = http.createHttp()
- try {
- const result = await res.request('https://zhousg.atomgit.net/harmonyos-next/takeaway.json')
- return JSON.parse(result.result as string)as Category[]
- }
- catch (error){//出现问题执行:
- promptAction.showToast({message:error.message})
- return Promise.reject(error)//逻辑请求已经出错,不能再继续了
- }
- finally {
- res.destroy()//销毁这个请求
- }
- }
复制代码 MTAddCut
- //夹菜和减菜的组件:
- import { FoodItem } from '../models'
- import { AddCutEnum, CartStore } from '../utils'
- @Component
- struct MTAddCut {
- @Consume
- userCart:FoodItem[]//接收MTIndex的provide传过来的购物车
- fid:number=0//接收MTFoodItem传过来的id来跟购物车判断:在不在购物车里
- item:FoodItem = new FoodItem()//接收MTFoodItem传过来的item
- getCount(){//判断当前的菜品和购物车的关系,只要当前菜品在购物车里,就把<数量>显示
- return this.userCart.find(item => item.id === this.fid)?.count || 0 //去购物车里找有没有和这个id一样的菜品,如果有说明这个菜品在购物车里
- }
- build() {
- Row({ space: 8 }) {
- Row() {
- Image($r('app.media.ic_screenshot_line'))
- .width(10)
- .aspectRatio(1)
- }
- .width(16)
- .aspectRatio(1)
- .justifyContent(FlexAlign.Center)
- .backgroundColor($r("app.color.white"))
- .borderRadius(4)
- .border({ width: 0.5 , color: $r("app.color.main_color")})
- .visibility(this.getCount() ? Visibility.Visible : Visibility.Hidden)//没有就消失,但是会占位
- .onClick(()=>{//减菜
- CartStore.addCutCart(AddCutEnum.CUT,this.item)//把item传给-菜方法
- })
- Text(this.getCount().toString())
- .visibility(this.getCount() ? Visibility.Visible : Visibility.Hidden)//没有就消失,但是会占位
- Row() {
- Image($r('app.media.ic_public_add_filled'))
- .width(10)
- .aspectRatio(1)
- }
- .width(16)
- .aspectRatio(1)
- .justifyContent(FlexAlign.Center)
- .backgroundColor($r("app.color.main_color"))
- .borderRadius(4)
- .onClick(()=>{//+菜
- CartStore.addCutCart(AddCutEnum.ADD,this.item)//把item传给加菜方法
- })
- }
- }
- }
- export default MTAddCut
复制代码 MTBottom
- import { FoodItem } from '../models'
- @Component
- struct MTBottom {
- @Consume//用来接收MTIndex传过来的showCart
- showCart:boolean
- @Consume//接MTIndex传下来的购物车userCart
- userCart:FoodItem[]
- //总件数方法:
- getTotalCount(){
- return this.userCart.reduce((preValue:number,item:FoodItem)=>{
- return preValue + item.count //0+总数
- },0)
- }
- //算总价格:
- getTotalPrice(){
- return this.userCart.reduce((preValue:number,item:FoodItem)=>{
- return preValue + item.count * item.price //0+总数
- },0)
- }
- build() {
- Row(){
- Row(){
- //小哥图像显示:
- Badge({ value: this.getTotalCount().toString(), position: BadgePosition.Right, style:{badgeSize:18}}){
- Image($r("app.media.ic_public_cart"))
- .width(47)
- .height(69)
- .position({y:-20})
- }
- .margin({left:25,right:10})
- .onClick(()=>{//点击小哥,就把showCart取反,来关闭和打开购物车
- this.showCart=!this.showCart
- })
- //显示总费用:
- Column(){
- Text(){
- //span imagespan
- Span("¥")
- .fontSize(12)
- Span(this.getTotalPrice().toString())
- .fontSize(24)
- }
- .fontColor($r("app.color.white"))
- Text("预估另需配送费¥5元")
- .fontColor($r("app.color.search_font_color"))
- .fontSize(14)
- }
- .alignItems(HorizontalAlign.Start)//column的水平轴对齐方式
- .layoutWeight(1)
- //去结算按钮:
- Text("去结算")
- .height(50)
- .textAlign(TextAlign.Center)//字要居中
- .width(80)
- .backgroundColor($r("app.color.main_color"))
- .borderRadius({topRight:25,bottomRight:20})
- }
- .height(50)
- .backgroundColor($r("app.color.bottom_back"))
- .width('100%')
- .borderRadius(25)
- }
- .padding({
- left:20,
- right:20,
- bottom:20,
- })
- .width('100%')
- }
- }
- export default MTBottom
复制代码 MTCart
- import { FoodItem } from '../models'
- import { CartStore } from '../utils'
- import MTCartItem from './MTCartItem'
- //购物车组件:
- @Component
- struct MTCart {
- @Consume
- userCart:FoodItem[]//接收MTIndex的provide传过来的购物车
- build() {
- Column(){
- Column(){
- Row(){
- Text("购物车")
- .fontSize(12)
- Text("清空购物车")
- .fontSize(12)
- .fontColor($r("app.color.search_font_color"))
- .onClick(()=>{
- CartStore.clearCart()
- })
- }
- .height(50)
- .width('100%')
- .justifyContent(FlexAlign.SpaceBetween)//两头对其
- .padding({left:15,right:15})
- //生成n个的菜单项:
- List({space:20}){
- ForEach(this.userCart,(item:FoodItem)=>{
- ListItem(){
- MTCartItem({item:item})
- }}, (item:FoodItem) => item.id.toString() )//第三个参数 防止闪烁
- }.padding({left:15,right:15})
- }
- .borderRadius({ topLeft:16,topRight:16})
- .padding({ bottom:100 })
- .width('100%')
- .backgroundColor($r('app.color.white'))
- }
- .width('100%')
- .height('100%')
- .justifyContent(FlexAlign.End)
- .backgroundColor("rgba(0,0,0,0.5)")//透明的背景色 0.5透明度
- }
- }
- export default MTCart
复制代码 MTCartItem
- import { FoodItem } from '../models'
- import MTAddCut from './MTAddCut'
- @Component
- struct MTCartItem {//购物车里商品抽提成的组件 单个
- item:FoodItem= new FoodItem()//接收MTCart的foreach传过来的item进行单个渲染
- build() {
- Row({space:10}){
- Image(this.item.picture)
- .width(60)
- .aspectRatio(1)
- .borderRadius(8)
- Column(){
- Text(this.item.name)
- .fontSize(14)
- .textOverflow({
- overflow:TextOverflow.Ellipsis
- })
- Row(){
- Text(){
- Span("¥")
- .fontSize(10)
- Span(this.item.price.toString())//价格
- .fontSize(20)
- .fontWeight(600)
- }
- .fontColor($r('app.color.font_main_color'))
- MTAddCut({fid:this.item.id,item:this.item})
- }
- .width('100%')
- .justifyContent(FlexAlign.SpaceBetween)
- }
- .layoutWeight(1)
- .alignItems(HorizontalAlign.Start)//column的副轴对齐方式
- }
- .width('100%')
- }
- }
- export default MTCartItem
复制代码 MTFoodItem
- import { FoodItem } from '../models'
- import MTAddCut from './MTAddCut'
- @Component
- struct MTFoodItem { //菜单栏的商品抽提成的组件 单个
- item :FoodItem = new FoodItem()//接收main的 ForEach传过来的数据并渲染
- build() {
- Row() {
- Image(this.item.picture)
- .width(90)
- .aspectRatio(1)
- Column({ space: 5 }) {
- Text(this.item.name)
- .textOverflow({
- overflow: TextOverflow.Ellipsis,
- })
- .maxLines(2)
- .fontWeight(600)
- Text(this.item.description)
- .textOverflow({
- overflow: TextOverflow.Ellipsis,
- })
- .maxLines(1)
- .fontSize(12)
- .fontColor($r("app.color.food_item_second_color"))
- ForEach(this.item.food_tag_list,(str:string)=>{
- Text(str)
- .fontSize(10)
- .backgroundColor($r("app.color.food_item_label_color"))
- .fontColor($r("app.color.font_main_color"))
- .padding({ top: 2, bottom: 2, right: 5, left: 5 })
- .borderRadius(2)
- })
- Text() {
- Span('月销售'+this.item.month_saled)
- Span(' ')
- Span(this.item.like_ratio_desc)
- }
- .fontSize(12)
- .fontColor($r("app.color.black"))
- Row() {
- Text() {
- Span('¥ ')
- .fontColor($r("app.color.font_main_color"))
- .fontSize(10)
- Span(this.item.price.toString())
- .fontColor($r("app.color.font_main_color"))
- .fontWeight(FontWeight.Bold)
- }
- MTAddCut({ fid:this.item.id ,item:this.item})//把id传给MTAddCut
- }
- .justifyContent(FlexAlign.SpaceBetween)
- .width('100%')
- }
- .layoutWeight(1)
- .alignItems(HorizontalAlign.Start)
- .padding({ left: 10, right: 10 })
- }
- .padding(10)
- .alignItems(VerticalAlign.Top)
- }
- }
- export default MTFoodItem
复制代码 MTMain
- import { getFoodData } from '../API'
- import { Category, FoodItem } from '../models'
- import MTFoodItem from './MTFoodItem'
- @Component
- struct MTMain {
- @State
- list:Category[]=[]
- // @State
- // list:string[]=["一人套餐","特色烧烤","杂粮主食"]
- @State
- activeIndex:number = 0//激活项的点菜类型索引
- aboutToAppear(): void {
- this.getData()
- }
- //获取数据的方法:
- async getData(){
- this.list = await getFoodData()//调用网络请求方法,把数据传给list
- }
- build() {
- Row(){
- //左侧分类:
- Column(){
- ForEach(this.list,(item:Category,index:number)=>{
- Text(item.name)
- .height(50)
- .width('100%')
- .fontSize(14)
- .backgroundColor(this.activeIndex === index?$r("app.color.white"):$r("app.color.left_back_color"))//选中的话显示白色,不选中默认色
- .textAlign(TextAlign.Center)
- .onClick(()=>{
- this.activeIndex=index//点到谁就把它的索引给激活项索引
- })
- })
- }
- .height('100%')
- .backgroundColor($r("app.color.left_back_color"))
- .width(90)
- //右侧食物列表:
- List(){
- ForEach( this.list[this.activeIndex]?.foods || [] ,(item:FoodItem)=>{
- ListItem(){
- MTFoodItem({item:item})//把数据传给MTFoodItem去渲染一个一个的菜品
- }
- })
- }
- .height('100%')
- .layoutWeight(1)
- .padding({bottom:120})
- }
- .width('100%')
- }
- }
- export default MTMain
复制代码 MTTop
- @Component
- struct MTTop {
- @Builder
- NavItem(active: boolean, title: string, subTitle?: string) {
- Column() {
- Text() {
- Span(title)
- if (subTitle) {
- Span(' ' + subTitle)
- .fontSize(10)
- .fontColor(active ? $r("app.color.black") : $r("app.color.un_select_color"))
- }
- }.layoutWeight(1)
- .fontColor(active ? $r("app.color.black") : $r("app.color.un_select_color"))
- .fontWeight(active ? FontWeight.Bold : FontWeight.Normal)
- Text()
- .height(1)
- .width(20)
- .margin({ left: 6 })
- .backgroundColor(active ? $r("app.color.select_border_color") : 'transparent')
- }
- .width(73)
- .alignItems(HorizontalAlign.Start)
- .padding({ top: 3 })
- }
- build() {
- Row() {
- this.NavItem(true, '点菜')
- this.NavItem(false, '评价', '1796')
- this.NavItem(false, '商家')
- Row() {
- Image($r('app.media.ic_public_search'))
- .width(14)
- .aspectRatio(1)
- .fillColor($r("app.color.search_font_color"))
- Text('请输入菜品名称')
- .fontSize(12)
- .fontColor($r("app.color.search_back_color"))
- }
- .backgroundColor($r("app.color.search_back_color"))
- .height(25)
- .borderRadius(13)
- .padding({ left: 5, right: 5 })
- .layoutWeight(1)
- }
- .padding({ left: 15, right: 15 })
- .height(40)
- .border({ width: { bottom: 0.5 }, color: $r("app.color.top_border_color") })
- }
- }
- export default MTTop
复制代码 model/index
- //数据类型:
- //1.菜品类型:
- export class FoodItem {
- id: number = 0
- name: string = ""
- like_ratio_desc: string = ""//好评率
- food_tag_list: string[] = []//点评网友推荐
- price: number = 0//价格
- picture: string = ""
- description: string = ""//描述
- tag: string = ""
- month_saled: number = 0//月销量
- count: number = 0
- }
- //2.分类类型:
- export class Category {
- tag: string = ""
- name: string =""
- foods: FoodItem[] = []
- }
复制代码 utils/index
- import { it } from '@ohos/hypium'
- import { FoodItem } from '../models'
- //控制购物车的读取
- //单例 只有一个实例
- PersistentStorage.persistProp("user_cart",[]) //声明了一个持久化的数据叫user_cart,初始值为空数组
- export class CartStore {
- //1.获取购物车方法:
- static getCarts (): FoodItem[] {
- return AppStorage.get("user_cart") || [] as FoodItem[] //如果拿不到,给上一个空数组
- }
- //2.加菜和减菜的方法:
- static addCutCart(type:AddCutEnum ,item:FoodItem){
- const list = CartStore.getCarts()//拿到持久化购物车给list
- const findFood = list.find(obj => obj.id === item.id)
- if (type===AddCutEnum.ADD) {
- //加菜:这个菜在购物车存在与否?
- if (findFood) {//意味着你点击的菜购物车里已经有了
- findFood.count++
- }
- else {//你的购物车里没有这个菜:给购物车加入这个菜,数量为1:
- list.unshift(item)//把这个菜加到头部
- item.count=1
- }
- }
- else if (type===AddCutEnum.CUT){
- //减菜:
- if (findFood && findFood.count>0 ) {//意味着你点击的菜 购物车里已经有了
- findFood.count--
- if (findFood.count === 0) {//减完了,得把这个菜删除购物车
- let index = list.findIndex(obj=>obj.id === findFood.id)
- list.splice(index,1)
- }
- }
- }
- //最后要把这个list数据更新到持久化
- AppStorage.set("user_cart",[...list])//写入持久化,把list进行了一次拷贝
- //写入的时候,如果发现对象的地址一致,就不写入
- //第二种方法:事件总线
- //线程内事件总线,线程间事件总线,进程间事件总线
- getContext().eventHub.emit("change_cart")//触发更新购物车事件
- }
- //3.清空购物车方法:
- static clearCart(){
- AppStorage.set("user_cart",[])//把"user_cart"设成空数组
- getContext().eventHub.emit("change_cart")//触发更新购物车事件
- }
- }
- //写成枚举给addCutCart用
- export enum AddCutEnum{
- ADD,
- CUT
- }
复制代码 效果:
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |