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

news2024/9/21 16:43:31

效果图

在这里插入图片描述

完整代码

  • 实例对象
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[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
  }
}

  • 使用
 @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)  
    })

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1948202.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MLIR的TOY教程学习笔记

MLIR TOY Language 文章目录 MLIR TOY Language如何编译该项目ch1: MLIR 前端IR解析ch2: 定义方言和算子 (ODS)1. 定义方言2. 定义OP3. OP相关操作4. 定义OP ODS (Operation Definition Specification)1. 基本定义2. 添加文档3. 验证OP4. 新增构造函数5. 定义打印OP的格式 ch3:…

【数据结构】:用Java实现链表

在 ArrayList 任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后搬移&#xff0c;时间复杂度为 O(n)&#xff0c;效率比较低&#xff0c;因此 ArrayList 不适合做任意位置插入和删除比较多的场景。因此&#xff1a;java 集合中又引入了 LinkedList&…

电脑怎么恢复删除的文件?8个方法,简单搞定文件恢复!(强力推荐)

电脑怎么恢复删除的文件&#xff1f;随着如今几乎每个人都拥有或使用计算机&#xff0c;文件丢失和误删已成为我们在日常计算机使用中难以避免的问题之一。在我们使用计算机的过程中&#xff0c;经常会遇到各种问题&#xff0c;有些可以轻松解决&#xff0c;而有些可能需要专业…

键盘是如何使用中断机制的?当打印一串字符到显示屏上时发生了什么???

当在键盘上按下一个键时会进行一下操作&#xff1a; 1.当按下任意一个键时&#xff0c;键盘编码器监控会来判断按下的键是哪个 2.键盘控制器用将解码,将键盘的数据保存到键盘控制器里数据寄存器里面 3.此时发送一个中断请求给中断控制器&#xff0c;中断控制器获取到中断号发送…

Spring Security认证授权介绍

一、目标 真正控制系统权限的&#xff0c;需要引入专门的安全框架才行&#xff0c;所以&#xff0c;我们今天重点来学习Spring家族中的一员Spring Security安全框架。最终呢&#xff0c;我们会使用Spring Security框架来控制养老项目的后台管理系统 能够熟悉常见的权限控制的方…

释疑 803-(1)概述 精炼提纯版

目录 习题 1-01计算机网络可以向用户提供哪些服务? 1-02 试简述分组交换的要点。 1-03 试从多个方面比较电路交换、报文交换和分组交换的主要优缺点。 1-05 互联网基础结构的发展大致分为哪几个阶段?请指出这几个阶段最主要的特点。 1-06 简述互联网标准制定的几个阶段…

导航网站WP主题/WP黑格导航主题BlackCandy-简约酷黑色高逼格+焕然一新的UI设计

源码简介&#xff1a; 导航网站WP主题-WP黑格导航主题BlackCandy&#xff0c;它有着简约酷黑色高逼格&#xff0c;而且有焕然一新的UI设计。它是一个简约漂亮的 WordPress 自媒体主题。黑格网址导航主题&#xff0c;自适应电脑端和手机端。 BlackCandy-V2.0这次全新升级了&am…

Godot游戏制作 03世界构建1.0版

在game场景&#xff0c;删除StaticBody2D节点&#xff0c;添加TileMap节点 添加TileSet图块集 添加TileSet源 拖动图片到图块&#xff0c;自动创建图块 使用橡皮擦擦除。取消橡皮擦后按住Shift创建大型图块。 进入选择模式&#xff0c;TileMap选择绘制&#xff0c;选中图块后在…

什么是设备运维管理系统?有什么作用?(6款设备运维管理系统推荐)

一、什么是设备运维管理系统&#xff1f; 设备运维管理系统是一种集成了监控、管理、维护和优化设备性能的软件平台。它旨在通过自动化的手段&#xff0c;提高设备运行的可靠性和效率&#xff0c;降低运维成本&#xff0c;并优化资源利用。 设备运维管理系统能够实时监控设备…

Springboot 开发之 RestTemplate 简介

