OpenHarmony实战开发-从0到1实现购物应用页面

概述

OpenHarmony ArkUI框架提供了丰富的动画组件和接口,开发者可以根据实际场景和开发需求,选用丰富的动画组件和接口来实现不同的动画效果。

本Codelab中,我们会构建一个简易的购物应用。应用包含两级页面,分别是主页(“商品浏览”页签、“购物车”页签、“我的”页签)和商品详情页面。效果如下图所示:

代码结构解读

本篇Codelab只对核心代码进行讲解,首先来介绍下整个工程的代码结构:

  • model:存放封装好的数据实体。
    • ArsData:我的页签相关参数实体。
    • GoodsData:商品列表页商品实体。
    • GoodsDataModels:各种实体的具体数据以及获取数据的方法。
    • Menu:我的页签菜单实体。
  • pages:存放页面。
    • HomePage:应用主页面,包含商品列表页签。
    • MyPage:我的页签。
    • ShoppingCartPage:购物车页签。
    • ShoppingDetail:商品详情页。
  • resources :存放工程使用到的资源文件。
    • resources/base/media:存放工程中使用的图片资源。
  • config.json:配置文件。

搭建OpenHarmony环境

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以Hi3516DV300开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)

以3.0版本为例:

2.搭建烧录环境

  1. 完成DevEco Device Tool的安装
  2. 完成Hi3516开发板的烧录

3.搭建开发环境

  1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
  2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。
  3. 工程创建完成后,选择使用真机进行调测。

构建商品列表页签

在本节中,我们将完成商品列表页签的设计,效果图如下:

从效果图可以看出,商品列表页签主要由三个部分组成:

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

实现步骤如下:

  1. 在pages目录下面新建一个ETS Page,命名为HomePage.ets,在config.json文件的pages属性中会自动添加“pages/HomePage”页面路由。

说明:

  • 页面文件名不能使用组件名称,比如:Text.ets、Button.ets等。
  • 每个页面文件中必须包含入口组件。

2.新建与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;}
}

一个文件中可以包含多个class ,Menu.ets中就包含了Menu类和ImageItem类,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;
}
//获取MyTrans数据列表
export function getTrans(): Array<ImageItem> {let ImageItemArray: Array<ImageItem> = []MyTrans.forEach(item => {ImageItemArray.push(new ImageItem(item.title,item.imageSrc));})return ImageItemArray;
}
//获取More数据列表
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;
}
//数据集合部分
...

3.在HomePage.ets文件中创建商品列表页签相关的组件,其中GoodsHome效果图如下:

代码如下:

@Component
@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(540).barHeight(50).scrollable(true).barMode(BarMode.Scrollable).backgroundColor('#007DFF').height('100%')}.alignItems(HorizontalAlign.Start)}
}

在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: GoodsDatabuild() {Navigator({ target: 'pages/ShoppingDetail' }) {Row() {Column() {Text(this.goodsItem.title).fontSize(18)Text(this.goodsItem.content).fontSize(14)Text('¥' + this.goodsItem.price).fontSize(18).fontColor(Color.Red)}.height(130).width('60%').margin({ left: 20 }).alignItems(HorizontalAlign.Start)Image(this.goodsItem.imgSrc).objectFit(ImageFit.ScaleDown).height(130).width('30%').renderMode(ImageRenderMode.Original).margin({ right: 10, left: 10 })}.backgroundColor(Color.White)}.params({ goodsData: this.goodsItem }).margin({ right: 5 })}
}

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

