效果图示意

代码截图示意


实现需求描述
好的,我重新为您总结一份专注于三级联动核心逻辑的笔记:
省市区三级联动笔记
1. 核心数据结构
@State range: string[][] = [['北京'], ['北京市'], ['东城区']] // TextPicker数据源
@State selected: number[] = [0, 0, 0] // 控制高亮位置
@State values: string[] = ['北京', '北京市', '东城区'] // 实际选中的值
@State timeID: number = 0 // 防抖定时器
2. 联动触发机制
TextPicker的onChange事件
.onChange((value) => {
const _pname = value[0] // 当前高亮的省份
const _cname = value[1] // 当前高亮的城市
const _aname = value[2] // 当前高亮的地区
// 防抖处理
clearTimeout(this.timeID)
this.timeID = setTimeout(async () => {
// 三级联动逻辑
}, 300)
})
3. 三级联动核心逻辑
第一级:省份变更联动
if (this.values[0] !== value[0]) {
// 1. 更新省份显示值
this.values[0] = _pname
// 2. 重新获取城市数据
const city = await this.req.request(`https://hmajax.itheima.net/api/city?pname=${encodeURIComponent(this.values[0])}`)
this.range[1] = (JSON.parse(city.result.toString()) as IResponse).list
this.values[1] = this.range[1][0] // 重置为第一个城市
// 3. 重新获取地区数据
const area = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.values[0])}&cname=${encodeURIComponent(this.values[1])}`)
this.range[2] = (JSON.parse(area.result.toString()) as IResponse).list
this.values[2] = this.range[2][0] // 重置为第一个地区
// 4. 重置下级高亮位置
this.selected[1] = 0 // 城市高亮重置
this.selected[2] = 0 // 地区高亮重置
return
}
第二级:城市变更联动
if (this.values[1] !== value[1]) {
// 1. 更新城市显示值
this.values[1] = _cname
// 2. 重新获取地区数据
const area = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.values[0])}&cname=${encodeURIComponent(this.values[1])}`)
this.range[2] = (JSON.parse(area.result.toString()) as IResponse).list
this.values[2] = this.range[2][0] // 重置为第一个地区
// 3. 重置地区高亮位置
this.selected[2] = 0
return
}
第三级:地区变更
// 直接更新地区显示值
this.values[2] = _aname
4. 联动机制关键点
数据流控制
range→ TextPicker显示的数据源values→ 页面实际显示的值selected→ TextPicker高亮位置控制
级联更新策略
- 省份变更:清空城市和地区数据,重新加载,重置高亮位置
- 城市变更:清空地区数据,重新加载,重置地区高亮位置
- 地区变更:仅更新显示值
防抖机制
clearTimeout(this.timeID)
this.timeID = setTimeout(async () => {
// 联动逻辑
}, 300)
- 避免用户快速滑动时频繁请求接口
- 300ms延迟确保操作稳定
5. API接口调用模式
接口参数传递
- 省份接口:
/api/province - 城市接口:
/api/city?pname=${省份名} - 地区接口:
/api/area?pname=${省份名}&cname=${城市名}
数据更新流程
- 用户滑动 → onChange触发
- 判断哪一级发生变化
- 清空下级数据并重新请求
- 更新显示值和高亮位置
6. 联动逻辑总结
核心思想:上级变更时,下级数据必须重新获取并重置为第一项
实现要点:
- 使用
this.values[0] !== value[0]判断是否真正发生变化 - 上级变更时,下级数据用
this.range[x] = 新数据更新 - 下级显示值用
this.values[x] = this.range[x][0]重置为第一项 - 下级高亮位置用
this.selected[x] = 0重置
这种设计确保了三级数据的级联更新和用户体验的流畅性。
相关接口



