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

打印 上一主题 下一主题

主题 702|帖子 702|积分 2106

效果图


完整代码



  • 实例对象
  1. export class ProvinceBean {
  2.   id?: string
  3.   pid?: string
  4.   isSelect?: boolean
  5.   deep?: object
  6.   extName?: string
  7.   children?: ProvinceBean[]
  8. }
复制代码


  • 级联代码
  1. import { MMKV } from '@tencent/mmkv/src/main/ets/utils/MMKV'
  2. import { ProvinceBean } from '../../../../bean/ProvinceBean'
  3. import { MMKVHelp } from '../../../../util/MMKVHelp'
  4. interface CascadeInterface {
  5.   onClick?: (provinc: ProvinceBean) => void
  6.   close?: () => void
  7. }
  8. @Preview
  9. @CustomDialog
  10. export struct CascadeDialog {
  11.   controller: CustomDialogController
  12.   scrollerOne: Scroller = new Scroller()
  13.   scrollerTwo: Scroller = new Scroller()
  14.   scrollerThree: Scroller = new Scroller()
  15.   callback?: CascadeInterface
  16.   @State provinceList: ProvinceBean[] = new Array<ProvinceBean>()
  17.   @State cityList: ProvinceBean[] = new Array<ProvinceBean>()
  18.   @State areaList: ProvinceBean[] = new Array<ProvinceBean>()
  19.   @State selectId: string = ''
  20.   // 记录上次选择的数据在列表中的下标,显示数据时,自动滚动到可见位置
  21.   @State provinceIndex: number = 0
  22.   @State cityIndex: number = 0
  23.   @State areaIndex: number = 0
  24.   // 跟随父级 改变数据
  25.   @Prop provinceItem: ProvinceBean = new ProvinceBean()
  26.   // 临时记录省级数据
  27.   @State tempProvinceItem: ProvinceBean = new ProvinceBean()
  28.   aboutToAppear() {
  29.     let data = MMKV.defaultMMKV().decodeString(MMKVHelp.KEY_CITY)
  30.     if (data) {
  31.       this.selectId = this.provinceItem.id ? this.provinceItem.id : ''
  32.       this.provinceList = JSON.parse(data)
  33.       if (this.provinceList) {
  34.         this.provinceList.forEach((provinceBean, provinceIndex) => {
  35.           if (provinceBean.id == this.selectId) {
  36.             this.provinceIndex = provinceIndex
  37.             // 展开式 同步最新省级临时数据
  38.             this.tempProvinceItem = provinceBean
  39.             provinceBean.isSelect = true
  40.             this.cityList = provinceBean.children ? provinceBean.children : new Array<ProvinceBean>()
  41.             /**
  42.              * @Desc 一级列表匹配上 2种场景的点击
  43.              * 二级列表点击:1.全省 2.直辖市
  44.              */
  45.             this.cityList[0].isSelect = true
  46.           } else {
  47.             provinceBean.isSelect = false
  48.             provinceBean.children?.forEach((cityBean, cityIndex) => {
  49.               if (cityBean.id == this.selectId) {
  50.                 this.cityIndex = cityIndex
  51.                 this.provinceIndex = provinceIndex
  52.                 // 展开时,同步省级对应的数据
  53.                 this.tempProvinceItem = provinceBean
  54.                 provinceBean.isSelect = true
  55.                 cityBean.isSelect = true
  56.                 this.cityList = provinceBean.children ? provinceBean.children : new Array<ProvinceBean>()
  57.                 this.areaList = cityBean.children ? cityBean.children : new Array<ProvinceBean>()
  58.                 /**
  59.                  * @Desc 二级列表匹配上 存在4种场景的点击
  60.                  * 1.全省 2.直辖市 3.直辖市下的区 4.三级列表的全市(第一条)
  61.                  */
  62.                 if (cityBean.children && cityBean.children.length > 0) { //第4种场景:
  63.                   this.areaList[0].isSelect = true
  64.                 } else {
  65.                   // 直辖市下的区
  66.                   console.log('直辖市下的区' + cityBean.extName)
  67.                 }
  68.               } else {
  69.                 cityBean.isSelect = false
  70.                 cityBean.children?.forEach((areaBean, areaIndex) => {
  71.                   if (areaBean.id == this.selectId) {
  72.                     this.areaIndex = areaIndex
  73.                     this.cityIndex = cityIndex
  74.                     this.provinceIndex = provinceIndex
  75.                     console.log('--22222---' + this.provinceIndex + ' = ' + this.cityIndex + ' = ' + this.cityIndex)
  76.                     // 展开时,同步省对应的数据
  77.                     this.tempProvinceItem = provinceBean
  78.                     areaBean.isSelect = true
  79.                     provinceBean.isSelect = true
  80.                     cityBean.isSelect = true
  81.                     this.cityList = provinceBean.children ? provinceBean.children : new Array<ProvinceBean>()
  82.                     this.areaList = cityBean.children ? cityBean.children : new Array<ProvinceBean>()
  83.                   } else {
  84.                     areaBean.isSelect = false
  85.                   }
  86.                 })
  87.               }
  88.             })
  89.           }
  90.         })
  91.       }
  92.     }
  93.   }
  94.   build() {
  95.     Column() {
  96.       Row() {
  97.         List({ scroller: this.scrollerOne }) {
  98.           ForEach(this.provinceList, (provinceItem: ProvinceBean, index: number) => {
  99.             ListItem() {
  100.               Text(provinceItem.extName)
  101.                 .width('100%')
  102.                 .fontColor(provinceItem.isSelect ? '#007FFF' : '#FF000000')
  103.                 .fontSize(12)
  104.                 .padding({ left: 10, top: 10, bottom: 10 })
  105.             }.onClick(() => {
  106.               if (provinceItem.isSelect) {
  107.                 console.log('点击的相同地区' + provinceItem.extName)
  108.                 return
  109.               } else {
  110.                 this.cityList.forEach(item => {
  111.                   item.isSelect = false
  112.                 })
  113.                 this.areaList.forEach(item => {
  114.                   item.isSelect = false
  115.                 })
  116.                 this.areaList = new Array<ProvinceBean>()
  117.               }
  118.               this.tempProvinceItem = provinceItem
  119.               this.upProvinceList(provinceItem)
  120.               this.cityList = provinceItem.children ? provinceItem.children : new Array<ProvinceBean>()
  121.             })
  122.           })
  123.         }.layoutWeight(1)
  124.         .backgroundColor(Color.White)
  125.         .height('100%').onSizeChange(() => {
  126.           this.scrollerOne.scrollToIndex(this.provinceIndex)
  127.         })
  128.         List({ scroller: this.scrollerTwo }) {
  129.           ForEach(this.cityList, (cityItem: ProvinceBean, KEY) => {
  130.             ListItem() {
  131.               Text(cityItem.extName)
  132.                 .width('100%')
  133.                 .fontColor(cityItem.isSelect ? '#007FFF' : '#FF000000')
  134.                 .fontSize(12)
  135.                 .padding({ left: 10, top: 10, bottom: 10 })
  136.             }.onClick(() => {
  137.               // cityItem.children :无数据说明是直辖市/省 ,有数据说明是市下的区
  138.               if (cityItem.children && cityItem.children.length > 0) { // 切换省下面的市
  139.                 this.upCityList(cityItem)
  140.                 if (!cityItem.isSelect) {
  141.                   this.areaList.forEach(item => {
  142.                     item.isSelect = false
  143.                   })
  144.                 }
  145.                 this.areaList = cityItem.children ? cityItem.children : new Array<ProvinceBean>()
  146.               } else {
  147.                 //直辖市/省
  148.                 this.callback?.onClick!(cityItem)
  149.               }
  150.             })
  151.           })
  152.         }.layoutWeight(1).backgroundColor('#F6F6F6').height('100%').onSizeChange(() => {
  153.           this.scrollerTwo.scrollToIndex(this.cityIndex)
  154.         })
  155.         List({ scroller: this.scrollerThree }) {
  156.           ForEach(this.areaList, (areaItem: ProvinceBean, KEY) => {
  157.             ListItem() {
  158.               Text(areaItem.extName)
  159.                 .width('100%')
  160.                 .fontColor(areaItem.isSelect ? '#007FFF' : '#FF000000')
  161.                 .fontSize(12)
  162.                 .padding({ left: 10, top: 10, bottom: 10 })
  163.             }.onClick(() => {
  164.               this.callback?.onClick!(areaItem)
  165.             })
  166.           })
  167.         }.layoutWeight(1).backgroundColor('#F0F0F0').height('100%').onSizeChange(() => {
  168.           this.scrollerThree.scrollToIndex(this.areaIndex)
  169.         })
  170.       }.alignItems(VerticalAlign.Top)
  171.       .width('100%')
  172.       .height(500)
  173.     }.onClick(() => {
  174.       this.controller?.close!()
  175.     }).backgroundColor("#90000000").height('100%')
  176.   }
  177.   /**
  178.    * @Desc 更新省:自身列表的ui状态
  179.    */
  180.   private upProvinceList(provinceItem: ProvinceBean) {
  181.     let temp = this.provinceList
  182.     temp.forEach(item => {
  183.       if (provinceItem.id == item.id) {
  184.         item.isSelect = true
  185.       } else {
  186.         item.isSelect = false
  187.       }
  188.     })
  189.     this.provinceList = new Array<ProvinceBean>()
  190.     this.provinceList = temp
  191.   }
  192.   /**
  193.    * @Desc 更新城市:自身列表的ui状态
  194.    */
  195.   private upCityList(itemBean: ProvinceBean) {
  196.     let temp = this.cityList
  197.     temp.forEach(item => {
  198.       if (itemBean.id == item.id) {
  199.         item.isSelect = true
  200.       } else {
  201.         item.isSelect = false
  202.       }
  203.     })
  204.     this.cityList = new Array<ProvinceBean>()
  205.     this.cityList = temp
  206.   }
  207. }
复制代码


  • 使用
  1. @State provinceItem: ProvinceBean = new ProvinceBean()
  2. this.controller = new CustomDialogController({
  3.       builder: CascadeDialog({
  4.         provinceItem: this.provinceItem,
  5.         callback: {
  6.           onClick: (province: ProvinceBean) => {
  7.             console.log(JSON.stringify(province))
  8.             this.provinceItem = province
  9.             this.controller?.close()
  10.           }
  11.         }
  12.       }),
  13.       cancel: () => {
  14.         this.controller?.close()
  15.       },
  16.       offset: { dx: 0, dy: this.postionY },// 弹窗的偏移量
  17.       autoCancel: true,
  18.       customStyle: true,
  19.       maskColor: Color.Transparent,
  20.       openAnimation: { duration: 0 },
  21.       closeAnimation: { duration: 0 }
  22.     });
  23.     this.controller.open()
复制代码


  • 获取点击组件,组件底部距离屏幕顶部的高度
  1. .onClick((event: ClickEvent) => {
  2.       this.postionY = Number(event.target.area.height) + Number(event.target.area.globalPosition.y)  
  3.     })
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

郭卫东

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表