OpenHarmony 实战开发——分布式购物车案例展示~

简介

分布式购物车demo 模拟的是我们购物时参加满减活动,进行拼单的场景;实现两人拼单时,其他一人添加商品到购物车,另外一人购物车列表能同步更新,且在购物车列表页面结算时,某一人结算对方也能实时知道结算金额和优惠金额。整个操作效果分为3个小动画,

  • 拉起对方用户

  • 添加商品到购物车列表

  • 购物车列表勾选

  • demo效果(HH-SCDAYU200)

工程目录

完整的项目结构目录如下

├─entry\\src\\main
│          │  config.json  应用配置文件
│          │ 
│          ├─ets
│          │  └─MainAbility
│          │      │  app.ets  ets应用程序主入口
│          │      │ 
│          │      ├─model
│          │      │      ArsData.ets     // 初始化我的页面数据
│          │      │      CommonLog.ets   // 日志类
│          │      │      GoodsData.ets   // 初始化商品信息数据类
│          │      │      MenuData.ets    // 初始化我的页面数据类
│          │      │      RemoteDeviceManager.ets  // 分布式拉起设备管理类
│          │      │      ShoppingCartDistributedData.ets  // 加入购物车分布式数据库
│          │      │      TotalSelectedDistributedData.ets // 结算购物车分布式数据库
│          │      │ 
│          │      └─pages
│          │              DetailPage.ets   // 商品详情页面
│          │              HomePage.ets     // 应用首页
│          │              MyPage.ets       // 我的页面
│          │              ShoppingCartListPage.ets  // 购物车列表页面
│     └─resources // 静态资源目录
│         ├─base
│         │  ├─element
│         │  ├─graphic
│         │  ├─layout
│         │  ├─media // 存放媒体资源
│         │  └─profile
│         └─rawfile

开发步骤

1. 新建OpenHarmony ETS项目

在DevEco Studio中点击File -> New Project ->[Standard]Empty Ability->Next,Language 选择ETS语言,最后点击Finish即创建成功。

2. 编写商品展示主页面

效果图如上可以分为两部分

2.1商品列表展示

1)首先在@entry组件入口build()中使用 Tabs作为容器,达到排行榜和推荐翻页的效果;

2)再通过 List 包裹 Row 布局依次写入 Column 包裹的三个 Text 组件和 Image 组件;

3)并通过 Navigator 组件实现点击商品跳转到商品详细页功能,页面跳转过程使用 pageTransition 转场动画

Tabs() {
       TabContent() {
         GoodsList({ goodsItems: this.goodsItems});
       }
       .tabBar("畅销榜")
       .backgroundColor(Color.White)

       TabContent() {
         GoodsList({ goodsItems: this.goodsItems});
       }
       .tabBar("推荐")
       .backgroundColor(Color.White)
     }
      Navigator({ target: 'pages/DetailPage' }) {
       Row({ space: '40lpx' }) {
         Column() {
           Text(this.goodsItem.title)
             .fontSize('28lpx')
           Text(this.goodsItem.content)
             .fontSize('20lpx')
           Text('¥' + this.goodsItem.price)
             .fontSize('28lpx')
             .fontColor(Color.Red)
         }
         .height('160lpx')
         .width('50%')
         .margin({ left: '20lpx' })
         .alignItems(HorizontalAlign.Start)

         Image(this.goodsItem.imgSrc)
           .objectFit(ImageFit.ScaleDown)
           .height('160lpx')
           .width('40%')
           .renderMode(ImageRenderMode.Original)
           .margin({ right: '20lpx', left: '20lpx' })

       }
       .height('180lpx')
       .alignItems(VerticalAlign.Center)
       .backgroundColor(Color.White)
     }
     .params({ goodsItem: this.goodsItem ,ShoppingCartsGoods:this.ShoppingCartsGoods})
     .margin({ left: '40lpx' })
   }
   // 转场动画使用系统提供的多种默认效果(平移、缩放、透明度等)
 pageTransition() {
   PageTransitionEnter({ duration: 1000 })
     .slide(SlideEffect.Left)
   PageTransitionExit({ duration: 1000  })
     .slide(SlideEffect.Right)
 }
2.2底部导航栏

1)通过 Row 包裹三个 Image 组件,并添加onClick 点击事件,修改 @Consume 修饰的变量,从而改变 @Provide 装饰的变量,再通过条件渲染展示不同的页面内容;

