项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
电商应用是移动应用开发中的重要场景之一,其中商品详情页是用户了解商品信息、做出购买决策的关键界面。一个设计良好的商品详情页需要清晰展示商品图片、价格、规格等信息,并提供便捷的购买操作。本教程将详细讲解如何使用HarmonyOS NEXT的ColumnSplit
组件构建一个电商商品详情页,通过垂直分割布局将界面分为商品图片区域和商品信息区域。
在本案例中,我们将使用以下HarmonyOS NEXT组件:
组件名称 | 功能描述 |
---|---|
ColumnSplit | 垂直分割布局容器,将界面分为上下两部分 |
Column | 垂直布局容器,用于垂直排列子组件 |
Row | 水平布局容器,用于水平排列子组件 |
Swiper | 轮播图组件,用于展示商品的多张图片 |
Image | 图片组件,用于显示商品图片 |
Text | 文本组件,用于显示商品名称、价格等信息 |
Button | 按钮组件,用于收藏、加入购物车和购买操作 |
ForEach | 循环渲染组件,用于渲染商品规格选项和轮播图 |
Circle | 圆形组件,用于创建轮播图指示器 |
Scroll | 滚动容器,用于在有限空间内展示更多内容 |
Flex | 弹性布局容器,用于灵活排列子组件 |
首先,我们定义了一个名为ECommerceDetailExample
的自定义组件:
@Component
export struct ECommerceDetailExample {
@State currentImageIndex: number = 0
@State selectedSize: string = 'M'
@State quantity: number = 1
@State isFavorite: boolean = false
build() {
// 组件内容
}
}
在这个组件中,我们定义了四个状态变量:
currentImageIndex
:当前显示的商品图片索引selectedSize
:当前选中的商品尺码quantity
:商品数量isFavorite
:是否收藏商品我们使用ColumnSplit
组件作为最外层容器,将界面分为上下两部分:
ColumnSplit() {
// 商品图片展示区
Column() {
// 图片轮播和指示器
}
.height('40%')
// 商品信息区
Column() {
// 商品信息和操作按钮
}
}
.height(600)
ColumnSplit
设置了600的高度,确保整个界面有足够的显示空间。上部分的商品图片展示区占总高度的40%,下部分的商品信息区占剩余高度。
商品图片展示区包含一个轮播图组件和一个图片指示器:
Column() {
Swiper() {
ForEach([
$r('app.media.big19'),
$r('app.media.big18'),
$r('app.media.big17')
], (img: Resource, index: number) => {
Image(img)
.width('100%')
.height(300)
.objectFit(ImageFit.Cover)
})
}
.indicatorStyle({
color: '#ff4757',
selectedColor: '#ff4757'
})
.onChange((index: number) => {
this.currentImageIndex = index
})
// 图片指示器
Row() {
ForEach([0, 1, 2], (index: number) => {
Circle()
.width(8)
.height(8)
.margin(3)
.fill(index === this.currentImageIndex ? '#ff4757' : '#cccccc')
})
}
.margin({ top: 10 })
.justifyContent(FlexAlign.Center)
}
.height('40%')
在这个部分:
Swiper
组件创建一个轮播图,通过ForEach
循环渲染三张商品图片。objectFit(ImageFit.Cover)
确保图片填充整个区域。onChange
事件更新currentImageIndex
状态。Circle
组件表示每张图片,当前显示的图片对应的圆点会高亮显示。商品信息区包含商品标题、价格、规格选择、数量选择、商品详情和底部操作栏:
Column() {
Scroll() {
Column() {
// 商品标题和价格
Row() {
Column() {
Text('男士休闲衬衫')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('夏季新款 透气舒适')
.fontSize(14)
.fontColor('#666666')
}
.layoutWeight(1)
Button(this.isFavorite ? $r('app.media.01') : $r('app.media.02'))
.width(24)
.height(24)
.backgroundColor(Color.Transparent)
.onClick(() => this.isFavorite = !this.isFavorite)
}
.margin({ bottom: 15 })
Text('¥189')
.fontSize(24)
.fontColor('#ff4757')
.margin({ bottom: 20 })
// 商品规格选择
Column() {
Text('尺码')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(['XS', 'S', 'M', 'L', 'XL'], (size: string) => {
Button(size)
.width(60)
.height(40)
.fontSize(14)
.backgroundColor(this.selectedSize === size ? '#ff4757' : '#f5f5f5')
.fontColor(this.selectedSize === size ? '#ffffff' : '#333333')
.margin({ right: 10, bottom: 10 })
.onClick(() => this.selectedSize = size)
})
}
}
.margin({ bottom: 20 })
// 商品数量选择
Column() {
Text('数量')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Row() {
Button('-')
.width(40)
.height(40)
.fontSize(18)
.onClick(() => {
if (this.quantity > 1) this.quantity--
})
Text(this.quantity.toString())
.fontSize(16)
.margin({ left: 15, right: 15 })
.width(40)
.textAlign(TextAlign.Center)
Button('+')
.width(40)
.height(40)
.fontSize(18)
.onClick(() => this.quantity++)
}
}
.margin({ bottom: 20 })
// 商品详情
Column() {
Text('商品详情')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Text('材质: 100%棉\n颜色: 浅蓝色\n款式: 休闲\n季节: 夏季\n洗涤说明: 建议手洗,不可漂白')
.fontSize(14)
.lineHeight(22)
}
.margin({ bottom: 20 })
}
.padding(20)
}
.layoutWeight(1)
// 底部操作栏
Row() {
Button('加入购物车')
.height(50)
.layoutWeight(1)
.backgroundColor('#ff9500')
.fontColor('#ffffff')
Button('立即购买')
.height(50)
.layoutWeight(1)
.backgroundColor('#ff4757')
.fontColor('#ffffff')
.margin({ left: 10 })
}
.padding(10)
.backgroundColor('#ffffff')
.border({
width:{top:1,bottom:0, left:0,right:0},
color:'#eee',
style:{
top:BorderStyle.Solid,
}
})
}
在这个部分:
Scroll
组件创建一个可滚动的区域,确保在内容超出可视区域时用户可以滚动查看。Row
和Column
组合布局,右侧添加了一个收藏按钮,点击可以切换收藏状态。Flex
组件创建一个弹性布局,通过ForEach
循环渲染尺码选项,当前选中的尺码会高亮显示。Row
组件水平排列减少按钮、数量文本和增加按钮,点击按钮可以调整商品数量。Text
组件显示商品的详细信息,通过\n
实现多行文本。layoutWeight
属性使两个按钮平分宽度。使用ColumnSplit
组件可以轻松实现上下分割的布局效果,适合商品详情页这种需要展示图片和详细信息的场景。通过设置子组件的高度比例,可以控制上下两部分的大小关系。
在本案例中,我们使用了多层嵌套的布局结构:
ColumnSplit
,将界面分为上下两部分Column
包含Swiper
和指示器Column
包含Scroll
和底部操作栏Scroll
内部使用Column
垂直排列各个信息区块Row
、Column
、Flex
等组件进行布局这种嵌套布局的方式使得界面结构清晰,各个部分的职责明确。
在商品信息区,我们使用了Scroll
组件使内容可滚动,同时将底部操作栏固定在底部不随内容滚动。这种布局方式在移动应用中非常常见,可以在有限的屏幕空间内展示更多内容,同时保持关键操作按钮始终可见。
在商品规格选择部分,我们使用了Flex
组件创建一个弹性布局,并设置wrap: FlexWrap.Wrap
使得当一行放不下所有选项时会自动换行。这种布局方式适合展示数量不确定的选项,可以根据屏幕宽度自动调整排列。
通过Swiper
组件实现图片轮播,并通过onChange
事件更新当前显示的图片索引:
Swiper()
// ...
.onChange((index: number) => {
this.currentImageIndex = index
})
通过Button
组件的onClick
事件实现规格选择,点击按钮时更新selectedSize
状态:
Button(size)
// ...
.onClick(() => this.selectedSize = size)
通过Button
组件的onClick
事件实现数量调整,点击"+“按钮增加数量,点击”-"按钮减少数量:
Button('-')
// ...
.onClick(() => {
if (this.quantity > 1) this.quantity--
})
Button('+')
// ...
.onClick(() => this.quantity++)
通过Button
组件的onClick
事件实现收藏状态切换,点击按钮时切换isFavorite
状态:
Button(this.isFavorite ? $r('app.media.01') : $r('app.media.02'))
// ...
.onClick(() => this.isFavorite = !this.isFavorite)
在本案例中,我们使用了以下颜色:
#ff4757
(红色),用于价格、选中状态和"立即购买"按钮#ff9500
(橙色),用于"加入购物车"按钮#f5f5f5
(浅灰色),用于未选中的规格按钮#333333
(深灰色)用于主要文本,#666666
(中灰色)用于次要文本这种颜色搭配符合电商应用的视觉风格,突出重要信息和操作按钮。
在布局中,我们使用了一致的间距设置:
这种一致的间距设置使得界面看起来整洁有序。
在本案例中,我们使用了不同的字体大小来区分不同层级的信息:
这种字体大小的层次设置使得用户可以快速识别重要信息。
在本教程中,我们学习了如何使用HarmonyOS NEXT的ColumnSplit
组件构建一个电商商品详情页。通过垂直分割布局,我们将界面分为商品图片区域和商品信息区域,使得界面结构清晰,信息展示合理。
我们还学习了如何使用Swiper
组件实现图片轮播,如何使用Flex
组件创建弹性布局,如何使用Scroll
组件实现内容滚动,以及如何通过状态变量和事件处理实现各种交互功能。
通过本教程,你应该能够理解垂直分割布局在电商商品详情页中的应用,并能够根据自己的需求进行定制和扩展。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有