img

目录

  • 案例介绍
  • 代码实现
  • 代码详解
  • 1. 状态管理
  • 2. 规格选择实现
  • 3. 售后服务展示
  • 4. 底部购买按钮
  • 总结

案例介绍

本篇文章将介绍如何在商品详情页中实现规格选择和相关交互功能,包括颜色、尺寸选择,以及售后服务信息的展示,提升用户的购物体验。

代码实现

@Entry
@Component
struct ProductDetailPage {
  // 商品基本信息
  private productInfo = {
    id: '10001',
    name: 'HarmonyOS智能手表 Pro',
    price: 1299,
    originalPrice: 1499,
    colors: ['黑色', '银色', '金色'],
    sizes: ['41mm', '45mm']
  };

  // 售后服务
  private services = [
    { title: '7天无理由退货', desc: '商品自签收之日起7天内,可无理由退货(商品完好且包装完整)' },
    { title: '15天质量问题换货', desc: '商品自签收之日起15天内,出现质量问题可申请换货' },
    { title: '1年官方保修', desc: '商品自签收之日起1年内,出现质量问题可享受官方保修服务' }
  ];

  // 选中的颜色和尺寸
  @State selectedColor: string = '黑色';
  @State selectedSize: string = '45mm';
  
  // 各部分的展开状态
  @State serviceExpanded: boolean = false;

  build() {
    Column() {
      // 规格选择区域
      Column({ space: 16 }) {
        // 颜色选择
        Column({ space: 8 }) {
          Text('颜色')
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
          
          Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
            ForEach(this.productInfo.colors, (color) => {
              Text(color)
                .fontSize(14)
                .padding(8)
                .backgroundColor(this.selectedColor === color ? '#E3F2FD' : '#FFFFFF')
                .borderRadius(4)
                .borderWidth(1)
                .borderColor(this.selectedColor === color ? '#2196F3' : '#DDDDDD')
                .margin({ right: 8, bottom: 8 })
                .onClick(() => {
                  this.selectedColor = color;
                })
            })
          }
        }
        
        // 尺寸选择
        Column({ space: 8 }) {
          Text('尺寸')
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
          
          Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
            ForEach(this.productInfo.sizes, (size) => {
              Text(size)
                .fontSize(14)
                .padding(8)
                .backgroundColor(this.selectedSize === size ? '#E3F2FD' : '#FFFFFF')
                .borderRadius(4)
                .borderWidth(1)
                .borderColor(this.selectedSize === size ? '#2196F3' : '#DDDDDD')
                .margin({ right: 8, bottom: 8 })
                .onClick(() => {
                  this.selectedSize = size;
                })
            })
          }
        }
      }
      .width('100%')
      .padding(16)
      .backgroundColor('#FFFFFF')
      .borderRadius(8)
      
      // 售后服务(可折叠)
      FolderStack({ initialExpand: this.serviceExpanded }) {
        // 服务标题
        FolderStackHeader() {
          Row() {
            Text('售后服务')
              .fontSize(16)
              .fontWeight(FontWeight.Medium)
            
            Blank()
            
            Image(this.serviceExpanded ? $r('app.media.ic_arrow_up') : $r('app.media.ic_arrow_down'))
              .width(20)
              .height(20)
          }
          .width('100%')
          .padding({ left: 16, right: 16 })
        }
        
        // 服务内容
        FolderStackContent() {
          Column({ space: 16 }) {
            ForEach(this.services, (service) => {
              Column({ space: 4 }) {
                Text(service.title)
                  .fontSize(14)
                  .fontWeight(FontWeight.Medium)
                  .fontColor('#333333')
                
                Text(service.desc)
                  .fontSize(12)
                  .fontColor('#666666')
              }
              .alignItems(HorizontalAlign.Start)
              .width('100%')
            })
          }
          .width('100%')
          .padding(16)
        }
      }
      .width('100%')
      .borderRadius(8)
      .headerBackgroundColor('#FFFFFF')
      .contentBackgroundColor('#FFFFFF')
      .dividerColor('#EEEEEE')
      .onChange((isExpanded: boolean) => {
        this.serviceExpanded = isExpanded;
      })
      
      // 底部购买按钮
      Row() {
        Button('加入购物车')
          .height(40)
          .backgroundColor('#FF9800')
          .fontColor('#FFFFFF')
          .layoutWeight(1)
        
        Button('立即购买')
          .height(40)
          .backgroundColor('#FF5722')
          .fontColor('#FFFFFF')
          .layoutWeight(1)
      }
      .width('100%')
      .height(60)
      .padding({ left: 16, right: 16 })
      .backgroundColor('#FFFFFF')
      .justifyContent(FlexAlign.SpaceBetween)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}

代码详解

1. 状态管理

@State selectedColor: string = '黑色';
@State selectedSize: string = '45mm';
@State serviceExpanded: boolean = false;

2. 规格选择实现

Flex({ wrap: FlexWrap.Wrap }) {
  ForEach(this.productInfo.colors, (color) => {
    Text(color)
      .backgroundColor(this.selectedColor === color ? '#E3F2FD' : '#FFFFFF')
      .borderColor(this.selectedColor === color ? '#2196F3' : '#DDDDDD')
      .onClick(() => {
        this.selectedColor = color;
      })
  })
}
  • 使用Flex布局实现规格选项
  • 根据选中状态改变样式
  • 点击事件更新选中状态

3. 售后服务展示

FolderStack({ initialExpand: this.serviceExpanded }) {
  FolderStackHeader() { /* 服务标题 */ }
  FolderStackContent() {
    Column({ space: 16 }) {
      ForEach(this.services, (service) => {
        Column({ space: 4 }) { /* 服务项 */ }
      })
    }
  }
}
  • 使用FolderStack组织售后服务信息
  • 标题和内容区域分离
  • 服务项采用上下布局

4. 底部购买按钮

Row() {
  Button('加入购物车')
    .backgroundColor('#FF9800')
  Button('立即购买')
    .backgroundColor('#FF5722')
}
.height(60)
.backgroundColor('#FFFFFF')
  • 固定在底部的按钮栏
  • 两个主要操作按钮
  • 不同的按钮样式区分

总结

本篇文章展示了如何实现商品详情页的规格选择和交互功能,主要包括:

  • 规格选择的状态管理
  • 可折叠的售后服务信息
  • 底部购买按钮的实现
  • 统一的交互反馈

通过这些功能的实现,使商品详情页具备了基本的购物功能。

Logo

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

更多推荐