当前位置:   article > 正文

鸿蒙HarmonyOS项目实战开发:分布式菜单

鸿蒙HarmonyOS项目实战开发:分布式菜单

简介

分布式菜单demo 模拟的是多人聚餐点菜的场景,不需要扫码关注公众号等一系列操作,通过分布式数据库可以方便每个人可及时查看到订单详情,数量,总额等;效果如下

  • demo效果

    show

目录

完整的项目结构目录如下

  1. ├─entry
  2. │ └─src
  3. │ └─main
  4. │ │ config.json // 应用配置文件
  5. │ │
  6. │ ├─ets
  7. │ │ └─MainAbility
  8. │ │ │ app.ets // 应用程序主入口
  9. │ │ │
  10. │ │ ├─model
  11. │ │ │ CommonLog.ets // 日志类
  12. │ │ │ MenuData.ets // 初始化菜单数据类
  13. │ │ │ MenuListDistributedData.ets // 加入菜单分布式数据库
  14. │ │ │ RemoteDeviceManager.ets // 分布式拉起设备管理类
  15. │ │ │ SubmitData.ets // 结算订单分布式数据库
  16. │ │ │
  17. │ │ └─pages
  18. │ │ detailedPage.ets // 菜品详细页面
  19. │ │ index.ets // 首页
  20. │ │ menuAccount.ets // 订单详情页面
  21. │ │
  22. │ └─resources
  23. │ ├─base
  24. │ │ ├─element
  25. │ │ │ string.json
  26. │ │ │
  27. │ │ ├─graphic
  28. │ │ ├─layout
  29. │ │ ├─media // 存放媒体资源
  30. │ │ │ icon.png
  31. │ │ │ icon_add.png
  32. │ │ │ icon_back.png
  33. │ │ │ icon_cart.png
  34. │ │ │
  35. │ │ └─profile
  36. │ └─rawfile

开发步骤

1. 新建OpenHarmony ETS项目

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

image-20211124092813545

image-20211124092813545

2. 编写商品展示主页面

image-20211124093106260

2.1用户信息

1): 主要用到Flex容器ImageText组件;

2): 用户名称和头像图标,根据设备序列号不同,可展示不同的名称和图标;

3): 点击右上角分享的小图标,可分布式拉起局域网内的另一台设备;

  1. @Component
  2. struct MemberInfo {
  3. @Consume userImg: Resource
  4. @Consume userName: string
  5. aboutToAppear() {
  6. // 根据设备序列号不同,展示不同的名称和图标
  7. CommonLog.info('==serial===' + deviceInfo.serial);
  8. if (deviceInfo.serial == '150100384754463452061bba4c3d670b') {
  9. this.userImg = $r("app.media.icon_user")
  10. this.userName = 'Sunny'
  11. }
  12. else {
  13. this.userImg = $r("app.media.icon_user_another")
  14. this.userName = 'Jenny'
  15. }
  16. }
  17. build() {
  18. Flex({ direction: FlexDirection.Column }) {
  19. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  20. Image(this.userImg)
  21. .width('96lpx')
  22. .height('96lpx')
  23. .margin({ right: '18lpx' })
  24. Text(this.userName)
  25. .fontSize('36lpx')
  26. .fontWeight(FontWeight.Bold)
  27. .flexGrow(1)
  28. Image($r("app.media.icon_share"))
  29. .width('64lpx')
  30. .height('64lpx')
  31. }
  32. // 打开分布式设备列表
  33. .onClick(() => {
  34. this.DeviceDialog.open()
  35. })
  36. .layoutWeight(1)
  37. .padding({ left: '48lpx', right: '48lpx' })
  38. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  39. Column() {
  40. Text('124')
  41. .fontSize('40lpx')
  42. .margin({ bottom: '24lpx' })
  43. Text('积分')
  44. .fontSize('22lpx')
  45. .opacity(0.4)
  46. }
  47. .flexGrow(1)
  48. Column() {
  49. Text('0')
  50. .fontSize('40lpx')
  51. .margin({ bottom: '24lpx' })
  52. Text('优惠劵')
  53. .fontSize('22lpx')
  54. .opacity(0.4)
  55. }
  56. .flexGrow(1)
  57. Column() {
  58. Image($r("app.media.icon_member"))
  59. .width('48lpx')
  60. .height('48lpx')
  61. .margin({ bottom: '24lpx' })
  62. Text('会员码')
  63. .fontSize('22lpx')
  64. .fontColor('#000000')
  65. .opacity(0.4)
  66. }
  67. .flexGrow(1)
  68. }
  69. .layoutWeight(1)
  70. }
  71. .width('93%')
  72. .height('25%')
  73. .borderRadius('16lpx')
  74. .backgroundColor('#FFFFFF')
  75. .margin({ top: '24lpx', bottom: '32lpx' })
  76. }
  77. }
