请添加图片描述
请添加图片描述

一、引言:电商详情页的布局挑战

1.1 商品详情页——移动端最复杂的页面之一

在移动应用开发中,商品详情页(Product Detail Page)是信息密度最高、布局要求最严格的页面类型之一。一个完整的商品详情页通常需要承载以下信息层次:

  • 商品展示层:轮播图、视频、3D 展示
  • 商品信息层:标题、价格、促销标签、评分
  • 规格参数层:品牌、型号、颜色、存储等结构化数据
  • 图文描述层:富文本描述与产品实拍图交替
  • 社交证明层:用户评价、评分、购买记录
  • 行动号召层:收藏、加入购物车、立即购买

这些内容以"从上到下、信息密度递减"的方式排列,用户通过滚动浏览逐步获取信息,最后在底部操作栏完成转化。

1.2 ArkUI 布局系统如何应对

鸿蒙 ArkUI 提供了应对这类复杂页面的完整布局能力:

布局需求 ArkUI 解决方案 核心组件
轮播图 Swiper + Image 容器 + 指示器
分区内容 Scroll + Column 可滚动 + 纵向排列
价格/标签行 Row + Blank 水平分布 + 弹性占位
规格表格 Row + layoutWeight 列宽比例分配
图文混排 文字段落 + 图片交替 Text + Column
底部固定栏 Scroll 外部 Row 固定高度不随滚动

本文将以一个完整的商品详情页 Demo 为例,从零到一剖析如何用 ArkUI 构建电商级详情页布局。

1.3 项目基础信息

本文示例基于以下环境构建:

  • 操作系统:HarmonyOS NEXT 6.1.1(API 24)
  • 开发语言:ArkTS(鸿蒙原生 TypeScript 扩展)
  • UI 框架:ArkUI 声明式 UI
  • 构建工具:Hvigor 6.1.1
  • 开发工具:DevEco Studio

项目在 entry/src/main/ets/pages/ProductDetailDemo.ets 中实现,完整代码 665 行。


二、整体布局架构

2.1 八层纵向结构

商品详情页采用"顶部导航 + 可滚动内容 + 底部固定操作栏"的经典三段式架构:

Column (全屏容器, #F5F5F5 灰色背景)
├── Row                    ① 顶部导航栏(半透明覆盖层)
│   ‹ 返回   商品详情   📤 分享  ⋯ 更多
│
├── Scroll (layoutWeight:1)  ② 可滚动主体(弹性占满)
│   └── Column
│       ├── Column          ③ 商品轮播图(渐变占位 + 指示点)
│       ├── Column          ④ 商品信息白卡
│       │   ├── Text        商品标题
│       │   ├── Row         ¥5,999 + 原价 + 限时优惠
│       │   ├── Row         [满减][免息][换新] 标签行
│       │   └── Row         ⭐4.9 + 月销 + 好评率
│       ├── Column          ⑤ 规格参数白卡
│       │   ├── "📋 规格参数"
│       │   └── 表格 8 行   品牌/型号/颜色/存储/屏幕/处理器/系统/电池
│       ├── Column          ⑥ 图文详情白卡
│       │   ├── Text        描述段落 1
│       │   ├── Column      模拟详情图 🖥️
│       │   ├── Text        描述段落 2
│       │   └── Column      模拟详情图 📷
│       └── Column          ⑦ 用户评价白卡
│           ├── "💬 用户评价" + ⭐4.9 + 3 条
│           ├── Row × 3     王**⭐⭐⭐⭐⭐ + 李**⭐⭐⭐⭐ + 赵**⭐⭐⭐⭐⭐
│           └── Divider 分隔
│
└── Row (height:64, 固定底部) ⑧ 底部操作栏
    🤍收藏  🛒购物车  [加入购物车🟠]  [立即购买🔴]

2.2 固定 + 弹性 + 固定的三段式

这个架构的核心设计模式是"固定 + 弹性 + 固定"(Fixed + Flex + Fixed):

┌────────────────────────────────┐
│        顶部导航栏 (48vp)        │  ← 固定高度,半透明浮层
├────────────────────────────────┤
│                                │
│      Scroll 内容区域            │  ← layoutWeight(1) 弹性占满
│      (layoutWeight:1)          │     用户手势滚动浏览
│                                │
├────────────────────────────────┤
│     底部操作栏 (64vp)           │  ← 固定高度,在 Scroll 外部
│   🤍  🛒  [加入购物车] [购买]   │     吸底不随滚动移动
└────────────────────────────────┘

在 Column 布局中,中间子组件的 layoutWeight(1) 是关键。这告诉 ArkUI 布局引擎:在顶部导航栏和底部操作栏测量完成后,将所有剩余空间分配给 Scroll 组件。

2.3 白卡式分区设计

详情页的内容被划分为多个"白卡"(白色圆角卡片),每个卡片承载一个独立的信息模块:

// 每个分区都是一个独立的 Column 白卡
Column() {
  // 分区内部内容
}
.width('100%')
.padding(16)
.backgroundColor('#FFFFFF')
.margin({ top: 12 })
.borderRadius(16)

这种设计的优势:

  1. 视觉分隔:灰色背景(#F5F5F5)上的白色卡片自然形成视觉分区
  2. 独立构建:每个分区由一个 @Builder 方法独立构建,便于维护
  3. 灵活排序:可以方便地调整分区顺序或增删分区
  4. 统一风格:所有分区共享相同的圆角(16vp)和间距(top:12)

三、商品轮播图:渐变占位 + 指示点

3.1 使用线性渐变模拟商品图

在实际电商应用中,轮播图通常使用 Swiper 组件包裹 Image 来实现。在本 Demo 中,为了展示布局能力而不引入实际图片资源,我们使用 linearGradient 模拟商品图片:

@Builder
buildImageCarousel(): void {
  Column() {
    // 图片占位区
    Column() {
      Text('📱')
        .fontSize(64)
        .opacity(0.6)

      Text('商品主图 ' + (this.currentImageIndex + 1) + ' / ' + this.bannerColors.length)
        .fontSize(14)
        .fontColor('rgba(255,255,255,0.7)')
        .margin({ top: 8 })
    }
    .width('100%')
    .height(320)
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .linearGradient({
      direction: GradientDirection.Bottom,
      colors: [
        [this.bannerColors[this.currentImageIndex], 0],  // 动态顶部色
        ['#1A1A2E', 1]                                     // 固定底部色
      ]
    })

    // 指示点(在底部叠加)
    Row() {
      ForEach(this.bannerColors, (_: string, idx: number) => {
        Column()
          .width(idx === this.currentImageIndex ? 20 : 8)   // 选中态拉长
          .height(4)
          .backgroundColor(
            idx === this.currentImageIndex
              ? '#FFFFFF'                       // 选中:白色
              : 'rgba(255,255,255,0.4)'         // 未选:半透明白
          )
          .borderRadius(2)
          .margin({ left: 3, right: 3 })
          .onClick((): void => {
            this.currentImageIndex = idx;       // 点击切换图片
          })
      })
    }
    .position({ bottom: 16 })
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
  .width('100%')
  .height(320)
}

关键设计要点

  1. 动态渐变颜色this.bannerColors[this.currentImageIndex] 根据当前图片索引切换渐变顶部颜色。四张"图"分别使用蓝(#4A90D9)、绿(#27AE60)、橙(#E67E22)、紫(#8E44AD),模拟不同商品主题色。

  2. 指示点的交互反馈:当前选中指示点宽度为 20vp(拉长),非选中为 8vp(圆形)。颜色从"半透明白"变为"纯白"。用户点击指示点可切换 currentImageIndex,这是一个典型的状态驱动 UI 模式。

  3. position({ bottom: 16 }):指示点使用 position 绝对定位在轮播图底部,不占用 Column 的正常流式布局空间。

3.2 在实际项目中的替换方案

在实际生产环境中,请将渐变占位替换为真正的 Swiper + Image:

// 生产级代码示例
Swiper() {
  ForEach(this.productImages, (imgUrl: string) => {
    Image(imgUrl)
      .width('100%')
      .height(320)
      .objectFit(ImageFit.Cover)
  })
}
.width('100%')
.height(320)
.autoPlay(true)
.interval(4000)
.indicator(true)
.indicatorStyle({ 
  selectedColor: '#FFFFFF', 
  color: 'rgba(255,255,255,0.4)' 
})
.onChange((index: number) => {
  this.currentImageIndex = index;
})

Swiper 组件内置了轮播指示器,通过 indicator(true/false) 控制显隐,通过 indicatorStyle 配置颜色样式。


四、商品信息区:价格 + 标签 + 评分

4.1 价格展示

价格展示是电商详情页的核心转化元素。本 Demo 的价格区域包含三个部分:现价、原价(划线)、促销标签:

Row() {
  // 现价
  Row() {
    Text('¥').fontSize(16).fontColor('#E53935').fontWeight(FontWeight.Bold)
    Text('5,999').fontSize(28).fontColor('#E53935').fontWeight(FontWeight.Bold)
  }
  .alignItems(VerticalAlign.End)   // ¥ 符号与数字底部对齐

  // 原价(删除线)
  Text('¥7,999')
    .fontSize(14)
    .fontColor('#C0C0C0')
    .margin({ left: 8 })
    .decoration({ type: TextDecorationType.LineThrough })

  Blank()

  // 促销标签
  Text('限时优惠')
    .fontSize(11).fontColor('#FFFFFF')
    .backgroundColor('#E53935')
    .borderRadius(8)
    .padding({ left: 8, right: 8, top: 2, bottom: 2 })
}

decoration({ type: TextDecorationType.LineThrough }) 是 ArkUI 中 Text 组件的文字装饰属性,通过设置删除线类型来实现"原价划线"效果。同类属性还包括 Underline(下划线)和 Overline(上划线)。

4.2 标签行的等分布局

促销标签行的实现展示了 Row 布局的灵活性——三个不同颜色的标签自然排布在一行:

Row() {
  Text('满 5000 减 300')
    .fontSize(12).fontColor('#E53935')
    .backgroundColor('#FFF5F5')
    .borderRadius(4)
    .padding({ left: 6, right: 6, top: 2, bottom: 2 })

  Text('6 期免息')
    .fontSize(12).fontColor('#27AE60')
    .backgroundColor('#F0FFF4')
    .borderRadius(4)
    .padding({ left: 6, right: 6, top: 2, bottom: 2 })
    .margin({ left: 8 })

  Text('以旧换新')
    .fontSize(12).fontColor('#4A90D9')
    .backgroundColor('#E3F2FD')
    .borderRadius(4)
    .padding({ left: 6, right: 6, top: 2, bottom: 2 })
    .margin({ left: 8 })
}

每个标签都是一个 Text 组件,通过 padding 控制内部间距,通过 borderRadius 实现圆角矩形,通过 backgroundColor 设置浅色底色。三个标签使用 margin({ left: 8 }) 产生间距。

这种实现方式的优势是零额外容器——不需要为每个标签创建 Column 或 Row 包裹,Text 组件自包含所有样式属性。

4.3 卡片叠卡的效果

商品信息区代码中的 margin({ top: -8 }) 是一个细节设计:

.margin({ top: -8 })          // 与轮播图略微重叠
.borderRadius({ topLeft: 16, topRight: 16 })

负的 top margin 让白色信息卡片向上偏移 8vp,与轮播图底部重叠。配合只有顶部圆角的设置(左上 + 右上),视觉上形成"卡片从轮播图底部滑出"的叠卡效果。


五、规格参数表:layoutWeight 列宽控制

5.1 表格布局的实现

规格参数区使用的是"伪表格"——并非真正的 Table 组件,而是通过 Row + layoutWeight 模拟的两列布局:

@Builder
buildSpecsSection(): void {
  Column() {
    // 标题行
    Row() {
      Text('📋 规格参数')
        .fontSize(16).fontWeight(FontWeight.Bold).fontColor('#1C1C1E')
      Blank()
      Text('查看全部 ›')
        .fontSize(13).fontColor('#4A90D9')
    }
    .width('100%')
    .padding({ bottom: 12 })

    // 表格体
    Column() {
      ForEach(this.specs, (spec: SpecItem, index: number) => {
        Row() {
          Text(spec.name)       // 参数名(左侧窄列)
            .fontSize(13)
            .fontColor('#8E8E93')
            .layoutWeight(1)    // 占 1 份

          Text(spec.value)      // 参数值(右侧宽列)
            .fontSize(13)
            .fontColor('#1C1C1E')
            .layoutWeight(2)    // 占 2 份
        }
        .width('100%')
        .height(36)

        // 行间分隔线(最后一项无)
        if (index < this.specs.length - 1) {
          Divider().height(0.5).color('#F0F0F0').width('100%')
        }
      })
    }
    .width('100%')
    .padding(12)
    .backgroundColor('#FAFAFA')
    .borderRadius(12)
  }
}

layoutWeight(1)layoutWeight(2) 的组合实现了 1:2 的列宽比例——参数名占 1/3 宽度,参数值占 2/3 宽度。这个比例设计考虑到了参数名称通常较短(2-4 个字),参数值通常较长(品牌名、规格描述等)。

5.2 layoutWeight 的深层机制

layoutWeight 是 ArkUI 弹性布局的核心属性。其底层行为可以概括为"先测量固定内容,再按权重分配剩余空间":

步骤 1:Row 测量所有设置了固定宽度的子组件
  → 本场景中无固定宽度子组件
步骤 2:计算剩余空间
  → 剩余空间 = Row 总宽度 - 所有固定宽度子组件之和
  → 本场景中 = Row 总宽度 - 0 = Row 总宽度
步骤 3:按 layoutWeight 比例分配剩余空间
  → layoutWeight(1) 获得 1/3 总宽度
  → layoutWeight(2) 获得 2/3 总宽度

这意味着即使在不同的屏幕宽度下,参数名称和参数值的比例始终保持 1:2。

5.3 条件分隔线

if (index < this.specs.length - 1) {
  Divider().height(0.5).color('#F0F0F0').width('100%')
}

这个条件确保最后一项下方没有多余的分隔线。Divider().color('#F0F0F0') 使用了非常浅的灰色,在白色底色上几乎不可见——这正是表格分隔线的标准做法:有分隔效果但不喧宾夺主。


六、图文混排:文字 + 图片交替布局

6.1 段落与图片交替

商品详情描述区展示了"文字段 → 图片 → 文字段 → 图片"的交替模式,这是电商详情页最标准的图文混排方式:

@Builder
buildDescriptionSection(): void {
  Column() {
    // 标题
    Row() {
      Text('📄 商品详情')
        .fontSize(16).fontWeight(FontWeight.Bold).fontColor('#1C1C1E')
    }
    .width('100%')
    .padding({ bottom: 12 })

    // ---- 文字段落 1 ----
    Text('HarmonyOS NEXT 6.1 新一代智能旗舰...')
      .fontSize(14).fontColor('#444444').lineHeight(22)
      .width('100%')

    Blank().height(16)

    // ---- 模拟图片 1 ----
    Column() {
      Text('🖥️').fontSize(40).opacity(0.5)
      Text('6.73" OLED 超感屏 · 1.07亿色')
        .fontSize(13).fontColor('rgba(255,255,255,0.7)')
        .margin({ top: 6 })
    }
    .width('100%').height(180)
    .linearGradient({ direction: GradientDirection.Right, colors: [['#2C3E50',0], ['#3498DB',1]] })
    .borderRadius(12)

    // ---- 文字段落 2 ----
    Text('采用全新星环设计语言...')
      .fontSize(14).fontColor('#444444').lineHeight(22)
      .width('100%')

    Blank().height(16)

    // ---- 模拟图片 2 ----
    Column() {
      Text('📷').fontSize(40).opacity(0.5)
      Text('5000 万超感光三摄 · 夜景模式')
        .fontSize(13).fontColor('rgba(255,255,255,0.7)')
        .margin({ top: 6 })
    }
    .width('100%').height(180)
    .linearGradient({ direction: GradientDirection.Bottom, colors: [['#1A1A2E',0], ['#16213E',1]] })
    .borderRadius(12)
  }
}

图文混排的间距控制

  • 段落内行间距:lineHeight(22) 让 14 号字体有 8vp 的行间距,阅读舒适
  • 段落到图片间距:Blank().height(16) 提供 16vp 的垂直间距
  • 图片圆角:borderRadius(12) 与页面中其他卡片的圆角一致,保持视觉统一

6.2 用线性渐变模拟产品图

两张"产品图"使用了不同方向的线性渐变:

  • 屏幕图:GradientDirection.Right(从左到右渐变)
  • 摄像头图:GradientDirection.Bottom(从上到下渐变)

不同的渐变方向增加了视觉变化,避免两张占位图看起来雷同。在实际项目中,这些占位图应该替换为真实的 Image 组件:

// 生产级替换
Image($r('app.media.product_detail_1'))
  .width('100%')
  .height(180)
  .objectFit(ImageFit.Cover)
  .borderRadius(12)

6.3 opacity 与文字叠加

Emoji 图标使用 opacity(0.5) 半透明显示,使其看起来像是"水印"或"背景装饰",而不是真正的内容部分。下方的说明文字使用 rgba(255,255,255,0.7) 半透明白色,确保在深色渐变背景上清晰可读。

这种"图标 + 说明文字"的叠加方式是图文混排中常见的"图片封面标注"设计模式。


七、用户评价:头像 + 评分 + 内容

7.1 用户评价的完整结构

每条用户评价的布局是 Row + Column 的典型组合:

Row() {
  // 头像(圆形)
  Text(review.avatar)
    .fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
    .width(36).height(36)
    .textAlign(TextAlign.Center)
    .backgroundColor('#4A90D9')
    .borderRadius(18)                // 圆形:宽/2 = 18
    .margin({ right: 10 })

  // 右侧内容
  Column() {
    // 用户名 + 时间
    Row() {
      Text(review.name).fontSize(13).fontColor('#1C1C1E').fontWeight(FontWeight.Medium)
      Blank()
      Text(review.time).fontSize(11).fontColor('#C0C0C0')
    }
    .width('100%')

    // 评分(用 ⭐ 重复)
    Text('⭐'.repeat(review.rating)).fontSize(12).margin({ top: 2 })

    // 评价内容
    Text(review.content)
      .fontSize(13).fontColor('#666666').lineHeight(20)
      .margin({ top: 4 })
      .maxLines(2)                    // 最多显示 2 行
      .textOverflow({ overflow: TextOverflow.Ellipsis })  // 超出省略
  }
  .layoutWeight(1)
  .alignItems(HorizontalAlign.Start)
}
.width('100%')
.alignItems(VerticalAlign.Top)

7.2 头像圆形裁剪

.width(36).height(36)
.borderRadius(18)      // 36/2 = 18,完美圆形

borderRadius 设为宽度的一半即可将方形 Text 裁剪为圆形。这是 ArkUI 中最常用的圆形头像实现方法,无需使用 Image 组件。

7.3 评分星星的动态生成

Text('⭐'.repeat(review.rating))

String.prototype.repeat(n) 是 ES6 方法,将字符串重复 n 次。review.rating 的值是 1-5 的整数,所以 4 分显示 “⭐⭐⭐⭐”、5 分显示 “⭐⭐⭐⭐⭐”。这是一种零代码成本生成评分星标的方法。

7.4 文本截断

.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })

maxLines(2) 限制文本最多显示 2 行,textOverflow({ overflow: TextOverflow.Ellipsis }) 在超出时显示省略号。这两个属性配合使用,确保长评论在预览区不会撑开卡片,保持列表的整齐。


八、底部固定操作栏:收藏 + 购物车 + 购买

8.1 固定底部的实现原理

底部操作栏是商品详情页最重要的转化区域。它的布局与页面中其他部分有本质区别——它不随 Scroll 滚动,始终固定在屏幕底部

实现方式很简单:底部操作栏的代码写在 Scroll 组件之外,同属于 Column 容器的子组件。在 Column 中,Scroll 通过 layoutWeight(1) 弹性占满,BottomBar 使用固定高度:

build() {
  Column() {
    // ---- 顶部导航栏 ----
    this.buildTopBar()

    // ---- 可滚动主体(弹性) ----
    Scroll() { /* ... */ }
      .layoutWeight(1)              // ★ 弹性占满剩余空间

    // ---- 底部操作栏(固定) ----
    this.buildBottomBar()           // ★ 在 Scroll 外,固定高度
  }
}

8.2 底部操作栏的布局

@Builder
buildBottomBar(): void {
  Row() {
    // 收藏(点击切换 🤍/❤️)
    Column() {
      Text(this.isFavorited ? '❤️' : '🤍').fontSize(22)
      Text('收藏').fontSize(10).fontColor('#8E8E93').margin({ top: 2 })
    }
    .alignItems(HorizontalAlign.Center)
    .width(48)
    .onClick((): void => {
      this.isFavorited = !this.isFavorited;   // 切换收藏状态
    })

    Blank().width(12)

    // 购物车
    Column() {
      Text('🛒').fontSize(22)
      Text('购物车').fontSize(10).fontColor('#8E8E93').margin({ top: 2 })
    }
    .alignItems(HorizontalAlign.Center)
    .width(48)

    Blank().width(12)

    // 加入购物车(橙色)
    Button() {
      Text('加入购物车')
        .fontSize(15).fontColor('#FFFFFF').fontWeight(FontWeight.Medium)
    }
    .type(ButtonType.Capsule).height(44)
    .backgroundColor('#F39C12')    // 橙色(促销色)
    .layoutWeight(1)

    Blank().width(10)

    // 立即购买(红色)
    Button() {
      Text('立即购买')
        .fontSize(15).fontColor('#FFFFFF').fontWeight(FontWeight.Medium)
    }
    .type(ButtonType.Capsule).height(44)
    .backgroundColor('#E53935')    // 红色(行动号召色)
    .layoutWeight(1)
  }
  .width('100%').height(64)
  .padding({ left: 12, right: 12 })
  .backgroundColor('#FFFFFF')
  .alignItems(VerticalAlign.Center)
  .shadow({ radius: 8, color: '#1A000000', offsetY: -2 })  // 向上阴影
}

8.3 阴影方向的控制

.shadow({ radius: 8, color: '#1A000000', offsetY: -2 })

offsetY: -2 表示阴影向上偏移(负值),在底部栏上边缘产生阴影效果,模拟"卡片浮在内容之上"的视觉层次。正值 offsetY: 2 则产生向下偏移的阴影。这个细节虽小,但对层次感的营造至关重要。

8.4 双按钮的权重分配

"加入购物车"和"立即购买"两个按钮都设置了 layoutWeight(1),因此它们等分 Blank() 之后的剩余宽度。在两个按钮之间有 Blank().width(10) 提供 10vp 的间距。


九、项目工程配置

9.1 build-profile.json5

{
  "app": {
    "products": [
      {
        "name": "default",
        "targetSdkVersion": "6.1.1(24)",
        "compatibleSdkVersion": "6.1.1(24)",
        "runtimeOS": "HarmonyOS"
      }
    ]
  }
}
  • targetSdkVersion: "6.1.1(24)":目标 SDK 版本,对应 API 24
  • compatibleSdkVersion: "6.1.1(24)":向前兼容的 SDK 版本
  • runtimeOS: "HarmonyOS":运行操作系统

9.2 EntryAbility 启动

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/ProductDetailDemo', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'EnglishApp',
          'Failed to load content: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'EnglishApp', 'Succeeded in loading content.');
    });
  }
}

