如何使用ArkUI从0-1写一个开发购物应用程序(上)

567 篇文章 2 订阅
555 篇文章 0 订阅

本文演示如何用HarmonyOS的ArkUI来开发一个购物应用程序。

首选是打开DevEco Studio 3,可以看到如下界面。

点击“Create Project”来创建ArkUI程序“ArkUIShopping”。

选择模板

选择空模板Empty Ability,点击“Next”执行下一步。

配置项目

配置项目信息,重要是以下圈中部分。其他配置按照默认配置即可。点击“Finish”执行下一步。

程序初始化完成之后,就能在该程序基础上进行代码开发、运行。

运行HarmonyOS应用,打开Device Manager

登入华为账号

点击“Sign In”登入个人注册的华为账号。如果没有,则参考本文最后的链接进行注册。

启动远程模拟器

运行应用,点击下命的三角形按钮以启动应用

应用运行效果图如下。

完善代码

在空模板的基础上,我们初步添加业务代码,来最终实现购物应用。

实现商品列表页签

主界面商品列表页签主要由下面三个部分组成:

  • 顶部的Tabs组件。
  • 中间TabContent组件内包含List组件。其中List组件的item是一个水平布局,由一个垂直布局和一个Image组件组成;item中的垂直布局由3个Text组件组成。
  • 底部的页签导航。

下面来一起创建第一个页面。

在pages目录下面新建一个Page.。

该Page命名为HomePage。

创建完成之后,会在pages目录下面生产一个HomePage.ets文件,HomePage.ets文件默认的代码如下。

