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

效果图

完整代码

  • 实例对象
javascript 复制代码
export class ProvinceBean {
  id?: string
  pid?: string
  isSelect?: boolean
  deep?: object
  extName?: string
  children?: ProvinceBean[]
}
  • 级联代码
javascript 复制代码
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[0].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[0].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
  }
}
  • 使用
javascript 复制代码
 @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()
  • 获取点击组件,组件底部距离屏幕顶部的高度
javascript 复制代码
.onClick((event: ClickEvent) => {
      this.postionY = Number(event.target.area.height) + Number(event.target.area.globalPosition.y)  
    })
相关推荐
鸿蒙自习室2 分钟前
鸿蒙多线程开发——并发模型对比(Actor与内存共享)
华为·harmonyos
JavaPub-rodert1 小时前
鸿蒙生态崛起:开发者的机遇与挑战
华为·harmonyos
帅比九日3 小时前
【HarmonyOS Next】封装一个网络请求模块
前端·harmonyos
yilylong5 小时前
鸿蒙(Harmony)实现滑块验证码
华为·harmonyos·鸿蒙
baby_hua5 小时前
HarmonyOS第一课——DevEco Studio的使用
华为·harmonyos
HarmonyOS_SDK5 小时前
融合虚拟与现实,AR Engine为用户提供沉浸式交互体验
harmonyos
- 羊羊不超越 -6 小时前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
长弓三石8 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
SameX10 小时前
鸿蒙 Next 电商应用安全支付与密码保护实践
前端·harmonyos
SuperHeroWu711 小时前
【HarmonyOS】键盘遮挡输入框UI布局处理
华为·harmonyos·压缩·keyboard·键盘遮挡·抬起