先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新HarmonyOS鸿蒙全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注鸿蒙)
正文
class ClassA {
public value: string;
constructor(value: string) {
this.value = value;
}
}
class Model {
public value: string;
public name: ClassA;
constructor(value: string, a: ClassA) {
this.value = value;
this.name = a;
}
}
@State装饰的类型是Model
// class类型
@State title: Model = new Model(‘Hello’, new ClassA(‘World’));
对@State装饰变量的赋值。
// class类型赋值
this.title = new Model(‘Hi’, new ClassA(‘ArkUI’));
对@State装饰变量的属性赋值。
// class属性的赋值
this.title.value = ‘Hi’;
嵌套属性的赋值观察不到。
// 嵌套的属性赋值观察不到
this.title.name.value = ‘ArkUI’;
- 当装饰的对象是array时,可以观察到数组本身的赋值和添加、删除、更新数组的变化。例子如下。
声明Model类。
class Model {
public value: number;
constructor(value: number) {
this.value = value;
}
}
@State装饰的对象为Model类型数组时。
// 数组类型
@State title: Model[] = [new Model(11), new Model(1)];
数组自身的赋值可以观察到。
// 数组赋值
this.title = [new Model(2)];
数组项的赋值可以观察到。
// 数组项赋值
this.title[0] = new Model(2);
删除数组项可以观察到。
// 数组项更改
this.title.pop();
新增数组项可以观察到。
// 数组项更改
this.title.push(new Model(12));
数组项中属性的赋值观察不到。
// 嵌套的属性赋值观察不到
this.title[0].value = 6;
- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口
setFullYear
,setMonth
,setDate
,setHours
,setMinutes
,setSeconds
,setMilliseconds
,setTime
,setUTCFullYear
,setUTCMonth
,setUTCDate
,setUTCHours
,setUTCMinutes
,setUTCSeconds
,setUTCMilliseconds
更新Date的属性。
@Entry
@Component
struct DatePickerExample {
@State selectedDate: Date = new Date(‘2021-08-08’)
build() {
Column() {
Button(‘set selectedDate to 2023-07-08’)
.margin(10)
.onClick(() => {
this.selectedDate = new Date(‘2023-07-08’)
})
Button(‘increase the year by 1’)
.margin(10)
.onClick(() => {
this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1)
})
Button(‘increase the month by 1’)
.margin(10)
.onClick(() => {
this.selectedDate.setMonth(this.selectedDate.getMonth() + 1)
})
Button(‘increase the day by 1’)
.margin(10)
.onClick(() => {
this.selectedDate.setDate(this.selectedDate.getDate() + 1)
})
DatePicker({
start: new Date(‘1970-1-1’),
end: new Date(‘2100-1-1’),
selected: this.selectedDate
})
}.width(‘100%’)
}
}
- 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口
set
,clear
,delete
更新Map的值。 - 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口
add
,clear
,delete
更新Set的值。
框架行为
- 当状态变量被改变时,查询依赖该状态变量的组件;
- 执行依赖该状态变量的组件的更新方法,组件更新渲染;
- 和该状态变量不相关的组件或者UI描述不会发生重新渲染,从而实现页面渲染的按需更新。
使用场景
装饰简单类型的变量
以下示例为@State装饰的简单类型,count被@State装饰成为状态变量,count的改变引起Button组件的刷新:
- 当状态变量count改变时,查询到只有Button组件关联了它;
- 执行Button组件的更新方法,实现按需刷新。
@Entry
@Component
struct MyComponent {
@State count: number = 0;
build() {
Button(click times: ${this.count}
)
.onClick(() => {
this.count += 1;
})
}
}
装饰class对象类型的变量
- 自定义组件MyComponent定义了被@State装饰的状态变量count和title,其中title的类型为自定义类Model。如果count或title的值发生变化,则查询MyComponent中使用该状态变量的UI组件,并进行重新渲染。
- EntryComponent中有多个MyComponent组件实例,第一个MyComponent内部状态的更改不会影响第二个MyComponent。
class Model {
public value: string;
constructor(value: string) {
this.value = value;
}
}
@Entry
@Component
struct EntryComponent {
build() {
Column() {
// 此处指定的参数都将在初始渲染时覆盖本地定义的默认值,并不是所有的参数都需要从父组件初始化
MyComponent({ count: 1, increaseBy: 2 })
.width(300)
MyComponent({ title: new Model(‘Hello World 2’), count: 7 })
}
}
}
@Component
struct MyComponent {
@State title: Model = new Model(‘Hello World’);
@State count: number = 0;
private increaseBy: number = 1;
build() {
Column() {
Text(${this.title.value}
)
.margin(10)
Button(Click to change title
)
.onClick(() => {
// @State变量的更新将触发上面的Text组件内容更新
this.title.value = this.title.value === ‘Hello ArkUI’ ? ‘Hello World’ : ‘Hello ArkUI’;
})
.width(300)
.margin(10)
Button(Click to increase count = ${this.count}
)
.onClick(() => {
// @State变量的更新将触发该Button组件的内容更新
this.count += this.increaseBy;
})
.width(300)
.margin(10)
}
}
}
从该示例中,我们可以了解到@State变量首次渲染的初始化流程:
- 使用默认的本地初始化:
@State title: Model = new Model(‘Hello World’);
@State count: number = 0;
- 对于@State来说,命名参数机制传递的值并不是必选的,如果没有命名参数传值,则使用本地初始化的默认值:
class C1 {
public count:number;
public increaseBy:number;
constructor(count: number, increaseBy:number) {
this.count = count;
this.increaseBy = increaseBy;
}
}
let obj = new C1(1, 2)
MyComponent(obj)
装饰Map类型变量
说明:
从API version 11开始,@State支持Map类型。
在下面的示例中,message类型为Map<number, string>,点击Button改变message的值,视图会随之刷新。
@Entry
@Component
struct MapSample {
@State message: Map<number, string> = new Map([[0, “a”], [1, “b”], [3, “c”]])
build() {
Row() {
Column() {
ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
Text(${item[0]}
).fontSize(30)
Text(${item[1]}
).fontSize(30)
Divider()
})
Button(‘init map’).onClick(() => {
this.message = new Map([[0, “a”], [1, “b”], [3, “c”]])
})
Button(‘set new one’).onClick(() => {
this.message.set(4, “d”)
})
Button(‘clear’).onClick(() => {
this.message.clear()
})
Button(‘replace the first one’).onClick(() => {
this.message.set(0, “aa”)
})
Button(‘delete the first one’).onClick(() => {
this.message.delete(0)
})
}
.width(‘100%’)
}
.height(‘100%’)
}
}
装饰Set类型变量
说明:
从API version 11开始,@State支持Set类型。
在下面的示例中,message类型为Set,点击Button改变message的值,视图会随之刷新。
@Entry
@Component
struct SetSample {
@State message: Set = new Set([0, 1, 2, 3, 4])
build() {
Row() {
Column() {
ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
Text(${item[0]}
).fontSize(30)
Divider()
})
Button(‘init set’).onClick(() => {
this.message = new Set([0, 1, 2, 3, 4])
})
Button(‘set new one’).onClick(() => {
this.message.add(5)
})
Button(‘clear’).onClick(() => {
this.message.clear()
})
Button(‘delete the first one’).onClick(() => {
this.message.delete(0)
})
}
.width(‘100%’)
}
.height(‘100%’)
}
}
State支持联合类型实例
@State支持联合类型和undefined和null,在下面的示例中,count类型为number | undefined,点击Button改变count的属性或者类型,视图会随之刷新。
@Entry
@Component
struct EntryComponent {
build() {
Column() {
MyComponent()
}
}
}
@Component
struct MyComponent {
@State count: number | undefined = 0;
build() {
Column() {
Text(count(${this.count})
)
Button(‘change’)
.onClick(() => {
this.count = undefined;
})
}
}
}
常见问题
使用箭头函数改变状态变量未生效
箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。所以在该场景下, changeCoverUrl的this指向PlayDetailViewModel,而不是被装饰器@State代理的状态变量。
反例:
export default class PlayDetailViewModel {
coverUrl: string = ‘#00ff00’
changeCoverUrl= ()=> {
this.coverUrl = ‘#00F5FF’
}
}
import PlayDetailViewModel from ‘./PlayDetailViewModel’
@Entry
@Component
struct PlayDetailPage {
@State vm: PlayDetailViewModel = new PlayDetailViewModel()
build() {
Stack() {
Text(this.vm.coverUrl).width(100).height(100).backgroundColor(this.vm.coverUrl)
Row() {
Button(‘点击改变颜色’)
.onClick(() => {
this.vm.changeCoverUrl()
})
}
}
.width(‘100%’)
.height(‘100%’)
.alignContent(Alignment.Top)
}
}
所以要将当前this.vm传入,调用代理状态变量的属性赋值。
正例:
export default class PlayDetailViewModel {
coverUrl: string = ‘#00ff00’
changeCoverUrl= (model:PlayDetailViewModel)=> {
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
Url()
})
}
}
.width(‘100%’)
.height(‘100%’)
.alignContent(Alignment.Top)
}
}
所以要将当前this.vm传入,调用代理状态变量的属性赋值。
正例:
export default class PlayDetailViewModel {
coverUrl: string = ‘#00ff00’
changeCoverUrl= (model:PlayDetailViewModel)=> {
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
[外链图片转存中…(img-QQG2Jsft-1713133931046)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!