@Entry
@Component
struct HomePage {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

新建与pages文件夹同级的model文件夹,并在model目录下新建ArsData.ets、GoodsData.ets、Menu.ets和GoodsDataModels.ets文件,其中ArsData.ets、GoodsData.ets、Menu.ets是数据实体类,GoodsDataModels.ets是存放这三种实体数据集合,并定义了获取各种数据集合的方法。数据实体包含实体的属性和构造方法,可通过new ArsData(string,string) 来获取ArsData对象。

ArsData.ets内容如下:

let NextId = 0;
export class ArsData {
  id: string;
  title: string;
  content: string;
  constructor(title: string, content: string) {
    this.id = `${NextId++}`;
    this.title = title;
    this.content = content;
  }
}

GoodsData.ets内容如下:

let NextId = 0;
export class GoodsData {
  id: string;
  title: string;
  content: string;
  price: number;
  imgSrc: Resource;
  constructor(title: string, content: string, price: number, imgSrc: Resource) {
    this.id = `${NextId++}`;
    this.title = title;
    this.content = content;
    this.price = price;
    this.imgSrc = imgSrc;
  }
}

Menu.ets内容如下:

let NextId = 0;
export class Menu {
  id: string;
  title: string;
  num: number;
  constructor(title: string, num: number) {
    this.id = `${NextId++}`;
    this.title = title;
    this.num = num;
  }
}
export class ImageItem {
  id: string;
  title: string;
  imageSrc: Resource;
  constructor(title: string, imageSrc: Resource) {
    this.id = `${NextId++}`;
    this.title = title;
    this.imageSrc = imageSrc;
  }
}

GoodsDataModels.ets内容如下:

import {  GoodsData} from './GoodsData'

import {Menu, ImageItem} from './Menu'
import {ArsData} from './ArsData'

export function initializeOnStartup(): Array<GoodsData> {
  let GoodsDataArray: Array<GoodsData> = []
  GoodsComposition.forEach(item => {
    console.log(item.title);
    GoodsDataArray.push(new GoodsData(item.title, item.content, item.price, item.imgSrc));
  })
  return GoodsDataArray;
}

export function getIconPath(): Array<string> {
  let IconPath: Array<string> = ['nav/icon-buy.png','nav/icon-shopping-cart.png','nav/icon-my.png']

  return IconPath;
}

export function getIconPathSelect(): Array<string> {
  let IconPathSelect: Array<string> = ['nav/icon-home.png','nav/icon-shopping-cart-select.png','nav/icon-my-select.png']

  return IconPathSelect;
}

export function getDetailImages(): Array<string> {
  let detailImages: Array<string> = ['computer/computer1.png','computer/computer2.png','computer/computer3.png','computer/computer4.png','computer/computer5.png','computer/computer6.png']

  return detailImages;
}


export function getMenu(): Array<Menu> {
  let MenuArray: Array<Menu> = []
  MyMenu.forEach(item => {
    MenuArray.push(new Menu(item.title,item.num));
  })
  return MenuArray;
}

export function getTrans(): Array<ImageItem> {
  let ImageItemArray: Array<ImageItem> = []
  MyTrans.forEach(item => {
    ImageItemArray.push(new ImageItem(item.title,item.imageSrc));
  })
  return ImageItemArray;
}

export function getMore(): Array<ImageItem> {
  let ImageItemArray: Array<ImageItem> = []
  MyMore.forEach(item => {
    ImageItemArray.push(new ImageItem(item.title,item.imageSrc));
  })
  return ImageItemArray;
}

export function getArs(): Array<ArsData> {
  let ArsItemArray: Array<ArsData> = []
  ArsList.forEach(item => {
    ArsItemArray.push(new ArsData(item.title,item.content));
  })
  return ArsItemArray;
}

const GoodsComposition: any[] = [
  {
    "title": 'HUAWEI nova 8 Pro ',
    "content": 'Goes on sale: 10:08',
    "price": '3999',
    "imgSrc": $rawfile('picture/HW (1).png')
  },
  {
    "title": 'HUAWEI Mate 30E Pro 5G',
    "content": '3 interest-free payments ',
    "price": '5299',
    "imgSrc": $rawfile('picture/HW (2).png')
  },
  {
    "title": 'HUAWEI MatePad Pro',
    "content": 'Flagship ',
    "price": '3799',
    "imgSrc": $rawfile('picture/HW (3).png')
  },
  {
    "title": 'HUAWEI Nova 8 Pro',
    "content": 'New arrival ',
    "price": '3999',
    "imgSrc": $rawfile('picture/HW (4).png')
  },
  {
    "title": 'HUAWEI WATCH FIT',
    "content": 'Versatile',
    "price": '769',
    "imgSrc": $rawfile('picture/HW (5).png')
  },
  {
    "title": 'HUAWEI nova 8 Pro ',
    "content": 'Goes on sale: 10:08',
    "price": '3999',
    "imgSrc": $rawfile('picture/HW (6).png')
  },
  {
    "title": 'HUAWEI Mate 30E Pro 5G',
    "content": '3 interest-free payments ',
    "price": '5299',
    "imgSrc": $rawfile('picture/HW (7).png')
  },
  {
    "title": 'HUAWEI MatePad Pro',
    "content": 'Flagship ',
    "price": '3799',
    "imgSrc": $rawfile('picture/HW (8).png')
  },
  {
    "title": 'HUAWEI Nova 8 Pro',
    "content": 'New arrival ',
    "price": '3999',
    "imgSrc": $rawfile('picture/HW (9).png')
  },
  {
    "title": 'HUAWEI WATCH FIT',
    "content": 'Versatile',
    "price": '769',
    "imgSrc": $rawfile('picture/HW (10).png')
  },
]

const MyMenu: any[] = [
  {
    'title': 'Favorites',
    'num': '10'
  },
  {
    'title': 'Searched',
    'num': '1000'
  },
  {
    'title': 'Following',
    'num': '100'
  },
  {
    'title': 'Followers',
    'num': '10000'
  }
]




const MyTrans: any[] = [
  {
    'title': 'Post: 520',
    'imageSrc': $rawfile('nav/icon-menu-release.png')
  },
  {
    'title': 'Sold: 520',
    'imageSrc': $rawfile('nav/icon-menu-sell.png')
  },
  {
    'title': 'Bought: 10',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  }
]

const MyMore: any[] = [
  {
    'title': 'Guide',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },
  {
    'title': 'Create',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },
  {
    'title': 'Poster',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },
  {
    'title': 'Games',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },
  {
    'title': 'Jobber',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },
  {
    'title': 'Myself',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },
  {
    'title': 'About',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },
  {
    'title': 'Rental',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },
  {
    'title': 'Author',
    'imageSrc': $rawfile('nav/icon-menu-buy.png')
  },

]

const ArsList: any[] =[
  {
    'title': 'Display Size',
    'content': '13.9 inches',
  },
  {
    'title': 'Memory',
    'content': '16 GB',
  },
  {
    'title': 'Marketing Name',
    'content': 'HUAWEI MateBook X Pro',
  },
  {
    'title': 'Color Gamut',
    'content': '100% sRGB color gamut (Typical)',
  },
  {
    'title': 'Battery',
    'content': '56 Wh (rated capacity)',
  },
  {
    'title': 'Storage',
    'content': '512 GB',
  },
  {
    'title': 'Resolution',
    'content': '3000x2000',
  },
  {
    'title': 'Processor',
    'content': '11th Gen Intel® Core™ i7-1165G7 Processor',
  },
  {
    'title': 'CPU Cores',
    'content': '4',
  },
  {
    'title': 'Launch Time',
    'content': 'January 2021',
  }
]

在HomePage.ets文件中创建商品列表页签相关的组件,添加GoodsHome代码如下:

@Component
struct GoodsHome {
  private goodsItems: GoodsData[]

