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

news/2024/4/29 0:39:58/文章来源:https://blog.csdn.net/m0_70749039/article/details/137123114

概述

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.luyixian.cn/news_show_1026844.aspx

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

相关文章

【Nebula笔记】基础操作

目录 一、预备~ 二、基础操作 (一) 图空间 1. 创建图空间 2. 清空图空间 3. 其他 4. FAQ 执行DROP SPACE语句删除图空间后&#xff0c;为什么磁盘的大小没变化&#xff1f; (二) 点类型 1. 创建Tag 2. 删除Tag 3. 更新Tag 4. 其他 (三) 边类型 1. 创建Edge type…

ubuntu系统下如何使用vscode编译和调试#小白入门#

编程环境&#xff1a;ubuntu系统为18.04.1&#xff0c;vscode版本为1.66.2 一、VSCode切换中文显示&#xff1a; 1、vscode安装完成后启动,在左侧externsions中搜索“简体中文”插件&#xff0c;并完成安装&#xff1a; 2、选择右下角齿轮形状的"Manage"&#xff…

自然指数函数e^x与欧拉数e (下)

自然指数函数e^x与欧拉数e Part I: 如何找到欧拉数e 上一篇文章停在了“应该存在一个b&#xff0c;使得指数函数b^x在x0处的导数为1。且该指数函数在任意一处的导数都等于当前位置的函数值”。根据前面所知道的&#xff0c;可以用数学公式列出以下一些已知条件&#xff1a; &am…

Go语言学习Day5:函数(下)

名人说&#xff1a;莫愁千里路&#xff0c;自有到来风。 ——钱珝 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、本质、数据类型与延迟函数①函数的本质②函数的数据类型③defer延迟函数 2、匿名、回调函数与闭…

Go——map操作及原理

一.map介绍和使用 map是一种无序的基于key-value的数据结构&#xff0c;Go语言的map是引用类型&#xff0c;必须初始化才可以使用。 1. 定义 Go语言中&#xff0c;map类型语法如下&#xff1a; map[KeyType]ValueType KeyType表示键类型ValueType表示值类型 map类型的变量默认…

班级综合测评管理系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 目录 1. …

docker 的网络管理

docker应用自带了三种类型的网络&#xff0c;然后我们自己也能自定义网络 roottest-virtual-machine:~# docker network ls NETWORK ID NAME DRIVER SCOPE 4c3e28760cff bridge bridge local afd1493dc119 host host local 5f200e2eaf22 n…

AOP切入点表达式基本格式

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 官方地址 https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/pointcuts.html AOP切入点表达式基本格式如下&#xff1a; execution(modifiers-patte…

Vscode创建php项目

1.安装中文插件&#xff08;可安装可不安装&#xff09; 2.安装主题&#xff08;可安装可不安装&#xff09; 3.安装和php相关的插件 4.打开文件夹 5.路由操作 查看项目中的route路由 浏览器中访问think 隐藏index.php入口文件 访问ThinkPHP5.1开发手册&#xff0c;复制apa…

React-1-jsx基础-事件绑定-样式处理

一.JSX基础-概念和本质 1.1 什么是JSX JSX是JavaScript和XML&#xff08;HTML&#xff09;的缩写&#xff0c;表示在JS代码中编写HTML模版结构,它是React中编写UI模版的方式 优势&#xff1a; 1. HTML的声明式模版写法 2. JS的可编程能力 JSX的本质&#xff1a; JSX并不是标…

[openGL] qt5版本+mingw编译Assimp库+调用

目录 一 版本 二 编译问题 三 CMAKE准备 四 开始编译 4.1 准备Assimp源码 4.2 编译工具准备 4.3 生成Assimp库 4.4 使用Assimp 4.4.1 准备 4.4.2 加载模型 4.4.3 模型效果 一 版本 Assimp官网上已经停止更新截至在3.3.1版本,但是这个版本编译是最稳定的,较新的版本…

WORDPRESS从WORD复制粘贴公式

整合教程&#xff1a;WordPress插件包整合教程 WordPaster支持自动上传本地图片文件&#xff0c;自动上传Word文档中的图片 步骤与效果&#xff1a; 1.打开word文档&#xff0c;复制word文档内容 2.在网页中打开编辑器页面&#xff0c;点击“粘贴本地文件,Word文档”按钮上传…

GBase8a-GDCA认证考试-复习参考题

个人能力有限&#xff0c;正确率97%&#xff08;97分&#xff09;。 请注意甄别&#xff0c;根据所学知识综合判断&#xff0c;欢迎指出错误答案。 欢迎学习天津南大通用数据技术股份有限公司|GBASE-致力于成为用户最信赖的数据库产品供应商 免费参加认证培训&#xff1a;为…

Visio中存在问题的解决方法

公式缩放 mathtype公式在visio缩放之后&#xff0c;出现了变形。 解决方法&#xff1a;每次输入公式都通过 插入->对象->mathType Equation 新建一个公式。可以避免 注&#xff1a;网上有的说在word中使用mathtype编写公式&#xff0c;之后复制到visio中。 插入波形 选择…

Java的IDEA的工程管理

模块和包的图标&#xff1a; 举个例子&#xff1a; IDEA中创建包&#xff1a; 如图所示&#xff0c;com.LBJ的意思是在com包中创建子包LBJ 参见&#xff1a; IDEA中项目、模块和包的关系_idea中模块和项目-CSDN博客

应用层协议之DNS协议

一.应用层协议的相关数据传输格式 1.文本字符串格式 应用层主要是自定义协议&#xff0c;以点外卖为例&#xff1a; 客户点开软件&#xff0c;就是应用程序和服务器之间进行网络通信交互。请求和响应可以如下设置 请求&#xff1a;用户信息&#xff0c;位置信息&#xff0c…

Vue模块化开发步骤—遇到的问题—解决办法

目录 1.npm install webpack -g 2.npm install -g vue/cli-init 3.初始化vue项目 4.启动vue项目 Vscode初建Vue时几个需要注意的问题-CSDN博客 1.npm install webpack -g 全局安装webpack 直接命令提示符运行改指令会报错&#xff0c;operation not permitted 注意&#…

【QT入门】 Qt代码创建布局之水平布局、竖直布局详解

往期回顾&#xff1a; 【QT入门】 Qt实现自定义信号-CSDN博客 【QT入门】 Qt自定义信号后跨线程发送信号-CSDN博客 【QT入门】 Qt内存管理机制详解-CSDN博客 【QT入门】 Qt代码创建布局之水平布局、竖直布局详解 先看两个问题&#xff1a; 1、ui设计器设计界面很方便&#xf…

1学习使用axios

一、axios介绍&#xff1a; axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;用于浏览器和 Node.js。它提供了一种简单的方法来发送 HTTP 请求&#xff0c;并且具有很多实用的功能&#xff0c;使得网络请求变得更加方便和可靠。 以下是 axios 的一些主要特点和功能&…

python判断当前日期是全年哪一天

设计者&#xff1a;ISDF 版本&#xff1a;v3..0 日期&#xff1a;04/01/2019设计者&#xff1a;ISDF 版本&#xff1a;v4..0 日期&#xff1a;03/27/2024 import datetime#闰年判断函数 def ys_leep_year(year):ys_leep Falseif (year % 400 0) or ((year % 4 0) and (year …