省市区获取
~~运用知识点
Promise async await
Promise是一种用于处理异步操作的对象,可以将异步操作转换为类似于同步操作的风格,以方便代码编写和维护
**简而言之:**Promise 用来管理异步,方便编码
- 处理异步操作成功与失败
- 能够解决回调函数地狱
一、回调函数地狱
如果回调函数一直【嵌套】下去,代码的可读性会非常糟糕
一般在多个异步操作【彼此依赖】的时候会出现回调函数嵌套的情况,(c 依赖 b,b 依赖 a),比如:
- 获取所有省份
- 获取第一个省的所有城市
- 获取第一个城市的所有地区
这里的数据来源于 3 个接口,【地区】 依赖于 【城市】 、【城市】 依赖于【 省】,所以代码写起来会是这样的结果(较为繁琐复杂)
这段代码主要为获取北京的地区(这段代码回调函数会一直嵌套下去,可读性差)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import http from '@ohos.net.http'
const req = http.createHttp()
interface Province { message: string list: string[] }
@Entry @Component struct TextPickerExample { @State apfruits: string[] = [] orfruits: string[] = ['orange1', 'orange2', 'orange3', 'orange4'] pefruits: string[] = ['peach1', 'peach2', 'peach3', 'peach4'] @State multi: string[][] = [this.apfruits, this.orfruits, this.pefruits]
aboutToAppear(): void { req.request('https://hmajax.itheima.net/api/province') .then(res => { const result = JSON.parse(res.result.toString()) as Province //this.apfruits = result.list // 获取省份信息 this.multi[0] = result.list // 获取一个省份的城市信息 req.request('https://hmajax.itheima.net/api/city?pname=' + encodeURIComponent(this.multi[0][0])) .then(res => { const result = JSON.parse(res.result.toString()) as Province this.multi[1] = result.list req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.multi[0][0])}&cname=${encodeURIComponent(this.multi[1][0])}`) .then(res => { const result = JSON.parse(res.result.toString()) as Province this.multi[2] = result.list }) }) }) }
build() { Column() { TextPicker({ range: this.multi }).canLoop(false) } } }
|
二、链式编程-基本使用
我们可以通过 Promise 的链式编程来解决这个问题(Promise 的 then 方法会返回一个新Promise 对象)
1 2 3 4 5 6 7 8 9
| promise对象1.then(res1=>{ promise对象2.then(res2=>{ promise对象3.then(res3=>{ promise对象4.then(res4=>{ //.... 可以一直写下去 }) }) }) })
|
上面代码aboutToAppear修改为Promise链式编程代码可读性就会提升很多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| aboutToAppear(): void { req.request('https://hmajax.itheima.net/api/province') .then(res => { const result = JSON.parse(res.result.toString()) as Province // 获取省份信息 this.multi[0] = result.list return req.request('https://hmajax.itheima.net/api/city?pname=' + encodeURIComponent(this.multi[0][0])) }) .then(res => { const result = JSON.parse(res.result.toString()) as Province this.multi[1] = result.list return req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.multi[0][0])}&cname=${encodeURIComponent(this.multi[1][0])}`) }) .then(res => { const result = JSON.parse(res.result.toString()) as Province this.multi[2] = result.list }) }
|
第二个aboutToAppear为修改为Promise链式编程代码的代码
三、async await 完成省市区获取
Promise 虽然不用嵌套了,但是依旧有回调函数,可以用 async 函数进一步优化
核心步骤:
- async 修饰函数
- await 等待成功(Promise 对象)
基本用法:
1 2 3 4 5 6 7
| async function func() { // await 获取到的是 之后 Promise 对象的成功结果 const res1 = await Promise对象1 const res2 = await Promise对象2 const res3 = await Promise对象3 } func()
|
进一步优化代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| import http from '@ohos.net.http';
interface IResponse { message: string list: string[] }
@Entry @Component struct Day03_06_AreaChange { @State message: string = '居住地选择'; @State range: string[][] = [['北京'], ['北京市'], ['东城区']] @State selected: number[] = [0, 0, 0] // 这部分信息的目的是渲染到页面上 @State values: string[] = ['北京', '北京市', '东城区'] // 请求对象 req: http.HttpRequest = http.createHttp() @State showSheet: boolean = false
async aboutToAppear() { const Province_Res = await this.req.request('https://hmajax.itheima.net/api/province') const result_Pro = JSON.parse(Province_Res.result.toString()) as IResponse // 获取省份信息 this.range[0] = result_Pro.list
const city_Res = await this.req.request('https://hmajax.itheima.net/api/city?pname=' + encodeURIComponent(this.range[0][0])) const result_City = JSON.parse(city_Res.result.toString()) as IResponse // 获取省份信息 this.range[1] = result_City.list
const area_Res = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.range[0][0])}&cname=${encodeURIComponent(this.range[1][0])}`) const result_Area = JSON.parse(area_Res.result.toString()) as IResponse this.range[2] = result_Area.list }
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({ range: this.range, selected: $$this.selected, // value: $$this.values // }) .canLoop(false) } } }
|
第一种情况:改变省份信息
利用TextPicker的onChange事件(当用户滑动时改变数据触发)
这段代码考虑第一种情况:用户改变省份信息(即滑动第一列)此时需要根据用户挑选的省重新进行网络请求获取对应的城市以及地区,同时城市及地区需要指向每列第一个(上段代码中定义了一个状态变量selected与TextPicker进行双向绑定 表示指向第几个省份,城市,地区)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| 接上段代码areaSheet部分 @Builder areaSheet() { Column() { TextPicker({ range: this.range, selected: $$this.selected, // value: $$this.values // }) .canLoop(false) .onChange(async (value, index) => { // 改变省份 if (this.values[0] != value[0]) { // 1. 刷新省份 const Province_Res = value[0] // 省份赋值 this.values[0] = value[0]
const city_Res = await this.req.request('https://hmajax.itheima.net/api/city?pname=' + encodeURIComponent(Province_Res)) const result_City = JSON.parse(city_Res.result.toString()) as IResponse // 获取省份信息 this.range[1] = result_City.list // 将城市指向到第一个 this.selected[1] = 0 // 赋值城市信息 this.values[1] = this.range[1][0]
// 查询地区信息 const cname = this.range[1][0] const area_Res = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(Province_Res)}&cname=${encodeURIComponent(cname)}`) const result_Area = JSON.parse(area_Res.result.toString()) as IResponse this.range[2] = result_Area.list // 将地区指向到第一个 this.selected[2] = 0 // 赋值地区 this.values[2] = this.range[2][0] } // console.log('这次' + value + '上次' + this.values[0]);
}) } } }
|
第二种情况:改变市
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| // 第二种情况 改变市 if (this.values[1] != value[1]) { // 保存最新选中的市 避免重复触发 this.values[1] = value[1] // 查询地区信息 const cname = value[1] const area_Res = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(value[0])}&cname=${encodeURIComponent(cname)}`) const result_Area = JSON.parse(area_Res.result.toString()) as IResponse this.range[2] = result_Area.list // 将地区指向到第一个 this.selected[2] = 0 // 赋值地区 this.values[2] = this.range[2][0] return }
|
第三种情况:改变地区
直接赋值到状态变量value即可
1 2 3 4 5
| // 第三种 改变区 if (this.values[2] != value[2]) { // 直接赋值value即可 this.values[2] = value[2] }
|
问题:函数防抖
常见的性能优化方案 , 它可以防止高频渲染页面时出现的视觉抖动(卡顿)
为解决该问题可以设定一个定时器,如果用户在一定时间内不操作则执行逻辑(连续事件停止触发后,一段时间内如果没有再次触发,就执行业务代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| @Builder areaSheet() { Column() { TextPicker({ range: this.range, selected: $$this.selected, // value: $$this.values // }) .canLoop(false) .onChange(async (value, index) => { // 清除上一次timeID clearTimeout(this.timeID) // 改变省份 // 函数防抖 this.timeID = setTimeout(async () => { // 第一种情况 改变省份:市区都需要重新获取并还原到每列第一个 if (this.values[0] != value[0]) { // 1. 刷新省份 const Province_Res = value[0] // 省份赋值 this.values[0] = value[0]
const city_Res = await this.req.request('https://hmajax.itheima.net/api/city?pname=' + encodeURIComponent(Province_Res)) const result_City = JSON.parse(city_Res.result.toString()) as IResponse // 获取省份信息 this.range[1] = result_City.list // 将城市指向到第一个 this.selected[1] = 0 // 赋值城市信息 this.values[1] = this.range[1][0]
// 查询地区信息 const cname = this.range[1][0] const area_Res = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(Province_Res)}&cname=${encodeURIComponent(cname)}`) const result_Area = JSON.parse(area_Res.result.toString()) as IResponse this.range[2] = result_Area.list // 将地区指向到第一个 this.selected[2] = 0 // 赋值地区 this.values[2] = this.range[2][0]
return }
// 第二种情况 改变市 if (this.values[1] != value[1]) { // 保存最新选中的市 避免重复触发 this.values[1] = value[1] // 查询地区信息 const cname = value[1] const area_Res = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(value[0])}&cname=${encodeURIComponent(cname)}`) const result_Area = JSON.parse(area_Res.result.toString()) as IResponse this.range[2] = result_Area.list // 将地区指向到第一个 this.selected[2] = 0 // 赋值地区 this.values[2] = this.range[2][0] return }
// 第三种 改变区 if (this.values[2] != value[2]) { // 直接赋值value即可 this.values[2] = value[2] } }, 500) }) } } }
|
四、案例~完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
import http from '@ohos.net.http';
interface IResponse { message: string list: string[] }
@Entry @Component struct Day03_06_AreaChange { @State message: string = '居住地选择'; @State range: string[][] = [['北京'], ['北京市'], ['东城区']] @State selected: number[] = [0, 0, 0] // 这部分信息的目的是渲染到页面上 @State values: string[] = ['北京', '北京市', '东城区'] // 请求对象 req: http.HttpRequest = http.createHttp() @State showSheet: boolean = false timeID: number = -1 // 设置定时器id
async aboutToAppear() { const Province_Res = await this.req.request('https://hmajax.itheima.net/api/province') const result_Pro = JSON.parse(Province_Res.result.toString()) as IResponse // 获取省份信息 this.range[0] = result_Pro.list
const city_Res = await this.req.request('https://hmajax.itheima.net/api/city?pname=' + encodeURIComponent(this.range[0][0])) const result_City = JSON.parse(city_Res.result.toString()) as IResponse // 获取省份信息 this.range[1] = result_City.list
const area_Res = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.range[0][0])}&cname=${encodeURIComponent(this.range[1][0])}`) const result_Area = JSON.parse(area_Res.result.toString()) as IResponse this.range[2] = result_Area.list }
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({ range: this.range, selected: $$this.selected, // value: $$this.values // }) .canLoop(false) .onChange(async (value, index) => { // 清除上一次timeID clearTimeout(this.timeID) // 改变省份 // 函数防抖 this.timeID = setTimeout(async () => { // 第一种情况 改变省份:市区都需要重新获取并还原到每列第一个 if (this.values[0] != value[0]) { // 1. 刷新省份 const Province_Res = value[0] // 省份赋值 this.values[0] = value[0]
const city_Res = await this.req.request('https://hmajax.itheima.net/api/city?pname=' + encodeURIComponent(Province_Res)) const result_City = JSON.parse(city_Res.result.toString()) as IResponse // 获取省份信息 this.range[1] = result_City.list // 将城市指向到第一个 this.selected[1] = 0 // 赋值城市信息 this.values[1] = this.range[1][0]
// 查询地区信息 const cname = this.range[1][0] const area_Res = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(Province_Res)}&cname=${encodeURIComponent(cname)}`) const result_Area = JSON.parse(area_Res.result.toString()) as IResponse this.range[2] = result_Area.list // 将地区指向到第一个 this.selected[2] = 0 // 赋值地区 this.values[2] = this.range[2][0]
return }
// 第二种情况 改变市 if (this.values[1] != value[1]) { // 保存最新选中的市 避免重复触发 this.values[1] = value[1] // 查询地区信息 const cname = value[1] const area_Res = await this.req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(value[0])}&cname=${encodeURIComponent(cname)}`) const result_Area = JSON.parse(area_Res.result.toString()) as IResponse this.range[2] = result_Area.list // 将地区指向到第一个 this.selected[2] = 0 // 赋值地区 this.values[2] = this.range[2][0] return }
// 第三种 改变区 if (this.values[2] != value[2]) { // 直接赋值value即可 this.values[2] = value[2] } }, 500) }) } } }
|