2.2列表展示

1): 主要用到Flex容器 和Scroll容器ImageText组件;

2): 从首页点击列表进入菜品详细页面,点菜成功后会自动返回首页,此时列表需要动态更新菜品的数量;

  1. @Component
  2. struct MenuHome {
  3. private specialty: any[]
  4. private winterNew: any[]
  5. private classic: any[]
  6. private soup: any[]
  7. private menuItems: MenuData[]
  8. private titleList = ['招牌菜', '冬季新品', '下饭菜', '汤品']
  9. @State name: string = '招牌菜'
  10. build() {
  11. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start }) {
  12. Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceAround }) {
  13. ForEach(this.titleList, item => {
  14. Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
  15. Text(item)
  16. .fontSize('24lpx')
  17. }
  18. .padding({ left: '24lpx' })
  19. .backgroundColor(this.name == item ? '#1A006A3A' : '#FFFFFF')
  20. .height('160lpx')
  21. .onClick(() => {
  22. this.name = item
  23. if (this.name == '招牌菜') {
  24. this.menuItems = initializeOnStartup(this.specialty);
  25. }
  26. else if (this.name == '冬季新品') {
  27. this.menuItems = initializeOnStartup(this.winterNew);
  28. }
  29. else if (this.name == '下饭菜') {
  30. this.menuItems = initializeOnStartup(this.classic);
  31. }
  32. else if (this.name == '汤品') {
  33. this.menuItems = initializeOnStartup(this.soup);
  34. }
  35. })
  36. }, item => item)
  37. }
  38. .width('20%')
  39. .backgroundColor('#FFFFFF')
  40. Flex({ direction: FlexDirection.Column }) {
  41. Text(this.name)
  42. .fontSize('32lpx')
  43. .fontWeight(FontWeight.Bold)
  44. .opacity(0.4)
  45. .height('8%')
  46. Scroll() {
  47. Column() {
  48. List() {
  49. ForEach(this.menuItems, item => {
  50. ListItem() {
  51. MenuListItem({ menuItem: item })
  52. }
  53. }, item => item.id.toString())
  54. }
  55. }
  56. }
  57. .height('92%')
  58. }
  59. .margin({ left: '10lpx' })
  60. .width('75%')
  61. }
  62. .height('50%')
  63. }
  64. }
2.3底部总额

1): 主要用到Flex容器 和Stack容器ImageText组件;

2): 从首页点击列表进入菜品详细页面,点菜成功后会自动返回首页,更新订单数量和总额;