windowStage.loadContent 是页面加载的核心 API,第一个参数是页面路径(对应 pages/ 目录下的 .ets 文件,不带后缀),第二个参数是加载完成后的回调。


十、商品详情页的常见布局模式

10.1 信息层级模型

电商详情页的信息组织遵循"漏斗模型":

上层(高转化)  →  商品图 + 标题 + 价格    用户最关注的"是什么"和"多少钱"
中层(决策)    →  规格 + 描述 + 评价      帮助用户决策的"好不好"
下层(补充)    →  推荐 + 售后             辅助信息

10.2 从本 Demo 到生产环境的升级路径

组件 Demo 实现 生产级方案
轮播图 渐变占位 + Text Swiper + Image + 懒加载
商品图 linearGradient Image($r('app.media.xxx')) 或网络图
价格 静态数据 从 API 获取 + 格式化
收藏 @State isFavorited 同步到本地/云端存储
规格 内存数据 + ForEach LazyForEach + 网络数据
评价 模拟数据 List 组件 + 分页加载

10.3 状态管理的演进

本 Demo 使用 @State 管理三个状态:

@State isFavorited: boolean = false;      // 收藏状态
@State currentImageIndex: number = 0;     // 轮播图索引
@State quantity: number = 1;              // 购买数量

在真实的电商应用中,状态管理的复杂度会大幅增加:

  • 商品数据:从后端 API 获取,可能使用 @State + 异步网络请求
  • SKU 选择:颜色、存储等规格联动,需要 @Observed + @ObjectLink
  • 购物车:跨页面共享状态,需要 AppStorageLocalStorage
  • 用户信息:持久化存储,需要 PersistentStorage

