回复
     157. [HarmonyOS NEXT 实战案例一:Grid] 基础网格布局:打造精美电商商品列表 原创
全栈若城
 发布于 2025-6-30 15:58
 浏览
 0收藏
[HarmonyOS NEXT 实战案例一:Grid] 基础网格布局:打造精美电商商品列表
项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
![157. [HarmonyOS NEXT 实战案例一:Grid] 基础网格布局:打造精美电商商品列表-鸿蒙开发者社区 157. [HarmonyOS NEXT 实战案例一:Grid] 基础网格布局:打造精美电商商品列表-鸿蒙开发者社区](https://dl-harmonyos.51cto.com/images/202506/99684902024402735cf1222b117dd173e7d92f.png?x-oss-process=image/resize,w_373,h_597)
1. Grid组件概述
在HarmonyOS NEXT的ArkUI框架中,Grid组件是一种强大的网格容器,它与GridItem子组件一起使用,可以创建灵活的网格布局。网格布局是由"行"和"列"分割的单元格组成,通过指定"项目"所在的单元格,可以实现各种各样的布局效果。
1.1 Grid与GridItem的关系
- Grid:网格容器组件,用于设置网格布局相关参数
 - GridItem:网格子项组件,定义子组件相关特征
 - Grid的子组件必须是GridItem组件
 
1.2 Grid组件的主要特性
| 特性 | 描述 | 
|---|---|
| 自定义行列数 | 可以通过rowsTemplate和columnsTemplate属性设置网格的行数和列数 | 
| 尺寸占比控制 | 可以控制每行每列的尺寸占比 | 
| 子组件跨行列 | 可以设置子组件横跨几行或几列 | 
| 布局方向 | 支持垂直和水平布局 | 
| 间距控制 | 可以设置行间距和列间距 | 
| 滚动能力 | 支持构建可滚动的网格布局 | 
2. 电商商品列表实战
在本案例中,我们将使用Grid和GridItem组件创建一个电商应用的商品列表页面,展示Apple Store的产品。
2.1 页面结构概览
我们的电商商品列表页面包含以下几个部分:
- 顶部标题栏:显示应用名称和操作按钮
 - 分类标签:显示商品分类和查看更多选项
 - 商品网格:使用Grid和GridItem展示商品信息
 - 底部导航栏:提供应用的主要导航选项
 
2.2 数据模型定义
首先,我们定义商品数据模型:
interface Product {
    id: number,
    name: string,
    price: number,
    image: Resource,
    discount?: number
}
然后,创建商品数据数组:
@State products:Product[] = [
    { id: 1, name: 'iPhone 15 Pro', price: 7999, image: $r('app.media.phone'), discount: 10 },
    { id: 2, name: 'MacBook Pro', price: 12999, image: $r('app.media.big15') },
    { id: 3, name: 'iPad Air', price: 4399, image: $r('app.media.big14'), discount: 5 },
    // 更多商品...
]
2.3 顶部标题栏实现
// 顶部标题栏
Row() {
    Text('Apple Store')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .fontColor('#1D1D1F')
    Blank()
    Button() {
        Image($r('app.media.search_icon'))
            .width(24)
            .height(24)
    }
    .width(40)
    .height(40)
    .borderRadius(20)
    .backgroundColor('#F5F5F7')
    Button() {
        Image($r('app.media.cart_icon'))
            .width(24)
            .height(24)
    }
    .width(40)
    .height(40)
    .borderRadius(20)
    .backgroundColor('#F5F5F7')
    .margin({ left: 12 })
}
.width('100%')
.padding({ left: 20, right: 20, top: 10, bottom: 10 })
.backgroundColor('#FFFFFF')
2.4 分类标签实现
// 分类标签
Row() {
    Text('热门商品')
        .fontSize(18)
        .fontWeight(FontWeight.Medium)
        .fontColor('#1D1D1F')
    Blank()
    Text('查看全部')
        .fontSize(14)
        .fontColor('#007AFF')
}
.width('100%')
.padding({ left: 20, right: 20, top: 16, bottom: 16 })
.backgroundColor('#FFFFFF')
3. Grid网格布局实现
3.1 Grid容器配置
Grid() {
    // GridItem子项...
}
.columnsTemplate('1fr 1fr') // 两列布局
.columnsGap(16)             // 列间距
.rowsGap(16)                // 行间距
.width('100%')
.layoutWeight(1)
.padding({ left: 20, right: 20, bottom: 20 })
.backgroundColor('#F2F2F7')
在这个配置中:
columnsTemplate('1fr 1fr'):设置两列布局,每列占比相等columnsGap(16):设置列间距为16vprowsGap(16):设置行间距为16vp
3.2 GridItem商品卡片实现
我们使用ForEach循环遍历商品数据,为每个商品创建一个GridItem:
ForEach(this.products, (product:Product) => {
    GridItem() {
        Column() {
            // 商品图片容器
            Stack({ alignContent: Alignment.TopEnd }) {
                Image(product.image)
                    .width('100%')
                    .height(120)
                    .objectFit(ImageFit.Contain)
                    .backgroundColor('#F8F8F8')
                    .borderRadius(12)
                // 折扣标签
                if (product.discount) {
                    Text(`-${product.discount}%`)
                        .fontSize(12)
                        .fontColor('#FFFFFF')
                        .backgroundColor('#FF3B30')
                        .padding({ left: 8, right: 8, top: 4, bottom: 4 })
                        .borderRadius(8)
                        .margin({ top: 8, right: 8 })
                }
            }
            .width('100%')
            .height(120)
            // 商品信息
            Column() {
                Text(product.name)
                    .fontSize(14)
                    .fontWeight(FontWeight.Medium)
                    .fontColor('#1D1D1F')
                    .maxLines(2)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
                    .margin({ top: 12 })
                Row() {
                    if (product.discount) {
                        Text(`¥${(product.price * (100 - product.discount) / 100).toFixed(0)}`)
                            .fontSize(16)
                            .fontWeight(FontWeight.Bold)
                            .fontColor('#FF3B30')
                        Text(`¥${product.price}`)
                            .fontSize(12)
                            .fontColor('#8E8E93')
                            .decoration({ type: TextDecorationType.LineThrough })
                            .margin({ left: 4 })
                    } else {
                        Text(`¥${product.price}`)
                            .fontSize(16)
                            .fontWeight(FontWeight.Bold)
                            .fontColor('#1D1D1F')
                    }
                    Blank()
                    Button() {
                        Image($r('app.media.add_icon'))
                            .width(16)
                            .height(16)
                            .fillColor('#FFFFFF')
                    }
                    .width(28)
                    .height(28)
                    .borderRadius(14)
                    .backgroundColor('#007AFF')
                }
                .width('100%')
                .margin({ top: 8 })
            }
            .alignItems(HorizontalAlign.Start)
            .width('100%')
        }
        .width('100%')
        .padding(12)
        .backgroundColor('#FFFFFF')
        .borderRadius(16)
        .shadow({
            radius: 8,
            color: 'rgba(0, 0, 0, 0.1)',
            offsetX: 0,
            offsetY: 2
        })
    }
    .onClick(() => {
        console.log(`点击了商品: ${product.name}`)
    })
})
每个GridItem包含:
- 商品图片:使用Stack布局,支持在右上角显示折扣标签
 - 商品名称:支持最多显示两行,超出部分使用省略号
 - 价格信息:显示原价和折扣价(如果有折扣)
 - 添加按钮:用于将商品添加到购物车
 
3.3 底部导航栏实现
// 底部导航栏
Row() {
    Column() {
        Image($r('app.media.home_icon'))
            .width(24)
            .height(24)
            .fillColor('#007AFF')
        Text('首页')
            .fontSize(12)
            .fontColor('#007AFF')
            .margin({ top: 4 })
    }
    .layoutWeight(1)
    // 其他导航项...
}
.width('100%')
.height(60)
.backgroundColor('#FFFFFF')
.borderColor('#E5E5EA')
.borderWidth({ top: 1 })
4. Grid组件的关键属性详解
4.1 行列设置
| 属性 | 描述 | 示例 | 
|---|---|---|
| columnsTemplate | 设置网格布局的列数和每列的尺寸占比 | '1fr 2fr':两列布局,第二列是第一列的两倍宽 | 
| rowsTemplate | 设置网格布局的行数和每行的尺寸占比 | '1fr 1fr 1fr':三行布局,每行高度相等 | 
| columnsGap | 设置列间距 | columnsGap(16) | 
| rowsGap | 设置行间距 | rowsGap(16) | 
4.2 GridItem定位属性
| 属性 | 描述 | 示例 | 
|---|---|---|
| rowStart | 设置起始行号 | rowStart(1) | 
| rowEnd | 设置结束行号 | rowEnd(3) | 
| columnStart | 设置起始列号 | columnStart(2) | 
| columnEnd | 设置结束列号 | columnEnd(4) | 
4.3 布局方向
Grid() {
  // 子项...
}
.layoutDirection(GridDirection.Row) // 水平方向布局
GridDirection枚举值:
GridDirection.Row:水平方向布局(默认)GridDirection.Column:垂直方向布局
5. 布局技巧与最佳实践
5.1 响应式网格布局
在不同屏幕尺寸下,可以动态调整列数:
// 根据屏幕宽度调整列数
let columns = '1fr 1fr';
if (screenWidth >= 600) {
  columns = '1fr 1fr 1fr';
}
if (screenWidth >= 840) {
  columns = '1fr 1fr 1fr 1fr';
}
Grid() {
  // 子项...
}
.columnsTemplate(columns)
5.2 商品卡片设计技巧
- 阴影效果:使用shadow属性为卡片添加阴影,增强立体感
 - 圆角处理:为卡片和图片添加borderRadius,使界面更加圆润
 - 折扣标签:使用条件渲染显示折扣标签,突出促销商品
 - 文本溢出处理:使用maxLines和textOverflow处理长文本
 
5.3 网格间距优化
适当的网格间距可以提升用户体验:
- 列间距(columnsGap):通常设置为12-20vp
 - 行间距(rowsGap):通常设置为16-24vp
 
6. 总结
在本教程中,我们学习了如何使用HarmonyOS NEXT的Grid和GridItem组件创建一个电商商品列表页面。我们详细讲解了Grid组件的基本概念、主要属性和使用方法,以及如何通过合理的布局和样式设计,打造美观实用的商品卡片。
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
     
        赞
        
 
        收藏 
      
 回复
  相关推荐
 



















