HarmonyOS-商城服务-二级联动

1、数据模型定义

(1)定义数据模型

//定义单个数据
export default class Goods{
  // 商品Id
  goodId:number
  // 商品名称
  goodName:string
  // 商品图片
  imageUrl:ResourceStr
  // 商品价格
  goodPrice:number
  // 商品类型id
  goodTypeId:number

  constructor(goodId: number, goodName: string, imageUrl: ResourceStr, goodPrice: number, goodTypeId: number) {
    this.goodId = goodId
    this.goodName = goodName
    this.imageUrl = imageUrl
    this.goodPrice = goodPrice
    this.goodTypeId = goodTypeId
  }

}
// 定义商品类型数据
export class GoodsType{
  // 商品类型id
  goodTypeId:number
  // 商品类型名称
  goodTypeName:string
  // 商品列表
  goodList:Array<Goods>

  constructor(goodTypeId: number, goodTypeName: string, goodList: Array<Goods>) {
    this.goodTypeId = goodTypeId
    this.goodTypeName = goodTypeName
    this.goodList = goodList
  }
}
// 定义两个数据的集合
export class LinkGoods{
  // 商品类型id
  goodTypeId:number
  // 商品类型名称
  goodTypeName:string
  // 商品Id
  goodId:number
  // 商品名称
  goodName:string
  // 商品图片
  imageUrl:ResourceStr
  // 商品价格
  goodPrice:number

  constructor(goodTypeId: number, goodTypeName: string, goodId: number, goodName: string, imageUrl: ResourceStr,
    goodPrice: number) {
    this.goodTypeId = goodTypeId
    this.goodTypeName = goodTypeName
    this.goodId = goodId
    this.goodName = goodName
    this.imageUrl = imageUrl
    this.goodPrice = goodPrice
  }
}

(2)定义数据,生成一个包含所有商品分类及其对应商品列表的数组

import Goods, { GoodsType, LinkGoods } from "../model/Goods"

export class NavGoodsModel{
  //设置方法,获取商品分类列表数据
  getLinkData():Array<GoodsType>{
    // 定义返回的商品分类列表数据
    const goodsTypeData:GoodsType[]=[]
    // 定义商品分类id
    let goodsTypeId:number=0
    LINK_DATA.forEach((item:LinkGoods)=>{
    //   首先判断当前商品所在的分类是否存在
      if (goodsTypeId!==item.goodTypeId) {
      //   不存在的话,创建对应的商品分类
        let goodsTypeItem:GoodsType=new GoodsType(item.goodTypeId,item.goodTypeName,[])
        goodsTypeData.push(goodsTypeItem)
      }
    //   当前商品分类存在的话,添加具体商品信息模型
      let goodsItem:Goods=new Goods(item.goodId,item.goodName,item.imageUrl,item.goodPrice,goodsTypeId)
      goodsTypeData[goodsTypeData.length-1].goodList.push(goodsItem)
      goodsTypeId=item.goodTypeId
    })
    return goodsTypeData
  }
}
let navGoodsModel=new NavGoodsModel()
export default  navGoodsModel as NavGoodsModel
// 创建所链接数据
const LINK_DATA: LinkGoods[] = [
  new LinkGoods(1, '热门商品', 1, 'HUAWEI P60 Art', $r('app.media.ic_img_1'), 0),
  new LinkGoods(1, '热门商品', 2, 'HUAWEI P60 Pro', $r('app.media.ic_img_2'), 5000),
  new LinkGoods(1, '热门商品', 3, 'HUAWEI Mate 50 Pro 4G', $r('app.media.ic_img_3'), 5000),
  new LinkGoods(1, '热门商品', 4, 'HUAWEI 畅享 60 X ', $r('app.media.ic_img_4'), 2220),
  new LinkGoods(1, '热门商品', 5, 'Matebook E 2023', $r('app.media.ic_img_5'), 2560),
  new LinkGoods(1, '热门商品', 6, 'Matebook D16 2023', $r('app.media.ic_img_6'), 0),
  new LinkGoods(1, '热门商品', 7, 'Matebook E Go', $r('app.media.ic_img_7'), 0),
  new LinkGoods(1, '热门商品', 8, 'HUAWEI MatePad Paper', $r('app.media.ic_img_8'), 4000),
  new LinkGoods(1, '热门商品', 9, 'MatePad Pro 11', $r('app.media.ic_img_9'), 6500),
  new LinkGoods(1, '热门商品', 10, '华为智慧屏 V98', $r('app.media.ic_img_10'),3000),
  new LinkGoods(1, '热门商品', 11, '华为智慧屏  V85', $r('app.media.ic_img_11'), 5000),
  new LinkGoods(2, '手机', 12, 'HUAWEI P60 Art', $r('app.media.ic_img_1'), 0),
  new LinkGoods(2, '手机', 13, 'HUAWEI P60 Pro', $r('app.media.ic_img_2'), 5000),
  new LinkGoods(2, '手机', 14, 'HUAWEI Mate 50 Pro 4G', $r('app.media.ic_img_3'), 5000),
  new LinkGoods(2, '手机', 15, 'HUAWEI 畅享 60 X ', $r('app.media.ic_img_4'), 2220),
  new LinkGoods(2, '手机', 16, 'HUAWEI 畅享 60 Pro', $r('app.media.ic_img_21'), 1599),
  new LinkGoods(3, '穿戴', 18, 'HUAWEI WATCH 4 Pro', $r('app.media.ic_img_22'), 3699),
  new LinkGoods(3, '穿戴', 19, 'HUAWEI WATCH 4', $r('app.media.ic_img_23'), 2699),
  new LinkGoods(3, '穿戴', 20, 'HUAWEI 手环8', $r('app.media.ic_img_24'), 319),
  new LinkGoods(3, '穿戴', 21, 'HUAWEI 通话手环B7', $r('app.media.ic_img_25'), 1199),
  new LinkGoods(3, '穿戴', 22, 'HUAWEI GT 3 Pro 系列', $r('app.media.ic_img_26'), 2688),
  new LinkGoods(4, '平板', 24, 'MatePad Air', $r('app.media.ic_img_27'), 2899),
  new LinkGoods(4, '平板', 25, 'HUAWEI MatePad Paper', $r('app.media.ic_img_8'), 4000),
  new LinkGoods(4, '平板', 26, 'MatePad Pro 11', $r('app.media.ic_img_9'), 6500),
  new LinkGoods(4, '平板', 27, 'MatePad Pro 12.6', $r('app.media.ic_img_28'), 4199),
  new LinkGoods(4, '平板', 28, 'MatePad SE 10.4 2023款', $r('app.media.ic_img_29'), 1499),
  new LinkGoods(5, '笔记本', 29, 'Matebook E 2023', $r('app.media.ic_img_5'), 2560),
  new LinkGoods(5, '笔记本', 30, 'Matebook D16 2023', $r('app.media.ic_img_6'), 0),
  new LinkGoods(5, '笔记本', 31, 'Matebook E Go', $r('app.media.ic_img_7'), 0),
  new LinkGoods(5, '笔记本', 32, 'Matebook X Pro 2023', $r('app.media.ic_img_30'), 11999),
  new LinkGoods(5, '笔记本', 33, 'Matebook 13s 2023', $r('app.media.ic_img_31'), 7299),
  new LinkGoods(6, '智慧屏', 36, '华为智慧屏 V98', $r('app.media.ic_img_10'),3000),
  new LinkGoods(6, '智慧屏', 37, '华为智慧屏  V85', $r('app.media.ic_img_11'), 5000),
]