十一、布局 API 速查表

11.1 核心布局组件

组件 用途 关键属性
Column 纵向排列 alignItems()justifyContent()
Row 横向排列 alignItems()justifyContent()
Scroll 可滚动容器 scrollBarState()edgeEffect()
Stack 层叠容器 position()alignContent()
Grid 网格布局 columnsTemplate()rowsTemplate()

11.2 常用属性

属性 用途 示例
layoutWeight(n) 弹性权重分配 .layoutWeight(1)
constraintSize() 尺寸约束 .constraintSize({ maxWidth: '70%' })
linearGradient() 线性渐变 .linearGradient({ direction: Bottom, colors: [[_0],[_1]] })
borderRadius() 圆角 .borderRadius(12)
shadow() 阴影 .shadow({ radius: 8, color: '#1A000000', offsetY: 4 })
decoration() 文字装饰 .decoration({ type: LineThrough })

11.3 运行与构建命令

# 快速验证(1-2 秒)
hvigorw PreBuildApp --no-daemon

# 调试构建
hvigorw assembleApp --mode debug --no-daemon

# 发布构建(需签名)
hvigorw assembleApp --mode release --no-daemon

十二、总结

12.1 技术要点回顾

本文通过一个完整的商品详情页 Demo,系统讲解了 ArkUI 在图文混排场景下的核心布局技术:

  1. 三段式架构:固定顶部 + 弹性 Scroll + 固定底部
  2. 分区白卡:灰色背景 + 白色圆角卡片,视觉自然分区
  3. 图文混排:文字段落与渐变色块交替排列
  4. 弹性权重layoutWeight 控制列宽比例
  5. 条件分隔线if + Divider 避免最后一项多余分隔
  6. 状态驱动@State 控制收藏、轮播切换
  7. 底部固定栏:Scroll 外部 Row,不受滚动影响

这些技术组合在一起,构成了电商级商品详情页的完整布局方案。无论是简单的商品展示页,还是复杂的多规格选购页,都可以基于这个架构进行扩展。

12.2 鸿蒙 NEXT 布局的未来

随着 HarmonyOS NEXT 6.1.1 的持续迭代,ArkUI 的布局能力在不断增强。从 API 24 开始,开发者可以期待以下新特性:

  • 自定义布局:通过 Layout 接口实现完全自定义的布局算法
  • 响应式断点:根据不同屏幕尺寸自动适配布局
  • 布局动画:组件增删时自动伴随过渡动画
  • 性能优化:更智能的布局测量缓存,减少不必要的重排

对于正在进入鸿蒙生态的开发者而言,商品详情页这样的综合案例是理解 ArkUI 布局系统的最佳入口——它涵盖了 Column、Row、Scroll、Stack、Grid 等所有核心组件,同时也涉及 @State 状态管理、@Builder 组件化等 ArkTS 特色功能。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