加载中...

数组方法与状态管理


数组方法

(1) map方法

map() 方法创建一个新数组,基于原数组,创建一个新数组(映射)

用法

1
数组.map<返回值类型>((数组项,索引)=>{ return xxx })

1.map简单使用:将一个对象数组中的某个属性值=>一个新的数组中返回

  1. 将一个数组映射为一个对象数组

注意: 在映射返回对象为对象时应该需要用泛型来约束返回的值

(2) filter方法

根据回调函数的执行结果,筛选出符合要求的元素,返回一个新数组

先举一个简单的例子:根据数组 选出所有成绩 < 60的数据,存储到一个数组中

使用filter方法进行数据筛选:如果符合小于60的则为true 赋值到res中

案例:王者英雄筛选

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
interface HeroInfo {
id: number
name: string
title: string
type: string
avatar: string
}

// 筛选条件: 全部、战士、法师、坦克、刺客、射手、辅助
const arr: HeroInfo[] = [
{
id: 116,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/116/116.jpg',
name: '阿轲',
title: '信念之刃',
type: '刺客'
},
{
id: 117,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/117/117.jpg',
name: '钟无艳',
title: '野蛮之锤',
type: '战士'
},
{
id: 118,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/118/118.jpg',
name: '孙膑',
title: '逆流之时',
type: '辅助'
},
{
id: 119,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/119/119.jpg',
name: '扁鹊',
title: '善恶怪医',
type: '法师'
},
{
id: 120,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/120/120.jpg',
name: '白起',
title: '最终兵器',
type: '坦克'
},
{
id: 121,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/121/121.jpg',
name: '芈月',
title: '永恒之月',
type: '法师'
},
{
id: 123,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/123/123.jpg',
name: '吕布',
title: '无双之魔',
type: '战士'
},
{
id: 132,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/132/132.jpg',
name: '马可波罗',
title: '远游之枪',
type: '射手'
},
{
id: 133,
avatar: 'https://game.gtimg.cn/images/yxzj/img201606/heroimg/133/133.jpg',
name: '狄仁杰',
title: '断案大师',
type: '射手'
},
]

/*TODO
* 1. 默认选中全部 点击对应的选项变为高亮效果(切换高亮效果 定义状态变量)
* 2. 根据选择的类型筛选arr数组 返回新的对象到一个新的数组中(heroList)

*/

