鸿蒙 APP 开发:ArkUI 组件库详解与常用组件实战
鸿蒙 ArkUI 组件库详解与常用组件实战。内容涵盖组件分类、核心特性及弹性布局与网格布局应用。通过构建电商首页示例,演示轮播图、分类导航、商品列表及底部导航栏的代码实现。包含数据模型定义、自定义组件编写、交互效果优化(悬停、点击动画)及响应式布局验证。

鸿蒙 ArkUI 组件库详解与常用组件实战。内容涵盖组件分类、核心特性及弹性布局与网格布局应用。通过构建电商首页示例,演示轮播图、分类导航、商品列表及底部导航栏的代码实现。包含数据模型定义、自定义组件编写、交互效果优化(悬停、点击动画)及响应式布局验证。


本文承接基础篇,复用项目架构,为后续电商购物车全栈项目铺垫核心组件基础。
学习目标:
学习重点:
HarmonyOS Next 的 ArkUI 组件库分为基础组件和高级组件:
| 分类 | 组件示例 |
|---|---|
| 基础组件 | Text、Image、Button、Input、TextArea、Checkbox、Radio、Slider、Switch |
| 容器组件 | Column、Row、Flex、Grid、GridItem、List、ListItem、Stack |
| 高级组件 | Swiper(轮播图)、TabContent(标签页)、Carousel(卡片轮播)、WaterFlow(瀑布流) |
基于基础项目架构,创建一个电商首页组件,包含以下功能:
在 entry/src/main/ets 目录下创建以下文件夹:
components:存放自定义组件;models:存放数据模型;utils:存放工具函数。entry/src/main/ets/models/HomeModel.ets
// 轮播图数据模型
export interface BannerModel {
id: number;
imageUrl: string;
linkUrl: string;
}
// 分类导航数据模型
export interface CategoryModel {
id: number;
name: string;
iconUrl: string;
}
// 商品数据模型
export interface GoodsModel {
id: number;
name: string;
imageUrl: string;
price: number;
originalPrice: number;
sales: number;
}
// 底部导航栏数据模型
export interface TabBarModel {
id: number;
name: string;
iconUrl: string;
selectedIconUrl: string;
pageUrl: string;
}
entry/src/main/ets/utils/ImageUtils.ets
// 图片加载工具函数
export function getImageUrl(imagePath: string): string {
return `$r('app.media.${imagePath}')`;
}
entry/src/main/ets/models/HomeData.ets
import { BannerModel, CategoryModel, GoodsModel, TabBarModel } from './HomeModel';
import { getImageUrl } from '../utils/ImageUtils';
// 轮播图模拟数据
export const bannerData: Array<BannerModel> = [
{ id: 1, imageUrl: getImageUrl('banner1'), linkUrl: 'pages/ProductDetailPage' },
{ id: 2, imageUrl: getImageUrl('banner2'), linkUrl: 'pages/ProductDetailPage' },
{ id: 3, imageUrl: getImageUrl('banner3'), linkUrl: 'pages/ProductDetailPage' }
];
// 分类导航模拟数据
export const categoryData: Array<CategoryModel> = [
{ id: 1, name: '手机', iconUrl: getImageUrl('category1') },
{ id: 2, name: '平板', iconUrl: getImageUrl('category2') },
{ id: 3, name: '笔记本', iconUrl: getImageUrl('category3') },
{ id: 4, name: '智能穿戴', iconUrl: getImageUrl('category4') },
{ id: 5, name: '家居', iconUrl: getImageUrl('category5') },
{ id: 6, name: '出行', iconUrl: getImageUrl('category6') }
];
// 商品模拟数据
export const goodsData: Array<GoodsModel> = [
{ id: 1, name: '华为 Mate 60 Pro', imageUrl: getImageUrl('goods1'), price: 6999, originalPrice: 7999, sales: 12345 },
{ id: 2, name: '华为 P60 Pro', imageUrl: getImageUrl('goods2'), price: 5999, originalPrice: 6999, sales: 8765 },
{ id: 3, name: '华为 nova 12 Pro', imageUrl: getImageUrl('goods3'), price: 3999, originalPrice: 4999, sales: 6543 },
{ id: 4, name: '华为 MateBook X Pro', imageUrl: getImageUrl('goods4'), price: 8999, originalPrice: 9999, sales: 4321 },
{ id: 5, name: '华为 Watch GT 4', imageUrl: getImageUrl('goods5'), price: 1499, originalPrice: 1699, sales: 2109 }
];
// 底部导航栏模拟数据
export const tabBarData: Array<TabBarModel> = [
{ id: 1, name: '首页', iconUrl: getImageUrl('tab1'), selectedIconUrl: getImageUrl('tab1_selected'), pageUrl: 'pages/Index' },
{ id: 2, name: '分类', iconUrl: getImageUrl('tab2'), selectedIconUrl: getImageUrl('tab2_selected'), pageUrl: 'pages/CategoryPage' },
{ id: 3, name: '购物车', iconUrl: getImageUrl('tab3'), selectedIconUrl: getImageUrl('tab3_selected'), pageUrl: 'pages/CartPage' },
{ id: 4, name: '我的', iconUrl: getImageUrl('tab4'), selectedIconUrl: getImageUrl('tab4_selected'), pageUrl: 'pages/MyPage' }
];
entry/src/main/ets/components/BannerComponent.ets
import { BannerModel } from '../models/HomeModel';
import router from '@ohos.router';
@Component
export struct BannerComponent {
@Prop data: Array<BannerModel> = [];
build() {
Swiper() {
ForEach(this.data, (item: BannerModel) => {
Image(item.imageUrl).width('100%').height(200).objectFit(ImageFit.Cover).borderRadius(12).onClick(() => {
router.pushUrl({ url: item.linkUrl });
});
}, (item: BannerModel) => item.id.toString());
}.width('100%').height(200).autoPlay(true).indicator({ style: IndicatorStyle.Number, isShow: true, size: 12 }).loop(true).duration(3000);
}
}
entry/src/main/ets/components/CategoryComponent.ets
import { CategoryModel } from '../models/HomeModel';
import router from '@ohos.router';
@Component
export struct CategoryComponent {
@Prop data: Array<CategoryModel> = [];
build() {
Grid() {
ForEach(this.data, (item: CategoryModel) => {
GridItem() {
Column({ space: 8 }) {
Image(item.iconUrl).width(50).height(50).objectFit(ImageFit.Contain);
Text(item.name).fontSize(14).textColor('#666666');
}.width('100%').height('100%').onClick(() => {
router.pushUrl({ url: 'pages/CategoryPage' });
});
}.width('33.33%').height('auto');
}, (item: CategoryModel) => item.id.toString());
}.width('100%').height('auto').columnsTemplate('1fr 1fr 1fr').rowsTemplate('1fr 1fr').columnsGap(20).rowsGap(20);
}
}
entry/src/main/ets/components/GoodsListComponent.ets
import { GoodsModel } from '../models/HomeModel';
import router from '@ohos.router';
@Component
export struct GoodsListComponent {
@Prop data: Array<GoodsModel> = [];
build() {
List({ space: 16 }) {
ForEach(this.data, (item: GoodsModel) => {
ListItem() {
GoodsItemComponent({ goods: item });
}.width('100%').height('auto');
}, (item: GoodsModel) => item.id.toString());
}.width('100%').height('auto').padding(0, 16, 0, 16);
}
}
@Component
struct GoodsItemComponent {
@Prop goods: GoodsModel;
build() {
Column({ space: 12 }) {
// 商品图片
Image(this.goods.imageUrl).width('100%').height(200).objectFit(ImageFit.Cover).borderRadius(12);
// 商品信息
Column({ space: 8 }) {
Text(this.goods.name).fontSize(16).fontWeight(FontWeight.Bold).textColor('#000000').maxLines(2).ellipsis({ overflow: TextOverflow.Ellipsis });
// 价格与销量
Row({ space: 16 }) {
Column({ space: 4 }) {
Text(`¥${this.goods.price}`).fontSize(18).fontWeight(FontWeight.Bold).textColor('#FF0000');
Text(`¥${this.goods.originalPrice}`).fontSize(14).textColor('#999999').decoration({ type: TextDecorationType.LineThrough });
}.alignItems(HorizontalAlign.Start);
Text(`已售${this.goods.sales}`).fontSize(14).textColor('#666666');
}.width('100%').justifyContent(FlexAlign.SpaceBetween);
}.width('100%').alignItems(HorizontalAlign.Start).padding(0, 0, 0, 8);
}.width('100%').height('auto').padding(16).backgroundColor('#FFFFFF').borderRadius(12).onClick(() => {
router.pushUrl({ url: 'pages/ProductDetailPage' });
});
}
}
entry/src/main/ets/components/TabBarComponent.ets
import { TabBarModel } from '../models/HomeModel';
import router from '@ohos.router';
@Component
export struct TabBarComponent {
@Prop data: Array<TabBarModel> = [];
@Prop selectedIndex: number = 0;
build() {
Row({ space: 0 }) {
ForEach(this.data, (item: TabBarModel, index: number) => {
Column({ space: 4 }) {
Image(index === this.selectedIndex ? item.selectedIconUrl : item.iconUrl).width(24).height(24).objectFit(ImageFit.Contain);
Text(item.name).fontSize(12).textColor(index === this.selectedIndex ? '#007DFF' : '#666666');
}.width('25%').height('100%').justifyContent(FlexAlign.Center).onClick(() => {
router.pushUrl({ url: item.pageUrl });
});
}, (item: TabBarModel) => item.id.toString());
}.width('100%').height(56).backgroundColor('#FFFFFF').borderRadius(16, 16, 0, 0).padding(0, 8, 0, 8);
}
}
entry/src/main/ets/pages/Index.ets(替换默认代码)
import { BannerComponent } from '../components/BannerComponent';
import { CategoryComponent } from '../components/CategoryComponent';
import { GoodsListComponent } from '../components/GoodsListComponent';
import { TabBarComponent } from '../components/TabBarComponent';
import { bannerData, categoryData, goodsData, tabBarData } from '../models/HomeData';
@Entry
@Component
struct Index {
@State selectedIndex: number = 0;
build() {
Column({ space: 0 }) {
// 页面内容
Scroll() {
Column({ space: 24 }) {
// 轮播图
BannerComponent({ data: bannerData });
// 分类导航
CategoryComponent({ data: categoryData });
// 热门商品标题
Text('热门商品').fontSize(18).fontWeight(FontWeight.Bold).textColor('#000000').width('100%').padding(0, 0, 0, 16);
// 商品列表
GoodsListComponent({ data: goodsData });
}.width('100%').padding(20);
}.width('100%').height('100%').layoutWeight(1);
// 底部导航栏
TabBarComponent({ data: tabBarData, selectedIndex: this.selectedIndex });
}.width('100%').height('100%').backgroundColor('#F5F5F5');
}
}
为商品列表组件添加悬停动画,提升用户体验:
entry/src/main/ets/components/GoodsListComponent.ets(修改 GoodsItemComponent)
@Component
struct GoodsItemComponent {
@Prop goods: GoodsModel;
@State isHover: boolean = false;
build() {
Column({ space: 12 }) {
// 商品图片
Image(this.goods.imageUrl).width('100%').height(200).objectFit(ImageFit.Cover).borderRadius(12).scale({ x: this.isHover ? 1.05 : 1, y: this.isHover ? 1.05 : 1 }).transition({ duration: 300, curve: Curve.EaseOut });
// 商品信息
// ...
}.width('100%').height('auto').padding(16).backgroundColor('#FFFFFF').borderRadius(12).onClick(() => {
router.pushUrl({ url: 'pages/ProductDetailPage' });
}).onHover(() => {
this.isHover = true;
}).onHoverEnd(() => {
this.isHover = false;
});
}
}
为按钮组件添加点击动画,反馈用户操作:
entry/src/main/ets/components/GoodsListComponent.ets(添加立即购买按钮)
@Component
struct GoodsItemComponent {
@Prop goods: GoodsModel;
@State isHover: boolean = false;
@State isPressed: boolean = false;
build() {
Column({ space: 12 }) {
// 商品图片
// ...
// 商品信息
Column({ space: 8 }) {
// 商品名称
// ...
// 价格与销量
// ...
// 立即购买按钮
Button('立即购买').width('100%').height(48).backgroundColor('#007DFF').onClick(() => {
console.log('点击了立即购买按钮');
}).onPress(() => {
this.isPressed = true;
}).onPressEnd(() => {
this.isPressed = false;
}).scale({ x: this.isPressed ? 0.95 : 1, y: this.isPressed ? 0.95 : 1 }).transition({ duration: 100, curve: Curve.EaseOut });
}.width('100%').alignItems(HorizontalAlign.Start).padding(0, 0, 0, 8);
}.width('100%').height('auto').padding(16).backgroundColor('#FFFFFF').borderRadius(12).onClick(() => {
router.pushUrl({ url: 'pages/ProductDetailPage' });
}).onHover(() => {
this.isHover = true;
}).onHoverEnd(() => {
this.isHover = false;
});
}
}
在 entry/src/main/resources/base/media 目录下添加以下图片资源(图片格式为.png,尺寸符合要求):
banner1.png、banner2.png、banner3.png(轮播图);category1.png、category2.png、category3.png、category4.png、category5.png、category6.png(分类导航);goods1.png、goods2.png、goods3.png、goods4.png、goods5.png(商品列表);tab1.png、tab1_selected.png、tab2.png、tab2_selected.png、tab3.png、tab3_selected.png、tab4.png、tab4_selected.png(底部导航栏)。① 在 DevEco Studio 中点击「Run」按钮; ② 选择调试设备,点击「OK」; ③ 等待编译安装完成,应用会自动在设备上启动。
✅ 轮播图:自动轮播促销活动,点击可跳转; ✅ 分类导航:显示 6 个商品分类,点击可跳转; ✅ 商品列表:显示 5 个热门商品,悬停有动画效果; ✅ 底部导航栏:实现 4 个页面的切换; ✅ 响应式布局:自动适配不同设备尺寸。
本文完成了对 ArkUI 组件库分类与核心特性的理解,演示了 15 个常用 ArkUI 组件的实战应用,构建了一个完整的电商首页组件,并实现了组件交互效果的优化(悬停、点击动画)。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online