Flex() {
        Image(this.iconPath[0])
          .objectFit(ImageFit.Cover)
          .height('60lpx')
          .width('60lpx')
          .margin({left:'50lpx',right:'40lpx'})
          .onClick(() => {
            this.iconPath[0] = this.iconPathSelectsTmp[0]
            this.iconPath[1] = this.iconPathTmp[1]
            this.iconPath[2] = this.iconPathTmp[2]
            this.currentPage = 1
          })
        Image(this.iconPath[1])
          .objectFit(ImageFit.Cover)
          .height('60lpx')
          .width('60lpx')
          .margin({left:'40lpx',right:'40lpx'})
          .onClick(() => {
            this.iconPath[0] = this.iconPathTmp[0]
            this.iconPath[1] = this.iconPathSelectsTmp[1]
            this.iconPath[2] = this.iconPathTmp[2]
            this.currentPage = 2
            this.remoteData.putData("shopping_cart", this.ShoppingCartsGoods)
          })
        Image(this.iconPath[2])
          .objectFit(ImageFit.Cover)
          .height('60lpx')
          .width('60lpx')
          .margin({left:'40lpx',right:'50lpx'})
          .onClick(() => {
            this.iconPath[0] = this.iconPathTmp[0]
            this.iconPath[1] = this.iconPathTmp[1]
            this.iconPath[2] = this.iconPathSelectsTmp[2]
            this.currentPage = 3
          })
      }
    .margin({top:'20lpx'})
    }
      
      Column() {
          if (this.currentPage == 1) {
            Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.End }) {
              Image($r("app.media.icon_share"))
                .objectFit(ImageFit.Cover)
                .height('60lpx')
                .width('60lpx')
            }
            .width("100%")
            .margin({ top: '20lpx', right: '50lpx' })
            .onClick(() => {
              this.playerDialog.open()
            })

            GoodsHome({ goodsItems: this.goodsItems})
          }
          else if (this.currentPage == 3) {
            //我的
            MyInfo()
          }
        }
3. 编写商品详细页面
3.1顶部滑动组件

1)滑动容器,提供切换子组件显示的能力;

Swiper() {
        ForEach(this.detailImages, item => {
          Image(item)
            .height('400lpx')
            .width('100%')
        })
      }
      .index(0)
      .autoPlay(true)
      .interval(3000)
      .indicator(true)
      .loop(true)
      .height('440lpx')
      .width('100%')
3.2 自定义弹框

1)通过 @CustomDialog 装饰器来创建自定义弹窗,使用方式可参考 自定义弹窗

2)规则弹窗效果如下,弹窗组成由两个 Text 和两个 Button 竖向排列组成;

所有我们可以在build()下使用 Flex 容器来包裹,组件代码如下:

@CustomDialog
struct CustomDialogExample {
  controller: CustomDialogController
  cancel: () => void
  confirm: () => void
  ShoppingCartsGoods: any[]

  build() {
    Flex() {
      Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
        Text('加入购物车成功')
          .fontColor("#000000")
          .fontSize('40lpx')
          .margin({ top: '20lpx', bottom: "20lpx" })

        Flex({ justifyContent: FlexAlign.SpaceAround }) {
          Button('取消')
            .onClick(() => {
              this.controller.close()
              this.cancel()
            }).backgroundColor(0xffffff).fontColor(Color.Black)
          Button('确定')
            .onClick(() => {
              this.controller.close()
              this.confirm()
            }).backgroundColor(0xffffff).fontColor(Color.Red)
        }.margin({ bottom: "20lpx" })
      }
    }
    .height('200lpx')
  }
}

3)在@entry创建CustomDialogController对象并传入弹窗所需参数,后面可通过该对象open()和close()方法进行打开和关闭弹窗;

dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomDialogExample({
      cancel: this.onCancel,
      confirm: this.onAccept,
      ShoppingCartsGoods: this.ShoppingCartsGoods
    }),
    cancel: this.existApp,
    autoCancel: true
  })
  onCancel() {
    CommonLog.info('Callback when the first button is clicked')
  }

  onAccept() {
    CommonLog.info('Callback when the second button is clicked')
    router.push({
      uri: "pages/HomePage",
      params: { dataList: this.ShoppingCartsGoods }
    })
  }

  existApp() {
    CommonLog.info('Click the callback in the blank area')
  }
4. 添加分布式流转

分布式流转需要在同一网络下通过 DeviceManager组件 进行设备间发现和认证,获取到可信设备的deviceId调用 featureAbility.startAbility ,即可把应用程序流转到另一设备。

1)创建DeviceManager实例;

2)调用实例的startDeviceDiscovery(),开始设备发现未信任设备;

3)设置设备状态监听on(‘deviceFound’,callback),获取到未信任设备,并用discoverList变量进行维护;

