HarmonyOS鸿蒙Next《仿盒马》app开发技术分享06-- 首页商品流(端云一体)

HarmonyOS鸿蒙Next《仿盒马》app开发技术分享06-- 首页商品流(端云一体)

开发准备

上一节我们实现了首页banner模块的功能,现在我们的首页还需要添加商品列表,作为一个购物类应用,商品列表是非常重要的一个模块,所以我们尽量把它设计的足够完善,参数能更好的支持我们后期复杂的逻辑,它需要有图片的展示,适配的优惠券列表,限购,立减,划线价等,但他实际的参数还要更多,因为我们的列表是比较紧凑的,更多的数据需要从点击后的商品详情页展示出来。

代码实现

创建商品表

{
  "objectTypeName": "home_product_list",
  "fields": [
    {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},
    {"fieldName": "goods_list_id", "fieldType": "Integer", "notNull": true, "defaultValue": 0},
    {"fieldName": "url", "fieldType": "String"},
    {"fieldName": "name", "fieldType": "Text"},
    {"fieldName": "price", "fieldType": "Double"},
    {"fieldName": "original_price", "fieldType": "Double"},
    {"fieldName": "amount", "fieldType": "Integer"},
    {"fieldName": "text_message", "fieldType": "String"},
    {"fieldName": "parameter", "fieldType": "String"},
    {"fieldName": "delivery_time", "fieldType": "String"},
    {"fieldName": "endTime", "fieldType": "String"},
    {"fieldName": "sales_volume", "fieldType": "Integer"},
    {"fieldName": "space_id", "fieldType": "Integer"},
    {"fieldName": "max_loop_amount", "fieldType": "Integer"},
    {"fieldName": "promotion_spread_price", "fieldType": "Double"},
    {"fieldName": "coupon_id", "fieldType": "Integer"}
  ],
  "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": "home_product_list",
  "objects": [
    {
      "id": 10,
      "goods_list_id": 1,
      "url": "https://img1.baidu.com/it/u=2691558025,827568548&fm=253&fmt=auto&app=120&f=JPEG?w=522&h=500",
      "name": "红颜草莓",
      "price": 10.5,
      "original_price": 18.5,
      "amount": 10,
      "text_message": "特价",
      "parameter": "冷藏",
      "delivery_time": "付款后24小时内发货",
      "endTime": "直降 | 结束时间2025年5月18日 10:00",
      "sales_volume": 9812,
      "space_id": 10,
      "max_loop_amount": 10,
      "promotion_spread_price": 5,
      "coupon_id": 10
    },
    {
      "id": 20,
      "goods_list_id": 1,
      "url": "https://img1.baidu.com/it/u=2791270874,1018261628&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=750",
      "name": "麒麟瓜",
      "price": 2.8,
      "original_price": 5.9,
      "amount": 1,
      "text_message": "当季新品",
      "parameter": "冷藏",
      "delivery_time": "付款后24小时内发货",
      "endTime": "直降 | 结束时间2025年5月18日 10:00",
      "sales_volume": 9812,
      "space_id": 11,
      "max_loop_amount": 10,
      "promotion_spread_price": 0,
      "coupon_id": 10
    }
  ]
}

我们接下来进行数据的查询

@State homeProduct:HomeProductList[]=[]//商品流数据
let databaseZone = cloudDatabase.zone('default');
let home_product=new cloudDatabase.DatabaseQuery(home_product_list);
let list7 = await databaseZone.query(home_product);
let json7 = JSON.stringify(list7)
let data7:HomeProductList[]= JSON.parse(json7)
this.homeProduct=data7

数据查出完成后,完善商品流的页面

import { HomeProductList } from "../entity/home_product_list"