3): 点击底部总额框,将订单列表加入分布式数据库,@entry模拟监听数据库变化,拉起订单列表详情页面;

  1. @Component
  2. struct TotalInfo {
  3. @Consume TotalMenu: any[];
  4. private total: number = 0;
  5. private amount: number = 0;
  6. private remoteData: MenuListData
  7. aboutToAppear() {
  8. for (var index = 0; index < this.TotalMenu.length; index++) {
  9. this.total = this.total + this.TotalMenu[index].price * this.TotalMenu[index].quantity
  10. this.amount = this.amount + this.TotalMenu[index].quantity
  11. }
  12. }
  13. build() {
  14. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  15. Stack({ alignContent: Alignment.Center }) {
  16. Image($r("app.media.icon_cart"))
  17. .width('96lpx')
  18. .height('96lpx')
  19. .margin({ left: '22lpx' })
  20. Text(this.amount.toString())
  21. .backgroundColor('#F84747')
  22. .borderRadius('30plx')
  23. .fontSize('24plx')
  24. .textAlign(TextAlign.Center)
  25. .fontColor('#FFFFFF')
  26. .width('50lpx')
  27. .height('50lpx')
  28. .margin({ left: '100lpx', bottom: '85lpx' })
  29. }
  30. .width('150lpx')
  31. .height('150lpx')
  32. Text('¥')
  33. .fontSize('22lpx')
  34. .fontColor('#006A3A')
  35. .margin({ left: '22lpx' })
  36. Text(this.total.toString())
  37. .fontSize('40lpx')
  38. .fontColor('#006A3A')
  39. .flexGrow(1)
  40. Text('点好了')
  41. .height('100%')
  42. .width('35%')
  43. .fontColor('#FFFFFF')
  44. .backgroundColor('#F84747')
  45. .textAlign(TextAlign.Center)
  46. }
  47. // 将总的订单数据,加入分布式数据库
  48. .onClick(() => {
  49. this.remoteData.putData("menu_list", this.TotalMenu)
  50. })
  51. .width('100%')
  52. .height('10%')
  53. .backgroundColor('#FFFFFF')
  54. }
  55. }
3. 编写菜单详细页面

image-20211124093106260

3.1 菜单详情

1): 主要用到Flex容器 ImageText组件Button组件;

2): 辣度可以选择;