2、定义左侧商品类型列表

import { GoodsType, LinkGoods } from "../model/Goods"
import NavGoodsModel from "../viewmodel/NavGoodsModel"

@Entry
@Component
export struct Index {
  // 定义左侧商品类型滑动条
  private goodsTypeScroller:Scroller=new Scroller()
  // 定义商品类型数据
  @State dataArr: GoodsType[] = []
  // 定义商品类型被选中的状态
  @State isChecked: boolean = false
  // 定义当前选中的index
  @State currentIndex:number=0

  aboutToAppear(): void {
    this.dataArr = NavGoodsModel.getLinkData()
  }

  build() {
    Row() {
      List({scroller:this.goodsTypeScroller}) {
        ForEach(this.dataArr, (item: GoodsType, index: number) => {
          ListItem() {
            this.typeGoodsItem(item.goodTypeName,index)
          }
        }, (item: GoodsType) => item.goodTypeId + '')
      }.height('100%')
      .width(100)
      .backgroundColor('#efefef')
      .alignListItem(ListItemAlign.Start)
      .divider({strokeWidth:1})
    }
    .height('100%')
    .width('100%')
  }
  // 定义商品类型,单个样式
  @Builder
  typeGoodsItem(goodTypeName: string,index:number) {
    Row() {
      Text(goodTypeName)
        .fontSize(14)
        .fontColor(this.currentIndex==index ? '#ff131212' : '#ff757579')
        .textAlign(TextAlign.Center)
    }.width(100)
    .height(70)
    .justifyContent(FlexAlign.Center)
    .backgroundColor(this.currentIndex===index?'#fffaf7f7':'#efefef')
    .onClick(() => {
      this.currentIndex=index
    })
  }
}

3、定义右侧商品列表

(1)定义头部样式

  //   定义商品分类展示所有数据的头部样式
  @Builder
  headerGoodType(goodTypeName: string) {
    Row() {
      Text(goodTypeName)
        .fontSize(18)
        .fontColor('#ff131212')
        .textAlign(TextAlign.Center)
    }
    .height(70)
    .width('100%')
    .justifyContent(FlexAlign.Start)
    .backgroundColor('#fffaf7f7')
  }

(2)定义单个商品数据