@Component
@Preview
export struct WaterFlowGoods {
  @Link goodsList: Array<HomeProductList>
  @State columns: number = 2
  build() {
    WaterFlow() {
      ForEach(this.goodsList, (item:HomeProductList, index) => {
        FlowItem() {
          Column() {
            Image(item.url)
              .width('100%')
              .aspectRatio(1)
              .objectFit(ImageFit.Cover)
              .borderRadius({topLeft:10,topRight:10})
            Column() {
              Text(item.name)
                .fontSize(16)
                .fontColor('#333')
                .margin({ bottom: 4 })
              Text(item.text_message)
                .fontSize(12)
                .fontColor('#666')
                .margin({ bottom: 8 })
              Text("最高立减"+item.promotion_spread_price)
                .fontSize(12)
                .fontColor('#ffffff')
                .visibility(item.promotion_spread_price>0?Visibility.Visible:Visibility.None)
                .margin({ bottom: 8 })
                .padding({left:5,right:5,top:2,bottom:2})
                .linearGradient({
                  angle:90,
                  colors: [[0xff0000, 0], [0xff6666, 0.2], [0xff6666, 1]]
                })
              Row(){
                Text("限购")
                  .width(40)
                  .fontSize(12)
                  .borderRadius(20)
                  .backgroundColor("#FB424C")
                  .padding(3)
                  .textAlign(TextAlign.Center)
                Text("每人限购"+item.max_loop_amount+"件")
                  .margin({left:5})
                  .fontSize(12)
                  .fontColor("#FB424C")
              }
              .borderRadius(20)
              .padding({top:2,bottom:2,right:10})
              .backgroundColor("#FEE3E3")
              .visibility(item.amount>0?Visibility.Visible:Visibility.None)
              Row () {
                Text(){
                  Span("¥")
                    .fontColor(Color.Red)
                    .fontSize(14)
                  Span(String(item.price))
                    .fontSize(16)
                    .fontColor(Color.Red)
                }
                Text(String(item.original_price))
                  .fontSize(12)
                  .fontColor('#999')
                  .decoration({
                    type: TextDecorationType.LineThrough,
                    color: Color.Gray
                  })
                  .margin({left:10})
                Blank()
                Column() {
                  Image($r('app.media.cart'))
                    .width(20)
                    .height(20)
                }
                .justifyContent(FlexAlign.Center)
                .width(36)
                .height(36)
                .backgroundColor("#ff2bd2fa")
                .borderRadius(18)
              }
              .margin({top:10})
              .width('100%')
              .justifyContent(FlexAlign.SpaceBetween)
            }
            .alignItems(HorizontalAlign.Start)
            .padding(12)
          }
          .backgroundColor(Color.White)
          .borderRadius(12)
          .onClick(() => {})
        }
        .margin({ bottom: 12 })
      }
    }
    .padding(10)
    .columnsTemplate('1fr 1fr')
    .columnsGap(12)
    .onAreaChange((oldVal, newVal) => {
      this.columns = newVal.width > 600 ? 2 : 1
    })
  }
}

然后在首页调用,传入参数

WaterFlowGoods({goodsList:this.homeProduct})

我们执行代码查看效果

可以看到商品列表已经展示出来的,到这里我们就实现了首页商品列表的内容


更多关于HarmonyOS鸿蒙Next《仿盒马》app开发技术分享06-- 首页商品流(端云一体)的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

HarmonyOS Next《仿盒马》首页商品流(端云一体)实现要点:

  1. 使用ArkTS声明式UI开发商品列表布局
  2. 通过@ohos.net.http模块发起云端商品数据请求
  3. 商品数据模型使用基于TypeScript的类定义
  4. 云端协同采用统一数据管理方案,通过云数据库同步商品信息
  5. 列表性能优化:LazyForEach懒加载+商品卡片组件复用
  6. 云函数处理分页逻辑,本地只缓存当前页数据
  7. 数据更新机制:云侧push通知+本地定时轮询结合

更多关于HarmonyOS鸿蒙Next《仿盒马》app开发技术分享06-- 首页商品流(端云一体)的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这是一个很好的HarmonyOS Next商品流实现案例。代码实现方面有几点值得注意:

  1. 数据库设计合理,包含了商品展示所需的核心字段(价格、图片、促销信息等),同时考虑了权限控制。

  2. 使用了WaterFlow组件实现瀑布流布局,通过columnsTemplate控制列数,并响应式地调整布局。

  3. 商品卡片UI细节处理到位:

  • 价格展示使用了Span组合
  • 原价使用了删除线样式
  • 促销标签使用了渐变背景
  1. 端云一体化实现完整:
  • 定义了云数据库对象类型
  • 完成了数据查询和本地状态管理
  • 使用@Link实现父子组件数据传递

建议可以进一步优化:

  1. 添加分页加载逻辑处理大量商品
  2. 实现购物车按钮的点击事件
  3. 考虑商品图片的懒加载
  4. 添加空状态和加载状态处理

整体实现符合HarmonyOS开发规范,展示了端云协同能力,可以作为电商类应用开发的参考范例。

回到顶部