import { GoodsData, IconImage } from '../model/GoodsData'
import { initializeOnStartup, getIconPath, getIconPathSelect } from '../model/GoodsDataModels'
import { ShoppingCart } from './ShoppingCartPage.ets'
import { MyInfo } from './MyPage.ets'
import router from '@system.router';@Entry
@Component
struct Index {@Provide currentPage: number = 1private goodsItems: GoodsData[] = initializeOnStartup()@State Build: Array<Object> = [{icon: $r('app.media.icon_home'),icon_after: $r('app.media.icon_buy1'),text: '首页',num: 0},{icon: $r('app.media.icon_shopping_cart'),icon_after: $r('app.media.icon_shopping_cart_select'),text: '购物车',num: 1},{icon: $r('app.media.icon_my'),icon_after: $r('app.media.icon_my_select'),text: '我的',num: 2}]@Builder NavigationToolbar() {Flex({direction:FlexDirection.Row,wrap:FlexWrap.NoWrap,justifyContent:FlexAlign.SpaceAround}) {ForEach(this.Build, item => {Column() {Image(this.currentPage == item.num ? item.icon_after : item.icon).width(25).height(25)Text(item.text).fontColor(this.currentPage == item.num ? "#ff7500" : "#000000")}.onClick(() => {this.currentPage = item.num})})}}build() {Column() {Navigation() {Flex() {if (this.currentPage == 0) {GoodsHome({ goodsItems: this.goodsItems })}if (this.currentPage == 1) {ShoppingCart() //购物车列表}if (this.currentPage == 2) {MyInfo() //我的}}.width('100%').height('100%')}.toolBar(this.NavigationToolbar).title("购物车").hideTitleBar(this.currentPage == 1 ? false : true).hideBackButton(true)}}
}

从入口组件的代码中可以看出,我们定义了一个全局变量currentPage ,当currentPage发生变化的时候,会显示不同的页签。在入口组件中,通initializeOnStartup获取商品列表数据(goodsItems)并传入GoodsHome组件中。效果图如下:

构建购物车页签

从上面效果图可以看出,主界面购物车页签主要由下面三部分组成:

  1. 顶部的title,由Navigation组件title属性设置。
  2. 中间的List组件,其中List组件的item是一个水平的布局内包含一个toggle组件,一个Image组件和一个垂直布局,其item中的垂直布局是由2个Text组件组成。
  3. 底部一个水平布局包含两个Text组件。

在本任务中我们主要是构建一个购物车页签,给商品列表的每个商品设置一个单选框,可以选中与取消选中,底部Total值也会随之增加或减少,点击Check Out时会触发弹窗。下面我们来完成ShoppingCart页签。

  1. 在pages目录下面新建一个ETS Page ,命名为ShoppingCart.ets,config.json文件pages属性中也会自动添加“pages/ShoppingCart”页面路由。
  2. 在ShoppingCartPage.ets文件中添加入口组件(ShoppingCart),并导入需要使用到的数据实体类、方法和组件。ShoppingCart组件代码如下:
import {GoodsData} from '../model/GoodsData'
import {initializeOnStartup} from '../model/GoodsDataModels'
import prompt from '@system.prompt';@Entry
@Componentexport struct ShoppingCart {@Provide totalPrice: number = 0private goodsItems: GoodsData[] = initializeOnStartup()build() {Column() {ShopCartList({ goodsItems: this.goodsItems });ShopCartBottom()}.height('100%').width('100%').alignItems(HorizontalAlign.Start)}
}

3.新建ShopCartList组件用于存放购物车商品列表,ShopCartList组件效果图如下:

代码如下:

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

在ShopCartListItem中使用Toggle的单选框类型来实现每个item的选择和取消选择,在Toggle的onChage事件中来改变totalPrice的数值。ShopCartListItem组件效果图如下:

代码如下:

@Component
struct ShopCartListItem {@Consume totalPrice: numberprivate goodsItem: GoodsDatabuild() {Row() {Toggle({ type: ToggleType.Checkbox }).width(13).height(13).onChange((isOn: boolean) => {if (isOn) {this.totalPrice += parseInt(this.goodsItem.price + '', 0)} else {this.totalPrice -= parseInt(this.goodsItem.price + '', 0)}})Image(this.goodsItem.imgSrc).objectFit(ImageFit.ScaleDown).height(130).width(100).renderMode(ImageRenderMode.Original)Column() {Text(this.goodsItem.title).fontSize(18)Text('¥' + this.goodsItem.price).fontSize(18).fontColor(Color.Red)}.margin({left:40})}.height(100).width('100%').margin({ left: 20 }).alignItems(VerticalAlign.Center).backgroundColor(Color.White)}
}

4.新建ShopCartBottom组件,ShopCartBottom组件效果图如下:

代码如下:

@Component
struct ShopCartBottom {@Consume totalPrice: numberbuild() {Row() {Text('Total:  ¥' + this.totalPrice).fontColor(Color.Red).fontSize(18).margin({ left: 20 }).width(150)Text('Check Out').fontColor(Color.Black).fontSize(18).margin({ right: 20, left: 180 }).onClick(() => {prompt.showToast({message: 'Checking Out',duration: 10,bottom: 100})})}.height(30).width('100%').backgroundColor('#FF7FFFD4').alignItems(VerticalAlign.Bottom)}
}

构建我的页签

从上面效果图可以看出,主界面我的页签主要由下面四部分组成:

  1. 顶部的水平布局。
  2. 顶部下面的文本加数字的水平List。
  3. My Transactio模块,图片加文本的水平List。
  4. More模块,图片加文本的Grid。

在本任务中,我们构建主页我的页签,主要可以划分成下面几步:

  1. 在pages目录下面新建一个ETS Page 命名为MyPage.ets,在config.json文件pages属性中也会自动添加“pages/MyPage”页面路由。
  2. 在MyPage.ets文件中添加入口组件(MyInfo),组件内容如下:
import {getMenu,getTrans,getMore} from '../model/GoodsDataModels'
import {Menu, ImageItem} from '../model/Menu'
@Entry
@Component
export struct MyInfo {build() {Column() {Row() {Image($r('app.media.icon_user')).objectFit(ImageFit.Contain).height(50).width(50).margin({left:10}).renderMode(ImageRenderMode.Original)Column() {Text('John Doe').fontSize(15)Text('Member Name : John Doe                     >').fontSize(15)}.height(60).margin({ left: 20, top: 10 }).alignItems(HorizontalAlign.Start)}TopList()MyTransList()MoreGrid()}.alignItems(HorizontalAlign.Start).width('100%').height('100%').flexGrow(1)}
}

入口组件中还包含TopList,MyTransList和MoreGrid三个子组件。

3.在MyPage.ets文件中新建TopList组件,效果图如下:

代码如下:

@Component
struct TopList {private menus: Menu1[] = getMenu()build() {Row() {List() {ForEach(this.menus, item => {ListItem() {MenuItem({ menu: item })}}, item => item.id.toString())}.height('100%').width('100%').margin({ top: 5,left: 10}).edgeEffect(EdgeEffect.None).listDirection(Axis.Horizontal)}.width('100%').height(50)}
}

getMenu()方法在上文中已有定义,是获取菜单列表的方法,TopList的子组件MenuItem内容如下:

@Component
struct MenuItem {private menu: Menu1build() {Column() {Text(this.menu.title).fontSize(15)Text(this.menu.num + '').fontSize(13)}.height(50).width(100).margin({ left: 8, right: 8 }).alignItems(HorizontalAlign.Start).backgroundColor(Color.White)}
}

4.在MyPage.ets文件中新建MyTransList组件和MoreGrid组件,MyTransList组件效果如如下:

代码如下:

@Component
struct MyTransList {private imageItems: ImageItem[] = getTrans()build() {Column() {Text('My Transaction').fontSize(20).margin({ left: 10 }).width('100%').height(30)Row() {List() {ForEach(this.imageItems, item => {ListItem() {DataItem({ imageItem: item })}}, item => item.id.toString())}.height(70).width('100%').edgeEffect(EdgeEffect.None).margin({ top: 5 }).padding({ left: 16, right: 16 }).listDirection(Axis.Horizontal)}}.height(120)}
}

MoreGrid组件效果图如下:

代码如下:

@Component
struct MoreGrid {private gridRowTemplate: string = ''private imageItems: ImageItem[] = getMore()private heightValue: numberaboutToAppear() {var rows = Math.round(this.imageItems.length / 3);this.gridRowTemplate = '1fr '.repeat(rows);this.heightValue = rows * 75;}build() {Column() {Text('More').fontSize(20).margin({ left: 10 }).width('100%').height(30)Scroll() {Grid() {ForEach(this.imageItems, (item: ImageItem) => {GridItem() {DataItem({ imageItem: item })}}, (item: ImageItem) => item.id.toString())}.rowsTemplate(this.gridRowTemplate).columnsTemplate('1fr 1fr 1fr').columnsGap(8).rowsGap(8).height(this.heightValue)}.padding({ left: 16, right: 16 })}.height(400)}
}

在MyTransList和MoreGrid组件中都包含子组件DataItem,为避免的重复代码,可以把多次要用到的结构体组件化,这里的结构体就是图片加上文本的上下结构体,DataItem组件内容如下:

@Component
struct DataItem {private imageItem: ImageItembuild() {Column() {Image(this.imageItem.imageSrc).objectFit(ImageFit.Contain).height(50).width(50).renderMode(ImageRenderMode.Original)Text(this.imageItem.title).fontSize(15)}.height(70).width(150).margin({ left: 10, right: 10 }).backgroundColor(Color.White)}
}

构建商品详情页面

从上面效果图可以看出,商品详情页面主要由下面五部分组成:

  1. 顶部的返回栏。
  2. Swiper组件。
  3. 中间多个Text组件组成的布局。
  4. 参数列表。
  5. 底部的Buy。

在本任务中,把上面每一部分都封装成一个组件,然后再放到入口组件内,当点击顶部返回图标时返回到主页面的商品列表页签,点击底部Buy时,会触发进度条弹窗

  1. 在pages目录下面新建一个ETS Page, 命名为ShoppingDetail.ets,config.json文件pages属性中也会自动添加“pages/ShoppingDetail”页面路由。
  2. 在ShoppingDetail.ets文件中创建入口组件,组件内容如下:
@Entry
@Component
struct ShoppingDetail {private arsItems: ArsData[] = getArs()build() {Column() {DetailTop()Scroll() {Column() {SwiperTop()DetailText()DetailArsList({ arsItems: this.arsItems })Image($r('app.media.computer1')).height(220).width('100%').margin({ top: 30 })Image($r('app.media.computer2')).height(220).width('100%').margin({ top: 30 })Image($r('app.media.computer3')).height(220).width('100%').margin({ top: 30 })Image($r('app.media.computer4')).height(220).width('100%').margin({ top: 30 })Image($r('app.media.computer5')).height(220).width('100%').margin({ top: 30 })Image($r('app.media.computer6')).height(220).width('100%').margin({ top: 30 })}.width('100%').flexGrow(1)}.scrollable(ScrollDirection.Vertical)DetailBottom()}.height('90%').width('100%')}
}

其中顶部DetailTop组件效果图如下:

代码如下:

@Component
struct DetailTop {build() {Column() {Row() {Image($r('app.media.icon_return')).height(40).width(40).margin({left: 20}).onClick(() => {router.push({uri: "pages/HomePage"})})}.width('100%').height(35).backgroundColor('#FF87CEEB')}.width('100%').height(40)}
}

3.SwiperTop组件效果图如下:

代码如下:

@Component
struct SwiperTop {build() {Column() {Swiper() {Image($r('app.media.computer1')).height(220).width('100%')Image($r('app.media.computer2')).height(220).width('100%')Image($r('app.media.computer3')).height(220).width('100%')Image($r('app.media.computer4')).height(220).width('100%')Image($r('app.media.computer5')).height(220).width('100%')Image($r('app.media.computer6')).height(220).width('100%')}.index(0).autoPlay(true).interval(3000).indicator(true).loop(true).height(250).width('100%')}.height(250).width('100%')}
}

4.DetailText组件效果图如下:

代码如下:

@Component
struct DetailText {build() {Column() {Row() {Image($r('app.media.icon_promotion')).objectFit(ImageFit.Contain).height(30).width(30).margin({ left: 10 })Text('Special Offer: ¥9999').fontColor(Color.White).fontSize(20).margin({ left: 10 })}.width('100%').height(35).backgroundColor(Color.Red)Column() {Text('New Arrival: HUAWEI MateBook X Pro 2021').fontSize(18).margin({ left: 10 }).alignSelf(ItemAlign.Start)Text('13.9-Inch, 11th Gen Intel® Core™ i7, 16 GB of Memory, 512 GB of Storage, Ultra-slim Business Laptop, 3K FullView Display, Multi-screen Collaboration, Emerald Green').fontSize(14).margin({ left: 10 })Row() {Image($r('app.media.icon_buy')).objectFit(ImageFit.Contain).height(30).width(30).margin({ left: 10 })Text('Limited offer').fontSize(15).fontColor(Color.Red).margin({ left: 100 })}.backgroundColor(Color.Pink).width('100%').height(45).margin({ top: 10 })Text(' Shipment:         2-day shipping').fontSize(13).fontColor(Color.Red).margin({ left: 10, top: 5 }).alignSelf(ItemAlign.Start)Text('    Ship To:         Hubei,Wuhan,China').fontSize(13).fontColor(Color.Red).margin({ left: 10, top: 5 }).alignSelf(ItemAlign.Start).onClick(() => {prompt.showDialog({ title: 'select address', })})Text('Guarantee:         Genuine guaranteed').fontSize(13).margin({ left: 10, top: 5 }).alignSelf(ItemAlign.Start)}.height(170).width('100%')}.height(180).width('100%')}
}

DetailArsList组件效果图如下:

代码如下:

@Component
struct DetailArsList{private arsItems: ArsData[]build() {Scroll() {Column() {List() {ForEach(this.arsItems, item => {ListItem() {ArsListItem({ arsItem: item })}}, item => item.id.toString())}.height('100%').width('100%').margin({ top: 5 }).listDirection(Axis.Vertical)}.height(200)}}
}

ArsListItem组件代码如下:

@Component
struct ArsListItem {private arsItem: ArsDatabuild() {Row() {Text(this.arsItem.title + " :").fontSize(11).margin({ left: 20 }).flexGrow(1)Text(this.arsItem.content).fontSize(11).margin({ right: 20 })}.height(14).width('100%').backgroundColor(Color.White)}
}

5.DetailBottom组件效果图如下:

代码如下:

@Component
struct DetailBottom {@Provideprivate value: number= 1dialogController: CustomDialogController = new CustomDialogController({builder: DialogExample({ action: this.onAccept }),cancel: this.existApp,autoCancel: true});onAccept() {}existApp() {}build() {Column() {Text('Buy').width(40).height(25).fontSize(20).fontColor(Color.White).onClick(() => {this.value = 1this.dialogController.open()})}.alignItems(HorizontalAlign.Center).backgroundColor(Color.Red).width('100%').height('10%')}
}

DialogExample自定义弹窗组件效果图如下:

代码如下:

@CustomDialog
struct DialogExample {@Consumeprivate value: numbercontroller: CustomDialogController;action: () => void;build() {Column() {Progress({ value: this.value++ >= 100 ? 100 : this.value, total: 100, style: ProgressStyle.Capsule }).height(50).width(100).margin({ top: 5 })}.height(60).width(100)}
}

相关概念与参考

API 参考