4)传入未信任设备参数,调用实例authenticateDevice方法,对设备进行PIN码认证;

5)若是已信任设备,可通过实例的getTrustedDeviceListSync()方法来获取设备信息;

6)将设备信息中的deviceId传入 `featureAbility.startAbility方法,实现流转;

7)流转接收方可通过 featureAbility.getWant()获取到发送方携带的数据;

项目中将上面设备管理封装至RemoteDeviceManager,通过RemoteDeviceManager的四个方法来动态维护deviceList设备信息列表,实现分布式流转只需要在deviceList中获取deviceId,然后调用featureAbility.startAbility并携带数据,即可实现分布式流转。

5.分布式数据管理

分布式数据管理 要求两个或多个设备在同一网络,才能监听到数据库的改变,从而渲染页面;开发步骤:

1)创建一个KVManager对象实例,用于管理数据库对象;

2)通过指定Options和storeId,创建并获取KVStore数据库,如下是参数说明;需要先通过createKVManager构建一个KVManager实例;

参数名类型必填说明
storeIdstring数据库唯一标识符,长度不大于 MAX_STORE_ID_LENGTH。
optionsOptions创建KVStore实例的配置信息。

3)KVStore数据库实例, KVStore.put提供增加数据的方法,如下是参数说明;

参数名类型必填说明
keystring要添加数据的key,不能为空且长度不大于 MAX_KEY_LENGTH 。
valueUint8Arraystringnumber
callbackAsyncCallback回调函数。

4) KVStore数据库实例,KVStore.on订阅指定类型的数据变更通知;一般监听远端设备变化,再进行相应操作达到分布式数据共享的效果;

本d项目通过storeId 值不同,创建了两个数据库,分别是ShoppingCartsInfo类和TotalData类,ShoppingCartsInfo应用添加商品到购物车,TotalData应用在购物车列表进行勾选结算;如下是TotalData类流程

如下是ShoppingCartsInfo类流程

项目下载和导入

1)git下载

git clone https://gitee.com/openharmony-sig/knowledge_demo_shopping.git  --depth=1

2)项目导入

打开DevEco Studio,点击File->Open->下载路径/FA/Shopping/DistributedShoppingCart

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://gitee.com/MNxiaona/733GH

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于单片机的多功能电子万年历系统

摘要:该题目要求学生综合运用单片机原理、低频电子线路、数字电路与逻辑设计等相关知识,设计完成多功能电子万年历系统。通过完成设计任务,使学生掌握单片机设计开发的基本流程,增强学生动手实践能力,培养学生分析和解决实际问题的能力,为后续课程的学习和工作打下良好基础。 关…

特征的前期融合与后期融合在召回、粗排、精排应用

前期融合:先对所有特征做concat,再输入DNN,一般常见于精排模型 特点:线上推理代价大,若有n个候选item需要做n次模型计算 后期融合:把用户和物品特征分别输入不同的神经网络,不对用户和物品做融…

基于Springboot的玩具租赁系统(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的玩具租赁系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构&…

多用户商城系统哪个好,2024多用户商城系统这样选

在2024年选择适合的多用户商城系统是一项至关重要的决策,因为一个优秀的商城系统不仅可以提升用户体验,还能够帮助企业实现业务目标并取得长期成功。然而,在众多的选择中挑选出最适合的一个并不容易,需要综合考虑各种因素&#xf…

static page 项目

static page 项目 作者:不染心 博客地址:https://blog.csdn.net/qq_38234785 源码地址:https://mbd.pub/o/bread/ZpWVlJps 未经允许,不得转载 文档版本v1,还没写完持续更新 一、引言 1. 软件概述和背景 本软件是…

Python-软件设计-“帮助”小孩子自我行为(电脑端看短视频)约束

目录 前言一、方式一:网站访问拦截二、方式二:SW(电脑软件简称)启动拦截三、使用代码的方式将方式一和方式二结合成自动化程序部署四、其他拓展知识1.程序打包2、开机自启文件夹 五、报错的解决方式1、打包成软件后,运行那个软件时不执行或报…

【论文阅读】ViTAE:Vision transformer advanced by exploring intrinsic inductive bias

ViTAE:Vision transformer advanced by exploring intrinsic inductive bias 论文地址摘要:简介:3 方法论3.1 重温视觉变压器3.2 ViTAE3.3 缩减单元3.4 Normal cell3.5 模型细节 4 训练4.1 Implementation details4.2 Comparison with the state-of-the-…

Linxu系统服务管理,systemd知识/进程优先级/平均负载/php进程CPU100%怎么解决系列知识!

shell脚本(命令)放后台 sleep 300& 放到后台运行,脚本或命令要全路径 nohup:用户推出系统进程继续工作 【功能说明】 nohup 命令可以将程序以忽略挂起信号的方式运行起来,被运行程序的输出信息将不会显示到终端 如…

华为鸿蒙应用--封装通用标题栏:CommonTitleBar(鸿蒙工具)-ArkTs

0、效果图 自定义通用标题栏 支持左、中、右常规标题栏设置; 支持自定义视图; 支持搜索功能 一、CommTitleBar代码 import router from ohos.router; import { Constants } from ../../constants/Constants; import { StyleConstants } from ../../…

PostgreSQL 把多余字段转JSON

核心SQL: json_agg(json_build_object(kgrq, a.kgrq, jgrq, a.jgrq, sgdd, a.sgdd))

理解与使用Linux设备树编译器(DTC)

这里写目录标题 设备树简介设备树编译器(DTC)安装DTC使用DTC实例:编辑设备树小结参考资料 Linux设备树编译器(DTC)是一个关键工具,用于处理嵌入式Linux系统中的设备树文件。本文将介绍设备树的概念、DTC的基…

基于Docker + Locust的数据持久化性能测试系统

前几天给大家分享了如何使用Locust进行性能测试,但是在实际使用中会发现存在压测的结果无法保存的问题,比如在分布式部署情况下进行压测,每轮压测完成需要释放资源删除容器重新部署后,这段时间的压测结果就都丢失了,如…

一文讲解Android车载系统camera架构 - EVS

Android的camera开发中,使用最多的是camera2 以及现在Google主推的cameraX 架构,而这两个架构主要针对的是手机移动端上camera的流程。 而今天介绍的EVS(Exterior View System)架构是不同于camera2上的手机架构,针对Automotive的版本&#x…

【源码阅读】 Golang中的database/sql库源码探究

Note:文章待完结 文章目录 前言一、整体目录结构二、driver包1、驱动相关driver.Driver2、驱动连接:driver.Conn3、预处理结构:Stmt4、执行结果 driver.Result5、查询结果:driver.Rows6、driver.RowsAffected7、driver.Value8、Va…

vue-quill-editor富文本插件控制字数显示

最终效果 富文本编辑框&#xff0c;只统计内容&#xff0c;不包含标签以及样式&#xff0c;超出最大字数限制提示。 具体代码 html <div class"relative"><quillEditorv-model"form.nutriSuggestion"ref"myQuillEditor7":options&quo…

03-JAVA设计模式-策略模式

策略模式 什么是策略模式 策略模式&#xff08;Strategy Pattern&#xff09;是行为设计模式之一&#xff0c;它使你能在运行时改变对象的行为。在策略模式中&#xff0c;一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为模式。 在策略模式中&#xff0c;…

uniapp微信小程序开发踩坑日记:由于图表数据渲染不出来,我第一次在项目中用watch函数监听数据变化

一、发现问题 在我们团队自己开发的微信小程序中&#xff0c;引入了Echarts图表库 然后突然有一天&#xff0c;后端队友反应图表渲染有问题。后面我去试了一下&#xff0c;确实20次里面必有一次数据渲染不出来 断定代码没问题&#xff0c;于是我们将其鉴定为玄学 二、问题原因…

【GitHub】主页简历优化

【github主页】优化简历 写在最前面一、新建秘密仓库二、插件卡片配置1、仓库状态统计2、Most used languages&#xff08;GitHub 常用语言统计&#xff09;使用细则 3、Visitor Badge&#xff08;GitHub 访客徽章&#xff09;4、社交统计5、打字特效6、省略展示小猫 &#x1f…

UDP和TCP(传输层)

这里写目录标题 UDPUDP的基本特点UDP协议报文格式 TCPTCP协议报文格式TCP特点可靠传输实现机制确认应答超时重传数据丢了应答报文丢了 小结 UDP UDP的基本特点 无连接不可靠传输面向数据报全双工 UDP协议报文格式 2个字节有效范围(无符号): 0 ~ 65535(2^16 - 1). 2个字节有效范…

用数据检验函数正确性,matlab2C

数据存取格式 filename1 g.txt; fid1 fopen(filename1,w); for i 1 : length(g)for j1:size(g,2)if(j1)fprintf(fid1,{%.16f,,g(i,j)); elseif(j>1&&j<151)fprintf(fid1,%.16f,,g(i,j)); elsefprintf(fid1,%.16f},\n,g(i,j));endend%fprintf(fid1,\n…
最新文章