一、什么是RestTemplate RestTemplate 是Spring框架提供的一个用于应用中调用REST服务的类。它简化了与HTTP服务的通信&#xff0c;统一了RESTFul的标准&#xff0c;并封装了HTTP连接&#xff0c;我们只需要传入URL及其返回值类型即可。RestTemplate的设计原则与许多其他Sprin…

Web响应式设计———1、Grid布局

1、网格布局 Grid布局 流动网格布局是响应式设计的基础。它通过使用百分比而不是固定像素来定义网格和元素的宽度。这样&#xff0c;页面上的元素可以根据屏幕宽度自动调整大小&#xff0c;适应不同设备和分辨率。 <!DOCTYPE html> <html lang"en"> &l…

代码随想录算法训练营第23天| 39. 组合总和 ,40.组合总和II ,131.分割回文串

学习任务&#xff1a; 39. 组合总和 40.组合总和II 131.分割回文串 Leetcode39. 组合总和 难度&#xff1a;中等 | 相关标签&#xff1a;数组、回溯 题目&#xff1a; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以…

阿里云公共DNS免费版自9月30日开始限速 企业或商业场景需使用付费版

本周阿里云发布公告对公共 DNS 免费版使用政策进行调整&#xff0c;免费版将从 2024 年 9 月 30 日开始按照请求源 IP 进行并发数限制&#xff0c;单个 IP 的请求数超过 20QPS、UDP/TCP 流量超过 2000bps 将触发限速策略。 阿里云称免费版的并发数限制并非采用固定的阈值&…

Android 15 适配整理——实践版

背景 谷歌发布Android 15后&#xff0c;国内的手机厂商迅速行动&#xff0c;开始了新系统的适配工作。小米、OPPO、vivo和联想等金标联盟成员联合发布了适配公告&#xff0c;督促APP开发者在2024年8月31日前完成适配工作&#xff0c;否则将面临搜索标签提示、应用降级、分机型…

MySQL数据库-库表操作

一、SQL语句基础 1.SQL简介 SQL&#xff1a;结构化查询语言&#xff08;Structured Query Language&#xff09;&#xff0c;在关系型数据库上执行数据操作、数据检索以及数据维护的标准语言。使用SQL语句&#xff0c;程序员和数据库管理员可以完成如下任务&#xff1a; &am…

Leetcode—426. 将二叉搜索树转化为排序的双向链表【中等】Plus

2024每日刷题&#xff08;148&#xff09; Leetcode—426. 将二叉搜索树转化为排序的双向链表 实现代码 /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node() {}Node(int _val) {val _val;left NULL;right NULL;}Node(int _val, Nod…

开放式耳机怎么选购性价比高?五大好评不断的爆款分享

长期使用入耳式耳机的朋友应该都会有这种担忧&#xff0c;经常塞着耳朵听歌&#xff0c;耳机上的细菌得不到及时的清理&#xff0c;不够健康卫生&#xff0c;还有诱发耳部发炎感染的风险。而开放式耳机的出现恰好缓解了这种担忧。如果你也想知道开放式耳机是否真有网上宣传的那…

Photos框架 - 自定义媒体选择器(UI列表)

引言Photos框架 - 自定义媒体资源选择器&#xff08;数据部分&#xff09;-CSDN博客 关于自定义媒体选择器上一篇博客我们已经介绍了使用Photos获取媒体资源数据和处理媒体资源数据&#xff0c;有了数据&#xff0c;UI的实现就比较灵活了&#xff0c;我就以上面的设计样式为例…

学习React(描述 UI)

React 是一个用于构建用户界面&#xff08;UI&#xff09;的 JavaScript 库&#xff0c;用户界面由按钮、文本和图像等小单元内容构建而成。React 帮助你把它们组合成可重用、可嵌套的 组件。从 web 端网站到移动端应用&#xff0c;屏幕上的所有内容都可以被分解成组件。在本章…

08 字符串和字节串

使用单引号、双引号、三单引号、三双引号作为定界符&#xff08;delimiter&#xff09;来表示字符串&#xff0c;并且不同的定界符之间可以相互嵌套。 很多内置函数和标准库对象也都支持对字符串的操作。 x hello world y Python is a great language z Tom said, "Le…