@Entry
@Component
struct Func3 {
@State heroList: HeroInfo[] = arr
@State selectIndex: number = 0
filterList: string[] = ['全部', '战士', '法师', '坦克', '刺客', '射手', '辅助']

build() {
Column() {
Row() {
ForEach(this.filterList, (item: string, index: number) => {
Text(item)
.onClick(() => {
this.selectIndex = index
let type = this.filterList[this.selectIndex] // 选中类型
this.heroList = arr.filter((hero) => {
if (type == '全部') {
return true
}
return hero.type == type
})
//console.log(JSON.stringify(this.heroList))
})
.border({
width: { bottom: 2 },
color: index == this.selectIndex ? Color.Orange : Color.Transparent
})

.padding({ bottom: 3 })
.fontColor(index == this.selectIndex ? Color.Orange : Color.Black)
.fontSize(index == this.selectIndex ? 18 : 13)
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding({ top: 10, bottom: 10 })

List({ space: 10 }) {
ForEach(this.heroList, (item: HeroInfo, index) => {
ListItem() {
Row({ space: 10 }) {
Image(item.avatar)
.width(50)
.borderRadius(10)
Column({ space: 10 }) {
Text(item.name)
Text(item.type)
.fontSize(12)
.fontColor(Color.Gray)
}
.alignItems(HorizontalAlign.Start)
}
.backgroundColor('#f8f9fc')
.width('100%')
.padding(5)
.borderRadius(10)
}
})


}
}
.width('100%')
.height('100%')
.padding(20)
}
}

(3) sort方法

return的值大于0则需要交换 小于等于0不交换

(4)reduce

1
2
3
4
5
6
7
8
9
10
11
12
13
let arr = [1, 5, 3, 2, 4]

// 累加
/*
const res = arr.reduce((上一次累加完的结果, 当前项, 下标) => {
return 上一次累加完的结果+当前项(本次累加后的结果)
}, 0)
*/
const res = arr.reduce((sum: number, nex: number) => {
return sum + nex
}, 0)
// TODO 0表示从0开始累加
console.log(res.toString())

状态管理

@State

@State装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就可以触发其直接绑定UI组件的刷新。当状态改变时,UI会发生对应的渲染改变。

但是并不是状态变量的所有更改都会引起UI的刷新,只有可以被框架观察到的修改才会引起UI刷新。

  • 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
  • 当装饰的数据类型为class或者Object时,@State修饰的变量 默认只能够监视【自身】和【第一层】

如图所示 this.person.dog.name为第二层 所以@State修饰的状态变量会发生变化但是不会引起UI的渲染

@Prop

为什么会有:普通传值,默认是不会联动的,父亲修改了,子不会自动更新

@Prop表示父传子,传递过来的数据,父修改,子也会进行修改

案例 知乎

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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
import { CommentItem } from '../components'


export interface ReplyItem {
id: number
avatar: ResourceStr
author: string
content: string
time: string
area: string
likeNum: number
likeFlag: boolean
}

class ReplyData {
// 用户回复列表
static getCommentList(): ReplyItem[] {
return [
{
id: 1,
avatar: 'https://picx.zhimg.com/027729d02bdf060e24973c3726fea9da_l.jpg?source=06d4cd63',
author: '偏执狂-妄想家',
content: '更何况还分到一个摩洛哥[惊喜]',
time: '11-30',
area: '海南',
likeNum: 34,
likeFlag: false
},
{
id: 2,
avatar: 'https://pic1.zhimg.com/v2-5a3f5190369ae59c12bee33abfe0c5cc_xl.jpg?source=32738c0c',
author: 'William',
content: '当年希腊可是把1:0发挥到极致了',
time: '11-29',
area: '北京',
likeNum: 58,
likeFlag: true
},
{
id: 3,
avatar: 'https://picx.zhimg.com/v2-e6f4605c16e4378572a96dad7eaaf2b0_l.jpg?source=06d4cd63',
author: 'Andy Garcia',
content: '欧洲杯其实16队球队打正赛已经差不多,24队打正赛意味着正赛阶段在小组赛一样有弱队。',
time: '11-28',
area: '上海',
likeNum: 10,
likeFlag: false
},
{
id: 4,
avatar: 'https://picx.zhimg.com/v2-53e7cf84228e26f419d924c2bf8d5d70_l.jpg?source=06d4cd63',
author: '正宗好鱼头',
content: '确实眼红啊,亚洲就没这种球队,让中国队刷',
time: '11-27',
area: '香港',
likeNum: 139,
likeFlag: true
},
{
id: 5,
avatar: 'https://pic1.zhimg.com/v2-eeddfaae049df2a407ff37540894c8ce_l.jpg?source=06d4cd63',
author: '柱子哥',
content: '我是支持扩大的,亚洲杯欧洲杯扩到32队,世界杯扩到64队才是好的,世界上有超过200支队伍,欧洲区55支队伍,亚洲区47支队伍,即使如此也就六成出现率',
time: '11-27',
area: '旧金山',
likeNum: 29,
likeFlag: false
},
{
id: 6,
avatar: 'https://picx.zhimg.com/v2-fab3da929232ae911e92bf8137d11f3a_l.jpg?source=06d4cd63',
author: '飞轩逸',
content: '禁止欧洲杯扩军之前,应该先禁止世界杯扩军,或者至少把亚洲名额一半给欧洲。',
time: '11-26',
area: '里约',
likeNum: 100,
likeFlag: false
}
]
}

// 作者信息
static getRootComment(): ReplyItem {
return {
id: 1,
avatar: $r('app.media.avatar'),
author: '周杰伦',
content: '意大利拌面应该使用42号钢筋混凝土再加上量子力学缠绕最后通过不畏浮云遮望眼',
time: '11-30',
area: '海南',
likeNum: 98,
likeFlag: true
}
}
}

@Entry
@Component
struct ZhiHu {
@State commentList: ReplyItem[] = ReplyData.getCommentList()
@State rootComment: ReplyItem = ReplyData.getRootComment()

build() {
Stack({ alignContent: Alignment.Bottom }) {
Column() {
Scroll() {
Column() {
// 顶部组件
HmNavBar()
// 顶部评论
CommentItem({
author: this.rootComment,
clickLike: () => {
this.rootComment.likeFlag = !this.rootComment.likeFlag
if (this.rootComment.likeFlag) {
this.rootComment.likeNum++
} else {
this.rootComment.likeNum--
}
}
})
// 分割线
Divider()
.strokeWidth(6)
.color("#f4f5f6")
// 回复数
ReplyCount({ ReplyNum: this.commentList.length })

// 回复评论列表
ForEach(this.commentList, (item: ReplyItem, index: number) => {
CommentItem({
author: item,
clickLike: () => {
item.likeFlag = !item.likeFlag
if (item.likeFlag) {
item.likeNum++
const res: ReplyItem = {
id: item.id,
avatar: item.avatar,
author: item.author,
content: item.content,
time: item.time,
area: item.area,
likeNum: item.likeNum,
likeFlag: item.likeFlag,
}
this.commentList.splice(index, 1, res)

} else {
item.likeNum--
const res: ReplyItem = {
id: item.id,
avatar: item.avatar,
author: item.author,
content: item.content,
time: item.time,
area: item.area,
likeNum: item.likeNum,
likeFlag: item.likeFlag,
}
this.commentList.splice(index, 1, res)
}
// console.log(item.likeNum.toString())
}
})
})
}
.width('100%')
.backgroundColor(Color.White)
}
.padding({
bottom: 60
})
.edgeEffect(EdgeEffect.Spring)
.scrollBar(BarState.Off)
}
.height('100%')

ReplyInput()
}
.height('100%')
}
}

// 顶部评论回复
@Component
struct HmNavBar {
build() {
Row() {
Row() {
Image($r('app.media.ic_public_arrow_left'))
.width(20)
.height(20)
.syncLoad(true) // 为了不阻塞 图片一般是分开加载的
}
.borderRadius(20)
.backgroundColor('#f6f6f6')
.justifyContent(FlexAlign.Center)
.width(30)
.aspectRatio(1)
.margin({
left: 15
})

Text("评论回复")
.layoutWeight(1)
.textAlign(TextAlign.Center)
.padding({
right: 35
})
}
.width('100%')
.height(50)
.border({
width: {
bottom: 1
},
color: '#f6f6f6',
})
}
}


// 回复数量
@Component
struct ReplyCount {
@Prop ReplyNum: number

build() {
Text() {
Span('回复')
Span(`${this.ReplyNum}`)
}
.padding(15)
.fontWeight(700)
.alignSelf(ItemAlign.Start)
}
}

// 底部回复组件
@Component
struct ReplyInput {
build() {
Row() {
TextInput({ placeholder: '回复' })
.layoutWeight(1)
.backgroundColor("#f4f5f6")
.height(40)
Text('发布')
.fontColor("#6ecff0")
.fontSize(14)
.margin({
left: 10
})

}
.padding(10)
.backgroundColor(Color.White)
.border({
width: { top: 1 },
color: "#f4f5f6"
})
}
}

知乎问题:

在使用splice方法后会出现点赞后头像图片闪烁情况,会影响用户体验感

原理:将原来图片加载,提到主线程上面

专门针对嵌套对象的Link =>典型场景(【{},{}】)数组包对象

之前用splice修改嵌套对象的写法,会让页面刷新,降低用户体验。为了解决这个问题,可以通过 @Observed 与 @ObjectLink 这两个装饰器解决

基本用法

@Provide/@Consume

将数据传递给后代,和后代的数据进行双向同步

如果使用Link需要在组件内传递参数(子孙嵌套多的话会很麻烦)

@Provide@Consume可以解决这个痛点

如图所示 @Provide@Consume可以实现父子孙组件之间的数据同步,且不会像Link传递参数那样麻烦


文章作者: 太阳神小赖
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 太阳神小赖 !
  目录