当前位置:   article > 正文

鸿蒙HarmonyOS项目实战开发:分布式购物车_harmonyos简单的购物应用示例_鸿蒙简单购物软件代码

鸿蒙简单购物软件代码

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img

img
img
htt

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

│ └─resources // 静态资源目录
│ ├─base
│ │ ├─element
│ │ ├─graphic
│ │ ├─layout
│ │ ├─media // 存放媒体资源
│ │ └─profile
│ └─rawfile


#### 开发步骤


##### 1. 新建OpenHarmony ETS项目


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


![image-20211124092813545](https://img-blog.csdnimg.cn/img_convert/196b484ccfaae5144564bda384e1a552.png)


##### 2. 编写商品展示主页面



![image-20211124093106260](https://img-blog.csdnimg.cn/img_convert/ab39dc7cb6ccefa0efa410af9797c2b0.png)


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


###### 2.1商品列表展示


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


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


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



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

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' })
}
// 转场动画使用系统提供的多种默认效果(平移、缩放、透明度等)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

pageTransition() {
PageTransitionEnter({ duration: 1000 })
.slide(SlideEffect.Left)
PageTransitionExit({ duration: 1000 })
.slide(SlideEffect.Right)
}


###### 2.2底部导航栏


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



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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()
      }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

##### 3. 编写商品详细页面


###### 3.1顶部滑动组件


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



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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]( )容器来包裹,组件代码如下:



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

@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')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

}
}


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



  • 1
  • 2
  • 3
  • 4
  • 5

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并携带数据,即可实现分布式流转。**



![RemoteDeviceManager](https://img-blog.csdnimg.cn/img_convert/1c0ea6e89a85cb2ae66784eebbc9248c.png)


##### 5.分布式数据管理


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


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


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




| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| storeId | string | 是 | 数据库唯一标识符,长度不大于[MAX\_STORE\_ID\_LENGTH]( )。 |
| options | [Options]( ) | 是 | 创建KVStore实例的配置信息。 |


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




| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| key | string | 是 | 要添加数据的key,不能为空且长度不大于[MAX\_KEY\_LENGTH]( )。 |
| value | Uint8Array | string | number | boolean | 是 | 要添加数据的value,支持Uint8Array、number 、 string 、boolean,Uint8Array、string 的长度不大于[MAX\_VALUE\_LENGTH]( )。 |
| callback | AsyncCallback | 是 | 回调函数。 |


4) KVStore数据库实例,KVStore.on订阅指定类型的数据变更通知;一般监听远端设备变化,再进行相应操作达到分布式数据共享的效果;
 | --- | --- | --- |
| key | string | 是 | 要添加数据的key,不能为空且长度不大于[MAX\_KEY\_LENGTH]( )。 |
| value | Uint8Array | string | number | boolean | 是 | 要添加数据的value,支持Uint8Array、number 、 string 、boolean,Uint8Array、string 的长度不大于[MAX\_VALUE\_LENGTH]( )。 |
| callback | AsyncCallback | 是 | 回调函数。 |


4) KVStore数据库实例,KVStore.on订阅指定类型的数据变更通知;一般监听远端设备变化,再进行相应操作达到分布式数据共享的效果;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/757226
推荐阅读
相关标签
  

闽ICP备14008679号