  1. Tabs组件
  2. CustomDialog自定义弹窗
  3. List组件
  4. Grid组件
  5. Image组件
  6. Button组件
  7. Text组件
  8. Progress组件
  9. Navigator组件
  10. TabContent组件
  11. Row组件
  12. Column组件
  13. Flex组件
  14. Scroll组件
  15. Navigation组件

总结

本篇CodeLab灵活使用了一些组件来实现页面效果:

  1. 使用Tabs组件完成商品分类。
  2. 使用List组件完成商品列表、图片列表、参数列表等。
  3. 使用Swiper组件完成图片的循环轮播。
  4. 使用Toggle组件完成购物车商品的选择。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频》

HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等.....视频教程

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

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

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

一、入门必看

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

二、HarmonyOS 概念

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

三、如何快速入门?《做鸿蒙应用开发到底学习些啥?》

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

四、开发基础知识

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

五、基于ArkTS 开发

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序被删除的文件一编译又回来了

一开始创建错了位置&#xff0c;就想着删除文件重新创建&#xff0c;但是没想到每次重新编译的时候&#xff0c;之前被删除的js、wsml文件就又回来了&#xff0c;后来发现是我在app.json中的pages里面的代码没有被删除。 因为我最开始创建错了&#xff0c;快捷创建了页面&#…

010——服务器开发环境搭建及开发方法(下)

目录 三、 第一个驱动程序 四、 buildroot 4.1 制作根文件系统 4.2 buildroot使用 五、 uboot 009——服务器开发环境搭建及开发方法&#xff08;上&#xff09;-CSDN博客 三、 第一个驱动程序 # 1. 使用不同的开发板内核时, 一定要修改KERN_DIR # 2. KERN_DIR中的内核要…

如何使用OpenHarmony实现视频暂停、播放、切换、倍速播放

介绍 本篇Codelab使用ArkTS语言实现视频播放器&#xff0c;主要包括主页面和视频播放页面&#xff0c;我们将一起完成以下功能&#xff1a; 获取本地视频和网络视频。通过AVPlayer进行视频播放。通过手势调节屏幕亮度和视频播放音量。 相关概念 AVPlayer&#xff1a;播放管理…

Kafka重要配置参数全面解读(重要)

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Kafka重要配置参数全面解读(重要 前言auto.create.topics.enableauto.leader.rebalance.enablelog.retention.{hour|minutes|ms}offsets.topic.num.partitions 和 offsets.topic.replication.factorlo…

Linux(3)软件安装-Centos 8.1安装-硬盘分区方案对比-linux上运行jar包-File上传下载

四、软件安装 1、Centos 8.1安装 1.1 安装过程 1、下载 CentOS 8.1 ISO 镜像文件 访问 CentOS 官方网站的下载页面。选择适当的版本&#xff0c;例如 CentOS Linux 8.1 (Linux Kernel 5.10.0-36)。根据您的硬件架构下载对应的 ISO 镜像文件&#xff08;如 CentOS-8.1-x86_6…

k8s 如何获取加入节点命名

当k8s集群初始化成功的时候&#xff0c;就会出现 加入节点 的命令如下&#xff1a; 但是如果忘记了就需要找回这条命令了。 kubeadm join 的命令格式如下&#xff1a;kubeadm join --token <token> --discovery-token-ca-cert-hash sha256:<hash>--token 令牌--…

如何在极狐GitLab 自定义 Pages 域名、SSL/TLS 证书

本文作者&#xff1a;徐晓伟 GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 本文主要讲述了在极狐GitLab 用户…

数据结构(六)——图

六、图 6.1 图的基本概念 图的定义 图&#xff1a;图G由顶点集V和边集E组成&#xff0c;记为G (V, E)&#xff0c;其中V(G)表示图G中顶点的有限非空集&#xff1b;E(G) 表示图G中顶点之间的关系&#xff08;边&#xff09;集合。若V {v1, v2, … , vn}&#xff0c;则用|V|…

为什么Python不适合写游戏?

知乎上有热门个问题&#xff1a;Python 能写游戏吗&#xff1f;有没有什么开源项目&#xff1f; Python可以开发游戏&#xff0c;但不是好的选择 Python作为脚本语言&#xff0c;一般很少用来开发游戏&#xff0c;但也有不少大型游戏有Python的身影&#xff0c;比如&#xff1…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之九 简单闪烁效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之九 简单闪烁效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之九 简单闪烁效果 一、简单介绍 二、简单闪烁效果实现原理 三、简单闪烁效果案例实现简单步骤 四、注意事项 一、简单…

OpenPLC_Editor 在Ubuntu 虚拟机安装记录

1. OpenPLC_Editor在虚拟机上费劲的装了一遍&#xff0c;有些东西已经忘了&#xff0c;主要还是python3 的缺失库版本对应问题&#xff0c;OpenPLC_Editor使用python3编译的&#xff0c;虚拟机的Ubuntu 18.4 有2.7和3.6两个版本&#xff0c;所以需要注意。 2. OpenPLC_Editor …

day72Html

常用标签&#xff1a; 分类&#xff1a; 块级标签&#xff1a;独立成行 行级标签&#xff1a;不独立成行&#xff0c;同一行可放多个行级标 注意网页显示时&#xff0c;忽略空白字符,(回车符&#xff0c;空格&#xff0c;tab制表符&#xff09; 一&#xff09;块级标签&#xf…