3):点击选好了,需要判断该菜品是否已经在总订单里面,并判断是哪一个用户添加,根据判断,做出相应的增加;

  1. @Component
  2. struct detailInfo {
  3. private menuItem
  4. private spicyList = ['正常辣', '加辣', '少辣']
  5. @State spicy: string = '正常辣'
  6. private TotalMenu: any[]
  7. private index = 0
  8. private userName: string
  9. build() {
  10. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
  11. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) {
  12. Flex({ direction: FlexDirection.Row }) {
  13. Flex() {
  14. Image(this.menuItem.imgSrc)
  15. .objectFit(ImageFit.Contain)
  16. }
  17. Flex({ direction: FlexDirection.Column }) {
  18. Text(this.menuItem.name)
  19. .fontSize('32lpx')
  20. .flexGrow(1)
  21. Text(this.menuItem.remarks)
  22. .fontSize('22lpx')
  23. .fontColor('#000000')
  24. .opacity(0.6)
  25. .flexGrow(1)
  26. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  27. Text('¥')
  28. .fontSize('22lpx')
  29. Text(this.menuItem.price.toString())
  30. .fontSize('40lpx')
  31. Text('/份')
  32. .fontSize('22lpx')
  33. .flexGrow(1)
  34. Image($r("app.media.icon_reduce"))
  35. .width('44lpx')
  36. .height('44lpx')
  37. .onClick(() => {
  38. prompt.showToast({
  39. message: "Reduce function to be completed",
  40. duration: 5000
  41. })
  42. })
  43. Text(this.menuItem.quantity.toString())
  44. .margin({ left: '15lpx', right: '15lpx' })
  45. Image($r("app.media.icon_add"))
  46. .width('44lpx')
  47. .height('44lpx')
  48. .margin({ right: '15lpx' })
  49. .onClick(() => {
  50. prompt.showToast({
  51. message: "Increase function to be completed",
  52. duration: 5000
  53. })
  54. })
  55. }
  56. .flexGrow(2)
  57. }
  58. }
  59. .height('40%')
  60. .margin({ top: '40lpx', bottom: '24lpx' })
  61. Button()
  62. .backgroundColor('#000000')
  63. .opacity(0.1)
  64. .height('2lpx')
  65. .margin({ left: '24lpx' })
  66. .width('92%')
  67. Flex({ direction: FlexDirection.Row }) {
  68. Button()
  69. .backgroundColor('#006A3A ')
  70. .width('8lpx')
  71. .height('48lpx')
  72. .margin({ right: '12lpx' })
  73. Text('辣度')
  74. }
  75. .margin({ left: '44lpx', top: '48lpx', bottom: '32lpx' })
  76. Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceEvenly }) {
  77. ForEach(this.spicyList, item => {
  78. Button(item)
  79. .fontSize('28lpx')
  80. .height('60lpx')
  81. .width('156lpx')
  82. .borderRadius('12lpx')
  83. .backgroundColor(this.spicy == item ? '#006A3A' : '#0D000000')
  84. .fontColor(this.spicy == item ? '#FFFFFF' : '#000000')
  85. .onClick(() => {
  86. this.spicy = item
  87. })
  88. }, item => item)
  89. }
  90. }
  91. .margin({ top: '56lpx' })
  92. .width('92%')
  93. .height('50%')
  94. .borderRadius('16lpx')
  95. .backgroundColor('#FFFFFF')
  96. Button('选好了')
  97. .fontSize('36lpx')
  98. .width('80%')
  99. .height('7%')
  100. .backgroundColor('#F84747')
  101. .onClick(() => {
  102. for (this.index = 0; this.index < this.TotalMenu.length; this.index++) {
  103. if (this.TotalMenu[this.index].name == this.menuItem.name && this.TotalMenu[this.index].spicy == this.spicy) {
  104. this.TotalMenu[this.index].quantity = this.TotalMenu[this.index].quantity + 1;
  105. if (this.userName == 'Sunny') {
  106. this.TotalMenu[this.index].userNumber = this.TotalMenu[this.index].userNumber + 1;
  107. } else if (this.userName == 'Jenny') {
  108. this.TotalMenu[this.index].anotherUserNumber = this.TotalMenu[this.index].anotherUserNumber + 1;
  109. }
  110. break;
  111. }
  112. }
  113. // 菜名不一样,辣度不一样,都需要重新push到列表里面
  114. if (this.index == this.TotalMenu.length) {
  115. this.menuItem.spicy = this.spicy;
  116. this.menuItem.quantity = 1;
  117. //根据不用的用户名称,
  118. if (this.userName == 'Sunny') {
  119. this.menuItem.userNumber = 1;
  120. } else if (this.userName == 'Jenny') {
  121. this.menuItem.anotherUserNumber = 1;
  122. }
  123. this.TotalMenu.push(this.menuItem);
  124. }
  125. router.push({
  126. uri: 'pages/index',
  127. params: { menuItem: this.menuItem, TotalMenu: this.TotalMenu }
  128. })
  129. })
  130. .margin({ top: '10%' })
  131. }
  132. }
  133. }
4. 编写订单详情页面

image-20211124093106260

4.1 订单列表

1): 主要用到Flex容器ImageText组件Button组件;