//   定义单个商品数据
  @Builder goodItem(good:Goods){
    Row(){
      Image(good.imageUrl)
        .width(80)
        .height(140)
        .aspectRatio(1)
      Column(){
        Text(good.goodName)
          .fontSize(18)
          .fontWeight(500)
          .maxLines(2)
          .textOverflow({overflow:TextOverflow.Ellipsis})
        Text(good.goodPrice.toString())
          .fontColor(Color.Red)
      }.height('100%')
      .layoutWeight(1)
      .padding({top:20,bottom:20,left:20})
      .justifyContent(FlexAlign.SpaceBetween)
      .alignItems(HorizontalAlign.Start)
    }.width('100%')
    .height(120)
    .backgroundColor(Color.White)
  }

(3)定义右侧滑动效果

List() {
        ForEach(this.dataArr, (goodsType: GoodsType, index: number) => {
          ListItemGroup({ header: this.headerGoodType(goodsType.goodTypeName) }) {
            ForEach(goodsType.goodList, (goods: Goods, index: number) => {
              ListItem() {
                this.goodItem(goods)
              }
            })
          }.divider({ strokeWidth: 1 })
        }, (item: GoodsType) => item.goodTypeName)
      }
      .layoutWeight(1)
      .height('100%')
      .backgroundColor('#efefef')
      .alignListItem(ListItemAlign.Start)
      .sticky(StickyStyle.Header)

(4)滑动联动效果

①点击左侧商品类型,右侧跳转到对应的商品

②滑动右侧商品,左侧商品类型也滑动到对应位置

4、Index页面完整代码

import Goods, { GoodsType, LinkGoods } from "../model/Goods"
import NavGoodsModel from "../viewmodel/NavGoodsModel"

@Entry
@Component
export struct Index {
  // 定义左侧商品类型滑动条
  private goodsTypeScroller: Scroller = new Scroller()
  // 定义右侧商品滑动条
  private goodsScroller: Scroller = new Scroller()
  // 定义商品类型数据
  @State dataArr: GoodsType[] = []
  // 定义商品类型被选中的状态
  @State isChecked: boolean = false
  // 定义当前选中的index
  @State currentIndex: number = 0

  aboutToAppear(): void {
    this.dataArr = NavGoodsModel.getLinkData()
  }

  build() {
    Row() {
      List({ scroller: this.goodsTypeScroller }) {
        ForEach(this.dataArr, (item: GoodsType, index: number) => {
          ListItem() {
            this.typeGoodsItem(item.goodTypeName, index)
          }
        }, (item: GoodsType) => item.goodTypeName)
      }
      .height('100%')
      .width(100)
      .backgroundColor('#efefef')
      .alignListItem(ListItemAlign.Start)
      .divider({ strokeWidth: 1 })


      List({ scroller: this.goodsScroller }) {
        ForEach(this.dataArr, (goodsType: GoodsType, index: number) => {
          ListItemGroup({ header: this.headerGoodType(goodsType.goodTypeName) }) {
            ForEach(goodsType.goodList, (goods: Goods, index: number) => {
              ListItem() {
                this.goodItem(goods)
              }
            })
          }.divider({ strokeWidth: 1 })
        }, (item: GoodsType) => item.goodTypeName)
      }
      .layoutWeight(1)
      .height('100%')
      .backgroundColor('#efefef')
      .alignListItem(ListItemAlign.Start)
      .sticky(StickyStyle.Header)
      .onScrollIndex((start: number, end: number) => {
        if (this.currentIndex !== start) {
          this.currentIndex=start
          this.goodsTypeScroller.scrollToIndex(this.currentIndex)
        }
      })
    }
    .height('100%')
    .width('100%')
  }

  // 定义商品类型,单个样式
  @Builder
  typeGoodsItem(goodTypeName: string, index: number) {
    Row() {
      Text(goodTypeName)
        .fontSize(14)
        .fontColor(this.currentIndex == index ? '#ff131212' : '#ff757579')
        .textAlign(TextAlign.Center)
    }
    .width(100)
    .height(70)
    .justifyContent(FlexAlign.Center)
    .backgroundColor(this.currentIndex === index ? '#fffaf7f7' : '#efefef')
    .onClick(() => {
      this.currentIndex = index
      this.goodsScroller.scrollToIndex(index)
    })
  }

  //   定义商品分类展示所有数据的头部样式
  @Builder
  headerGoodType(goodTypeName: string) {
    Row() {
      Text(goodTypeName)
        .fontSize(18)
        .fontColor('#ff131212')
        .textAlign(TextAlign.Center)
    }
    .height(70)
    .width('100%')
    .justifyContent(FlexAlign.Start)
    .backgroundColor('#fffaf7f7')
  }

  //   定义单个商品数据
  @Builder
  goodItem(good: Goods) {
    Row() {
      Image(good.imageUrl)
        .width(80)
        .height(140)
        .aspectRatio(1)
      Column() {
        Text(good.goodName)
          .fontSize(18)
          .fontWeight(500)
          .maxLines(2)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
        Text(good.goodPrice.toString())
          .fontColor(Color.Red)
      }
      .height('100%')
      .layoutWeight(1)
      .padding({ top: 20, bottom: 20, left: 20 })
      .justifyContent(FlexAlign.SpaceBetween)
      .alignItems(HorizontalAlign.Start)
    }.width('100%')
    .height(120)
    .backgroundColor(Color.White)
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值