  build() {
    Column() {
      Tabs() {
        TabContent() {
          GoodsList({ goodsItems: this.goodsItems });
        }
        .tabBar("Top Sellers")
        .backgroundColor(Color.White)
        TabContent() {
          GoodsList({ goodsItems: this.goodsItems });
        }
        .tabBar("Recommended")
        .backgroundColor(Color.White)
        TabContent() {
          GoodsList({ goodsItems: this.goodsItems });
        }
        .tabBar("Lifestyle")
        .backgroundColor(Color.White)
        TabContent() {
          GoodsList({ goodsItems: this.goodsItems });
        }
        .tabBar("Deals")
        .backgroundColor(Color.White)
      }
      .barWidth(500)
      .barHeight(25)
      .scrollable(true)
      .barMode(BarMode.Scrollable)
      .backgroundColor('#007DFF')
      .height(700)

    }
    .alignItems(HorizontalAlign.Start)
    .width('100%')
  }
}

在GoodsHome中使用Tabs组件,在Tabs组件中设置4个TabContent,给每个TabContent设置tabBar属性,并设置TabContent容器中的内容GoodsList组件,GoodsList组件代码如下:

@Component
struct GoodsList {
  private goodsItems: GoodsData[]
  build() {
    Column() {
      List() {
        ForEach(this.goodsItems, item => {
          ListItem() {
            GoodsListItem({ goodsItem: item })
          }
        }, item => item.id.toString())
      }
      .height('100%')
      .width('100%')
      .align(Alignment.Top)
      .margin({top: 5})
    }
  }
}

在GoodsList组件中遍历商品数据集合,ListItem组件中设置组件内容,并使用Navigator组件给每个Item设置顶级跳转路由,GoodsListItem组件代码如下:

@Component
struct GoodsListItem {
  private goodsItem: GoodsData
  build() {
    Navigator({ target: 'pages/ShoppingDetail' }) {
      Row() {
        Column(){
          Text(this.goodsItem.title)
            .fontSize(14)
          Text(this.goodsItem.content )
            .fontSize(10)
          Text('¥' + this.goodsItem.price)
            .fontSize(14)
            .fontColor(Color.Red)
        }
        .height(100)
        .width('50%')
        .margin({left: 20})
        .alignItems(HorizontalAlign.Start)
        Image(this.goodsItem.imgSrc)
          .objectFit(ImageFit.ScaleDown)
          .height(100)
          .width('40%')
          .renderMode(ImageRenderMode.Original)
          .margin({right: 10,left:10})
      }
      .backgroundColor(Color.White)
    }
    .params({ goodsData: this.goodsItem })
    .margin({ right: 5})
  }

在HomePage.ets中创建文件入口组件(Index)以及底部页签导航组件(HomeBottom),导入需要使用到的数据实体类以及需要使用的方法和组件,每个page文件都必须包含一个入口组件,使用@Entry修饰,HomePage文件中的入口组件(Index)代码如下:

import {GoodsData} from '../model/GoodsData'
import {initializeOnStartup,getIconPath,getIconPathSelect} from '../model/GoodsDataModels'
import {ShoppingCart} from './ShoppingCart'
import {MyInfo} from './MyPage'
@Entry
@Component
struct Index {
  @Provide currentPage: number = 1
  private goodsItems: GoodsData[] = initializeOnStartup()
  build() {
    Column() {
      Scroll() {
        Column() {
          if (this.currentPage == 1) {
            GoodsHome({ goodsItems: this.goodsItems })
          } else if (this.currentPage == 2) {
            //购物车列表
            ShoppingCart()
          } else {
            //我的
            MyInfo()
          }
        }
        .height(700)
      }
      .flexGrow(1)
      HomeBottom()
    }
    .backgroundColor("white")
  }
}

从入口组件的代码中可以看出,我们定义了一个全局变量currentPage ,并且使用@provide修饰,在其子组件(HomeBottom)中使用@Consume修饰。当子组件currentPage发生变化的时候,父组件currentPage也会发生变化,会重新加载页面,显示不同的页签。在入口组件中,通过initializeOnStartup获取商品列表数据(goodsItems)并传入GoodsHome组件中,HomeBottom组件代码如下

@Component
struct HomeBottom {
  @Consume currentPage: number
  private iconPathTmp: string[] =  getIconPath()
  private iconPathSelectsTmp: string[] =  getIconPathSelect()
  @State iconPath: string[] =  getIconPath()
  build() {
    Row(){
      List() {
        ForEach(this.iconPath, item => {
          ListItem() {
            Image($rawfile(item))
              .objectFit(ImageFit.Cover)
              .height(30)
              .width(30)
              .renderMode(ImageRenderMode.Original)
              .onClick(()=>{
                if(item==this.iconPath[0]){
                  this.iconPath[0]=this.iconPathTmp[0]
                  this.iconPath[1]=this.iconPathTmp[1]
                  this.iconPath[2]=this.iconPathTmp[2]
                  this.currentPage=1
                }
                if(item==this.iconPath[1]){
                  this.iconPath[0]=this.iconPathSelectsTmp[0]
                  this.iconPath[1]=this.iconPathSelectsTmp[1]
                  this.iconPath[2]=this.iconPathTmp[2]
                  this.currentPage=2
                }
                if(item==this.iconPath[2]){
                  this.iconPath[0]=this.iconPathSelectsTmp[0]
                  this.iconPath[1]=this.iconPathTmp[1]
                  this.iconPath[2]=this.iconPathSelectsTmp[2]
                  this.currentPage=3
                }
              })
          }
          .width(120)
          .height(40)
        }, item => item)
      }
      .margin({left:10})
      .align(Alignment.BottomStart)
      .listDirection(Axis.Horizontal)
    }
    .alignItems(VerticalAlign.Bottom)
    .height(30)
    .margin({top:10 ,bottom:10})
  }
}

以上内容是介绍了如何用ArkUI来开发一个购物应用程序(上半部分),关注我学习更多鸿蒙开发相关知识,接下来我将更新(ArkUI开发购物应用程序)下半部分

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了几套最新版的HarmonyOS NEXT学习资源

获取完整版高清学习路线,请点击→《HarmonyOS教学视频

HarmonyOS教学视频

鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取白皮书:请点击→《鸿蒙生态应用开发白皮书V2.0PDF

在这里插入图片描述

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. .……

在这里插入图片描述


二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

在这里插入图片描述

三、如何快速入门?鸿蒙基础入门学习指南

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. .……

在这里插入图片描述


四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. .……

在这里插入图片描述


五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 7.网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. .……

在这里插入图片描述


更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册

  • 31
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值