2): 点击下单,将"submitOk" 加入分布式数据库,监听数据库变化后,弹出自定义对话框;

  1. @Component
  2. struct TotalItem {
  3. private totalMenu: MenuData
  4. build() {
  5. Flex({ direction: FlexDirection.Column }) {
  6. Flex({ direction: FlexDirection.Row, alignContent: FlexAlign.Start, justifyContent: FlexAlign.Start }) {
  7. Image(this.totalMenu.imgSrc)
  8. .width('210lpx')
  9. .height('100%')
  10. Flex({ direction: FlexDirection.Column }) {
  11. Text(this.totalMenu.name)
  12. .fontSize('32lpx')
  13. .flexGrow(1)
  14. Text(this.totalMenu.spicy)
  15. .fontSize('22lpx')
  16. .fontColor('#000000')
  17. .opacity(0.6)
  18. .flexGrow(1)
  19. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  20. Text('¥')
  21. .fontSize('22lpx')
  22. Text(this.totalMenu.price.toString())
  23. .fontSize('40lpx')
  24. Text('/份')
  25. .fontSize('22lpx')
  26. .flexGrow(1)
  27. Text(this.totalMenu.quantity.toString())
  28. .fontColor("#F84747")
  29. .fontSize('40lpx')
  30. }
  31. .flexGrow(2)
  32. }
  33. .padding({ left: '5%', top: '6%' })
  34. .width('70%')
  35. }
  36. .height('180lpx')
  37. Button()
  38. .backgroundColor('#000000')
  39. .opacity(0.1)
  40. .height('2lpx')
  41. .margin({ top: '20lpx' })
  42. .width('100%')
  43. if (this.totalMenu.userNumber > 0) {
  44. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  45. Image(this.totalMenu.userImg)
  46. .width('96lpx')
  47. .height('96lpx')
  48. Text(this.totalMenu.userName)
  49. .fontSize('36lpx')
  50. .fontWeight(FontWeight.Bold)
  51. .margin({ left: '12lpx' })
  52. .flexGrow(1)
  53. Text(this.totalMenu.userNumber.toString())
  54. .fontSize('32lpx')
  55. .margin({ right: '11plx' })
  56. }
  57. .height('150lpx')
  58. }
  59. if (this.totalMenu.anotherUserNumber > 0) {
  60. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  61. Image(this.totalMenu.anotherUserImg)
  62. .width('96lpx')
  63. .height('96lpx')
  64. Text(this.totalMenu.anotherUserName)
  65. .fontSize('36lpx')
  66. .fontWeight(FontWeight.Bold)
  67. .margin({ left: '12lpx' })
  68. .flexGrow(1)
  69. Text(this.totalMenu.anotherUserNumber.toString())
  70. .fontSize('32lpx')
  71. .margin({ right: '11plx' })
  72. }
  73. .height('150lpx')
  74. }
  75. }
  76. .margin({ top: '12lpx' })
  77. .borderRadius('16lpx')
  78. .padding({ left: '3%', right: '3%', top: '2%' })
  79. .backgroundColor('#FFFFFF')
  80. }
  81. }
4.2自定义弹框

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

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

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

  1. @CustomDialog
  2. struct SubmitDialog {
  3. private controller: CustomDialogController
  4. build() {
  5. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
  6. Flex({ justifyContent: FlexAlign.Center }) {
  7. Image($r("app.media.icon_success"))
  8. .width('100lpx')
  9. .height('80lpx')
  10. }
  11. .flexGrow(1)
  12. Text('下单成功')
  13. .fontSize('36lpx')
  14. .fontColor('#000000')
  15. .flexGrow(1)
  16. Text('*温馨提示:菜品具体售卖情况请以店面实际情况为准哦~')
  17. .fontSize('22lpx')
  18. .opacity(0.6)
  19. .fontColor('#000000')
  20. .padding({ left: '10lpx', right: '10lpx' })
  21. }
  22. .height('300lpx')
  23. .width('100%')
  24. .padding({ top: '50lpx', bottom: '20lpx' })
  25. }
  26. }

​ 3)在@entry创建CustomDialogController对象并传入弹窗所需参数,设置点击允许点击遮障层退出,通过open()方法,显示弹窗;

  1. SubmitDialog: CustomDialogController = new CustomDialogController({
  2. builder: SubmitDialog(),
  3. autoCancel: true
  4. })
  5. aboutToAppear() {
  6. this.remoteData.createManager(() => {
  7. let self = this;
  8. var data;
  9. if (JSON.stringify(self.remoteData.dataItem).length > 0) {
  10. data = self.remoteData.dataItem;
  11. CommonLog.info("======submit==" + data[0].submit);
  12. if (data[0].submit == "submitOk") {
  13. this.SubmitDialog.open()
  14. }
  15. }
  16. }, "com.distributed.order", "submit")
  17. }