全部代码
import http from '@ohos.net.http';
interface IResponse {
message: string
list: string[]
}
@Entry
@Component
struct Day03_06_AreaChange {
@State message: string = '居住地选择';
@State range: string[][] = [['北京'], ['北京市'], ['东城区']]// 在滑动组件中显示的数据 //index [ [0][0], [1][0] ,[2][0] ]
@State selected: number[] = [0, 0, 0]//// 控制滑动组件中数据的高亮
@State values: string[] = ['北京', '北京市', '东城区'] // 这部分信息的目的是渲染到页面上
req: http.HttpRequest = http.createHttp() // 请求对象
@State showSheet: boolean = false // 半模态的显示
@State timeID: number = 0 // 定时器的id
// 初始化数据的加载显示
async aboutToAppear() {
//省份
const res1 = await this.req.request(`https://hmajax.itheima.net/api/province`)
this.range[0] = (JSON.parse(res1.result.toString()) as IResponse).list //默认第一个省份
this.values[0] = this.range[0][0] //页面数据初始时 省份 显示第一个数据
// 城市
const res2 = await this.req.request(`https://hmajax.itheima.net/api/city?pname=${encodeURIComponent(this.range[0][0])}`)
this.range[1] = (JSON.parse(res2.result.toString()) as IResponse).list
AlertDialog.show({ message: JSON.stringify(this.range[1]) })
this.values[1] = this.range[1][0] //页面数据初始时 城市 显示第一个数据
// 地区
const res3 = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.range[0][0])}&cname=${encodeURIComponent(this.range[1][0])}`)
this.range[2] = (JSON.parse(res3.result.toString()) as IResponse).list
this.values[2] = this.range[2][0] //页面数据初始时 地区 显示第一个数据
}
build() {
Column({ space: 10 }) {
// 标题
Text(this.message)
.fontSize(30)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
.width('100%')
.margin({ bottom: 20 })
//页面显示的地址数据
Row({ space: 10 }) {
Text('居住地:')
.fontWeight(FontWeight.Bold)
Text(this.values.join('/'))
.layoutWeight(1)
.fontColor(Color.Gray)
.onClick(() => {
this.showSheet = true
})
Image($r('app.media.ic_public_arrow_right'))
.width(20)
}
Divider()
Blank()
}
.height('100%')
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding(20)
.bindSheet($$this.showSheet, this.areaSheet(), {
height: 300
})
}
@Builder
areaSheet() {
Column() {
// TextPicker 级联组件 滑动选择文本内容的组件
TextPicker({
range: this.range,//在滑动组件中显示的数据
selected: $$this.selected,//控制滑动组件中数据的高亮
})
.canLoop(false)
//onChange事件 的形参 返回数组 数组中显示的是滑动的高亮数据 ['北京', '北京市', '东城区']
.onChange((value) => {
console.log(`123`, value)
const _pname = value[0] //省份 高亮数据
const _cname = value[1] //城市 高亮数据
const _aname = value[2] //地区 高亮数据
// 先清理一下定时器
clearTimeout(this.timeID)
this.timeID = setTimeout(async () => {
// 处理业务
// 1.判断 滑动后高亮的省份 和页面上显示的地址的省份 是否一致,
// 如果不一致,进if判断
if (this.values[0] !== value[0]) {
// 1.1 高亮的省份 赋值给 页面显示地址的省份
this.values[0] = _pname
// 1.2 滑动省份时 城市和地区联动
// 城市的联动
const city =
await this.req.request(`https://hmajax.itheima.net/api/city?pname=${encodeURIComponent(this.values[0])}`)
this.range[1] = (JSON.parse(city.result.toString()) as IResponse).list //滑动省份时 对应省份下面的所有城市数据
this.values[1] = this.range[1][0] //滑动省份时 对应省份下面的城市数据中 页面上的地址显示第一个城市
// 地区的联动
const area =
await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.values[0])}&cname=${encodeURIComponent(this.values[1])}`)
this.range[2] = (JSON.parse(area.result.toString()) as IResponse).list //滑动省份时 选择对应城市下面的 所有地区的数据
this.values[2] = this.range[2][0] //滑动省份时 选择对应城市下面的 所有地区数据中 页面上的地址显示第一个地区
// 1.3 切换省份时 城市和地区第一个高亮
this.selected[1] = 0 //城市 高亮
this.selected[2] = 0 //地区 高亮
return
}
// 2.判断滑动后高亮的地址 和页面上显示地址的城市 是否一致
// 如果不一致,进if判断
if (this.values[1] !== value[1]) {
//2.1 高亮的城市 赋值给页面上显示地址的城市
this.values[1] = _cname
//2.2 滑动城市时 地区联动
const area =
await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.values[0])}&cname=${encodeURIComponent(this.values[1])}`)
this.range[2] = (JSON.parse(area.result.toString()) as IResponse).list //滑动城市时 对应城市下面的所有地区数据
this.values[2] = this.range[2][0] //滑动城市时 选择对应地区下面的 页面上的地址显示第一个地区
//2.3 切换城市时 地区第一个高亮
this.selected[2] = 0 // 地区 高亮
return
}
// 3.滑动高亮的地区 赋值给页面上显示地址中的地区
this.values[2] = _aname
}, 300)
})
}
}
}
1611

被折叠的 条评论
为什么被折叠?



