# 14.2:@Local
@Local 装饰器是最基础的状态装饰器,它修饰的变量称为 状态变量,一旦 状态变量 的值发生了变化,那么用到该状态变量的组件会重新渲染从而实现 UI 刷新的功能。
# 14.2.1:约束与限制
@Local 装饰器修饰的变量必须 指定类型 和 初始化
@Local
装饰器修饰的变量必须指定类型和初始化,否则编译报错:Property 'message' has no initializer and is not definitely assigned in the constructor.
# 14.2.2:语法介绍
@Local 的使用很简单,直接在组件内的属性前添加 @Local 装饰器即可,格式为:【@Local attributeName: attributeType = attributeValue】,样例如下:
@Entry @ComponentV2 struct Index {
@Local userName: string = 'Hello World'; // 在组件属性前添加@Local
@Local
bookName : string = "《ArkUI实战》" // 在组件属性上添加@Local
build() {}
}
2
3
4
5
6
7
8
9
# 14.2.3:简单使用
@Local 装饰器的使用很简单,直接在组件内的变量前添加 @Local
即可。简单样例如下所示:
@Entry @ComponentV2 struct Page_02_state {
message1: string = 'Hello World' // 变量 message1 没有@Local装饰器
@Local
message2: string = 'Hello World' // 变量 message2 添加@Local装饰器
// @Local message3: string; // 编译报错,必须对message3赋值
build() {
Column({space: 10}) {
Button(this.message1)
.fontSize(30)
.id("button1")
.onClick(() => {
this.message1 = "Hello, OpenHarmony";
})
Button(this.message2)
.fontSize(30)
.id("button2")
.onClick(() => {
this.message2 = "Hello, 《ArkUI实战》";
})
}
.padding(10)
.width('100%')
.height("100%")
}
}
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
简单样例运行结果如下所示:

上述样例中,属性 message1 和 message2 都赋值了默认值,只是 message2 添加了 @Local 装饰器。分别点击 button1
和 button2
表现如下:
点击button1:
把 message1 被赋予了
Hello, OpenHarmony
,此时页面无反应;点击button2:
把 message2 被赋予了
Hello, 《ArkUI实战》
,此时页面显示新值。
结果按钮2的文字则显示了新值,由此可见是 @Local 装饰器导致了按钮2发生了重绘。
📢:@Local 装饰器修饰的变量必须 指定类型 和 初始化,否则编译报错:Property 'message' has no initializer and is not definitely assigned in the constructor.
# 14.2.4:作用域
@Local 装饰器装饰的变量是私有的,只能在当前组件范围内访问,简单样例如下所示:
@Entry @ComponentV2 struct Page_02_state {
message1: string = 'Hello World'
@Local
message2: string = 'Hello World'
build() {
Column({space: 10}) {
Button(this.message1)
.fontSize(30)
.onClick(() => {
this.message1 = "Hello, 《ArkUI实战》";
})
Button(this.message2)
.fontSize(30)
.onClick(() => {
this.message2 = "Hello, 《ArkUI实战》";
})
CustomButton()
}
.padding(10)
.width('100%')
.height("100%")
}
}
@Component struct CustomButton {
@Local
message2: string = 'Hello CustomWidget'
build() {
Button(this.message2)
.fontSize(30)
.onClick(() => {
this.message2 = "《ArkUI实战》, Hello";
})
}
}
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
样例运行结果如下图所示:

由运行结果可知,父子组件虽然都定义了状态变量,但是 CustomButton
内部的 message2 的值发生了更改但不会引发外部 Page_02_state
组件的状态变化。
# 14.2.5:支持的数据类型
@Local 装饰器目前支持的数据类型主要如下:
简单数据类型
简单数据类型目前支持的类型有: number, boolean, string, enum。简单样例如下所示:
enum ColorType { R, G, B } @Entry @ComponentV2 struct Page_02_state { @Local message1: string = 'Hello World' // 定义 string 类型 @Local message2: number = 10086 // 定义 number 类型 @Local message3: boolean = false // 定义 boolean 类型 @Local message4: ColorType = ColorType.R // 定义 enum 类型 build() { Column({space: 10}) { Button(this.message1) .fontSize(30) .onClick(() => { this.message1 = "Hello, 《ArkUI实战》"; }) Button(this.message2.toString()) .fontSize(30) .onClick(() => { this.message2 = 10010 }) Button(this.message3.toString()) .fontSize(30) .onClick(() => { this.message3 = true }) Button(this.message4.toString()) .fontSize(30) .onClick(() => { this.message4 = ColorType.B }) } .padding(10) .width('100%') .height("100%") } }
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样例运行结果如下图所示:
简单数组类型
简单数据类型 目前支持的有: number, boolean, string, enum,笔者把由它们组成的 数组 简称为简单数组,目前简单数组支持的操作为:数组重新赋值,数组单项赋值,数组数据添加 和 数组数据删除,以上支持的操作会引起相关组件的重绘。简单样例如下所示:
@Entry @ComponentV2 struct Page_02_state { @Local message2: number[] = [] build() { Column({space: 10}) { Text("size: " + this.message2.length + ", total: " + this.total()) .fontSize(20) Button("添加操作") .onClick(() => { this.message2.push(Math.round(Math.random() * 100)) // 数组添加数据操作 }) Button("删除操作") .onClick(() => { this.message2.pop() // 数组删除数据操作 }) Button("重新赋值") .onClick(() => { this.message2 = [100, 200, 300] // 数组重新初始化 }) Button("单项赋值") .onClick(() => { this.message2[0] = 500 // 数组单项数据更新 }) } .padding({top: 40, left: 10, right: 10, bottom: 10}) .width('100%') .height("100%") } // 计算数组总和 private total(): number { let total = 0 this.message2.forEach((value: number) => { total += value }) return total } }
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样例运行结果如下图所示:
class、Object 类型
当装饰的数据类型为 class 或 Object 时,支持的操作为:重新赋值 操作,简单样例如下所示:
class Headmaster { public name: string; constructor(name: string) { this.name = name; } } class Student { public name: string; constructor(name: string) { this.name = name; } } class Teacher { public headmaster: Headmaster; public students: Student[]; public name: string; public age: number; constructor(headmaster: Headmaster, student: Student[], name: string, age: number) { this.headmaster = headmaster; this.students = student; this.name = name; this.age = age; } } @Entry @ComponentV2 struct Page_02_state { headmaster: Headmaster = new Headmaster("刘校长"); student: Student = new Student("张三"); @Local teacher: Teacher = new Teacher(this.headmaster, [this.student], "张老师", 26); build() { Column({space: 10}) { Text("老师姓名: " + this.teacher.name + "\n老师年龄:" + this.teacher.age + "\n老师领导:" + this.teacher.headmaster.name + "\n教有学生:" + this.teacher.students.length + "\n学生名字:" + this.studentNames()) .fontSize(20) Button("重新赋值") .onClick(() => { this.teacher = new Teacher(new Headmaster("王校长"), [this.student], "王老师", 30); }) Button("属性赋值") .onClick(() => { this.teacher.students = [new Student("李四"), new Student("王五")]; this.teacher.age = 40; this.teacher.name = "新来的刘老师" this.teacher.headmaster = new Headmaster("新来的吕校长") }) Button("嵌套赋值") .onClick(() => { this.teacher.headmaster.name = "新来的刘校长" this.teacher.students.push(new Student("新来的王同学")) this.teacher.students[0].name = "新来的刘同学"; this.teacher.students.pop() }) } .padding(10) .width('100%') .height("100%") } private studentNames(): string { let names = ""; this.teacher.students.forEach((student) => { names = names.concat(student.name).concat(","); }); return names; } }
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样例运行结果如下图所示:
由样例运行结果可知,@Local 装饰器修饰的 class 或者 object,支持自身的 重新赋值 操作。
# 14.2.6:初始化顺序
@Local 装饰器装饰的状态数据初始化顺序为 本地初始化
,就是在定义状态数据的时候直接赋予初始值,样例代码如下:
@Entry @ComponentV2 struct Page_02_state {
@Local count: number = Math.random(); // 定义count时直接赋予初始值
build() {
Column({space: 10}) {
Text("count: " + this.count)
.fontSize(22)
.onClick(() => {
this.count = Math.random();
})
}
.padding(10)
.width("100%")
.height("100%")
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
样例运行结果如下图所示:

# 14.2.7:完整样例
笔者结合 List 组件实现一个 添加
,删除
,重置
和 局部更新
的小样例,代码如下所示:
class Student {
public name: string;
public age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
@Entry @ComponentV2 struct Page_02_state {
@Local students: Array<Student> = [];
build() {
Column({space: 10}) {
List({
space: 10
}) {
ForEach(this.students, (item: Student, index: number) => {
ListItem() {
Row() {
Text(index.toString())
.width(50)
.textAlign(TextAlign.Center)
Column() {
Text(item.name + index)
.fontSize(18)
Text("age: " + item.age)
.fontSize(12)
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
.height("100%")
}
.borderRadius(10)
.backgroundColor("#aabbcc")
.width("100%")
.height(45)
}
.width("100%")
.height(45)
})
}
.width("100%")
.layoutWeight(1)
Row({space: 5}) {
Button("添加")
.onClick(() => {
this.students.push(new Student("张三", Math.round(Math.random() * 100 + 1)));
})
Button("删除")
.onClick(() => {
this.students.pop();
})
Button("重置")
.onClick(() => {
this.students = [];
})
Button("更新 1")
.onClick(() => {
this.students[this.students.length - 1] = new Student("新来的张三", 20);
})
Button("更新 2")
.onClick(() => {
this.students[this.students.length - 1].age = 110;
this.students[this.students.length - 1].name = "新来的学生"
})
}
.width("100%")
}
.padding(10)
.width('100%')
.height("100%")
}
}
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
样例运行结果如下图所示:

← 14.1:前言 14.3:@Param →
