郭卫东 发表于 2024-7-29 06:33:24

HarmonyOS Next 省市区级联(三级联动)筛选框

效果图

https://i-blog.csdnimg.cn/direct/44998739f07b4cb894e3b8559c060726.gif
完整代码



[*]实例对象
export class ProvinceBean {
id?: string
pid?: string
isSelect?: boolean
deep?: object
extName?: string
children?: ProvinceBean[]
}


[*]级联代码
import { MMKV } from '@tencent/mmkv/src/main/ets/utils/MMKV'
import { ProvinceBean } from '../../../../bean/ProvinceBean'
import { MMKVHelp } from '../../../../util/MMKVHelp'

interface CascadeInterface {
onClick?: (provinc: ProvinceBean) => void
close?: () => void
}

@Preview
@CustomDialog
export struct CascadeDialog {
controller: CustomDialogController
scrollerOne: Scroller = new Scroller()
scrollerTwo: Scroller = new Scroller()
scrollerThree: Scroller = new Scroller()
callback?: CascadeInterface
@State provinceList: ProvinceBean[] = new Array<ProvinceBean>()
@State cityList: ProvinceBean[] = new Array<ProvinceBean>()
@State areaList: ProvinceBean[] = new Array<ProvinceBean>()
@State selectId: string = ''
// 记录上次选择的数据在列表中的下标,显示数据时,自动滚动到可见位置
@State provinceIndex: number = 0
@State cityIndex: number = 0
@State areaIndex: number = 0
// 跟随父级 改变数据
@Prop provinceItem: ProvinceBean = new ProvinceBean()
// 临时记录省级数据
@State tempProvinceItem: ProvinceBean = new ProvinceBean()

aboutToAppear() {
    let data = MMKV.defaultMMKV().decodeString(MMKVHelp.KEY_CITY)
    if (data) {
      this.selectId = this.provinceItem.id ? this.provinceItem.id : ''
      this.provinceList = JSON.parse(data)
      if (this.provinceList) {
      this.provinceList.forEach((provinceBean, provinceIndex) => {
          if (provinceBean.id == this.selectId) {
            this.provinceIndex = provinceIndex
            // 展开式 同步最新省级临时数据
            this.tempProvinceItem = provinceBean

            provinceBean.isSelect = true
            this.cityList = provinceBean.children ? provinceBean.children : new Array<ProvinceBean>()
            /**
             * @Desc 一级列表匹配上 2种场景的点击
             * 二级列表点击:1.全省 2.直辖市
             */
            this.cityList.isSelect = true
          } else {
            provinceBean.isSelect = false
            provinceBean.children?.forEach((cityBean, cityIndex) => {
            if (cityBean.id == this.selectId) {
                this.cityIndex = cityIndex
                this.provinceIndex = provinceIndex
                // 展开时,同步省级对应的数据
                this.tempProvinceItem = provinceBean

                provinceBean.isSelect = true
                cityBean.isSelect = true
                this.cityList = provinceBean.children ? provinceBean.children : new Array<ProvinceBean>()
                this.areaList = cityBean.children ? cityBean.children : new Array<ProvinceBean>()
                /**
               * @Desc 二级列表匹配上 存在4种场景的点击
               * 1.全省 2.直辖市 3.直辖市下的区 4.三级列表的全市(第一条)
               */
                if (cityBean.children && cityBean.children.length > 0) { //第4种场景:
                  this.areaList.isSelect = true
                } else {
                  // 直辖市下的区
                  console.log('直辖市下的区' + cityBean.extName)
                }
            } else {
                cityBean.isSelect = false
                cityBean.children?.forEach((areaBean, areaIndex) => {
                  if (areaBean.id == this.selectId) {
                  this.areaIndex = areaIndex
                  this.cityIndex = cityIndex
                  this.provinceIndex = provinceIndex
                  console.log('--22222---' + this.provinceIndex + ' = ' + this.cityIndex + ' = ' + this.cityIndex)
                  // 展开时,同步省对应的数据
                  this.tempProvinceItem = provinceBean

                  areaBean.isSelect = true
                  provinceBean.isSelect = true
                  cityBean.isSelect = true
                  this.cityList = provinceBean.children ? provinceBean.children : new Array<ProvinceBean>()
                  this.areaList = cityBean.children ? cityBean.children : new Array<ProvinceBean>()
                  } else {
                  areaBean.isSelect = false
                  }
                })
            }
            })
          }
      })
      }
    }

}

build() {
    Column() {
      Row() {
      List({ scroller: this.scrollerOne }) {
          ForEach(this.provinceList, (provinceItem: ProvinceBean, index: number) => {
            ListItem() {
            Text(provinceItem.extName)
                .width('100%')
                .fontColor(provinceItem.isSelect ? '#007FFF' : '#FF000000')
                .fontSize(12)
                .padding({ left: 10, top: 10, bottom: 10 })
            }.onClick(() => {
            if (provinceItem.isSelect) {
                console.log('点击的相同地区' + provinceItem.extName)
                return
            } else {
                this.cityList.forEach(item => {
                  item.isSelect = false
                })
                this.areaList.forEach(item => {
                  item.isSelect = false
                })
                this.areaList = new Array<ProvinceBean>()
            }
            this.tempProvinceItem = provinceItem
            this.upProvinceList(provinceItem)
            this.cityList = provinceItem.children ? provinceItem.children : new Array<ProvinceBean>()
            })
          })
      }.layoutWeight(1)
      .backgroundColor(Color.White)
      .height('100%').onSizeChange(() => {
          this.scrollerOne.scrollToIndex(this.provinceIndex)
      })


      List({ scroller: this.scrollerTwo }) {
          ForEach(this.cityList, (cityItem: ProvinceBean, KEY) => {
            ListItem() {
            Text(cityItem.extName)
                .width('100%')
                .fontColor(cityItem.isSelect ? '#007FFF' : '#FF000000')
                .fontSize(12)
                .padding({ left: 10, top: 10, bottom: 10 })
            }.onClick(() => {
            // cityItem.children :无数据说明是直辖市/省 ,有数据说明是市下的区
            if (cityItem.children && cityItem.children.length > 0) { // 切换省下面的市
                this.upCityList(cityItem)
                if (!cityItem.isSelect) {
                  this.areaList.forEach(item => {
                  item.isSelect = false
                  })
                }
                this.areaList = cityItem.children ? cityItem.children : new Array<ProvinceBean>()
            } else {
                //直辖市/省
                this.callback?.onClick!(cityItem)
            }
            })
          })
      }.layoutWeight(1).backgroundColor('#F6F6F6').height('100%').onSizeChange(() => {
          this.scrollerTwo.scrollToIndex(this.cityIndex)
      })

      List({ scroller: this.scrollerThree }) {
          ForEach(this.areaList, (areaItem: ProvinceBean, KEY) => {
            ListItem() {
            Text(areaItem.extName)
                .width('100%')
                .fontColor(areaItem.isSelect ? '#007FFF' : '#FF000000')
                .fontSize(12)
                .padding({ left: 10, top: 10, bottom: 10 })
            }.onClick(() => {
            this.callback?.onClick!(areaItem)
            })
          })
      }.layoutWeight(1).backgroundColor('#F0F0F0').height('100%').onSizeChange(() => {
          this.scrollerThree.scrollToIndex(this.areaIndex)
      })
      }.alignItems(VerticalAlign.Top)
      .width('100%')
      .height(500)
    }.onClick(() => {
      this.controller?.close!()
    }).backgroundColor("#90000000").height('100%')
}

/**
   * @Desc 更新省:自身列表的ui状态
   */
private upProvinceList(provinceItem: ProvinceBean) {
    let temp = this.provinceList
    temp.forEach(item => {
      if (provinceItem.id == item.id) {
      item.isSelect = true
      } else {
      item.isSelect = false
      }
    })
    this.provinceList = new Array<ProvinceBean>()
    this.provinceList = temp
}

/**
   * @Desc 更新城市:自身列表的ui状态
   */
private upCityList(itemBean: ProvinceBean) {
    let temp = this.cityList
    temp.forEach(item => {
      if (itemBean.id == item.id) {
      item.isSelect = true
      } else {
      item.isSelect = false
      }
    })
    this.cityList = new Array<ProvinceBean>()
    this.cityList = temp
}
}



[*]使用
@State provinceItem: ProvinceBean = new ProvinceBean()

this.controller = new CustomDialogController({
      builder: CascadeDialog({
      provinceItem: this.provinceItem,
      callback: {
          onClick: (province: ProvinceBean) => {
            console.log(JSON.stringify(province))
            this.provinceItem = province
            this.controller?.close()
          }
      }
      }),
      cancel: () => {
      this.controller?.close()
      },
      offset: { dx: 0, dy: this.postionY },// 弹窗的偏移量
      autoCancel: true,
      customStyle: true,
      maskColor: Color.Transparent,
      openAnimation: { duration: 0 },
      closeAnimation: { duration: 0 }
    });
    this.controller.open()


[*]获取点击组件,组件底部距离屏幕顶部的高度
.onClick((event: ClickEvent) => {
      this.postionY = Number(event.target.area.height) + Number(event.target.area.globalPosition.y)
    })

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: HarmonyOS Next 省市区级联(三级联动)筛选框