5. 添加分布式流转

分布式流转需要在同一网络下通过 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

6.分布式数据管理

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

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

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

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

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

参数名类型必填说明
keystring要添加数据的key,不能为空且长度不大于MAX_KEY_LENGTH
valueUint8Array | string | number | boolean要添加数据的value,支持Uint8Array、number 、 string 、boolean,Uint8Array、string 的长度不大于MAX_VALUE_LENGTH
callbackAsyncCallback回调函数。

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

本项目通过storeId 值不同,创建了两个数据库,分别是MenuListDistributedData类和SubmitData类;

MenuListDistributedData是将完整订单添加到分布式数据库

  1. @Component
  2. struct TotalInfo {
  3. @Consume TotalMenu: any[];
  4. private total: number = 0;
  5. private amount: number = 0;
  6. private remoteData: MenuListData
  7. aboutToAppear() {
  8. for (var index = 0; index < this.TotalMenu.length; index++) {
  9. this.total = this.total + this.TotalMenu[index].price * this.TotalMenu[index].quantity
  10. this.amount = this.amount + this.TotalMenu[index].quantity
  11. }
  12. }
  13. build() {
  14. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  15. Stack({ alignContent: Alignment.Center }) {
  16. Image($r("app.media.icon_cart"))
  17. .width('96lpx')
  18. .height('96lpx')
  19. .margin({ left: '22lpx' })
  20. Text(this.amount.toString())
  21. .backgroundColor('#F84747')
  22. .borderRadius('30plx')
  23. .fontSize('24plx')
  24. .textAlign(TextAlign.Center)
  25. .fontColor('#FFFFFF')
  26. .width('50lpx')
  27. .height('50lpx')
  28. .margin({ left: '100lpx', bottom: '85lpx' })
  29. }
  30. .width('150lpx')
  31. .height('150lpx')
  32. Text('¥')
  33. .fontSize('22lpx')
  34. .fontColor('#006A3A')
  35. .margin({ left: '22lpx' })
  36. Text(this.total.toString())
  37. .fontSize('40lpx')
  38. .fontColor('#006A3A')
  39. .flexGrow(1)
  40. Text('点好了')
  41. .height('100%')
  42. .width('35%')
  43. .fontColor('#FFFFFF')
  44. .backgroundColor('#F84747')
  45. .textAlign(TextAlign.Center)
  46. }
  47. .onClick(() => {
  48. this.remoteData.putData("menu_list", this.TotalMenu)
  49. })
  50. .width('100%')
  51. .height('10%')
  52. .backgroundColor('#FFFFFF')
  53. }
  54. }

SubmitData在订单结算是点击下单,将submitOk 添加到数据库;

  1. @Component
  2. struct SubmitList {
  3. private remoteData: SubmitData
  4. private SubmitOK: any[] = [
  5. {
  6. submit: "submitOk"
  7. }
  8. ];
  9. build() {
  10. Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
  11. Text('下单')
  12. .fontSize('36lpx')
  13. .fontColor('#FFFFFF')
  14. }
  15. .width('100%')
  16. .height('10%')
  17. .backgroundColor('#F84747')
  18. .onClick(() => {
  19. this.remoteData.putData("submit", this.SubmitOK)
  20. })
  21. .margin({ top: '5%' })
  22. }
  23. }

最后,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(Harmony NEXT)资料用来跟着学习是非常有必要的。 

为了能够帮助大家快速掌握鸿蒙(Harmony NEXT)应用开发技术知识。在此给大家分享一下我结合鸿蒙最新资料整理出来的鸿蒙南北向开发学习路线以及整理的最新版鸿蒙学习文档资料。

这份鸿蒙(Harmony NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员,可以直接领取这份资料

 获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(Harmony NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

 有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/265981
推荐阅读
相关标签
  

闽ICP备14008679号