鸿蒙的状态管理
任何语言都有本身的声明数据的方式,好比C语言中 int a=1;JavaScript中let arr=这篇文章主要探讨鸿蒙中的数据声明以及数据通报。
鸿蒙的底子知识可以参考:Harmony OS NEXT初学笔记-CSDN博客
一.@state与private
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
private str="你好"
build() {
Column() {
Text(`message:${this.message}`)
Text(`str:${this.str}`)
Button("按钮")
.onClick(()=>{
this.message="你好世界"
this.str="hello "
console.log(`点击按钮后,message:${this.message},str:${this.str}`)
})
}
.height('100%')
.width('100%')
}
} 在这部分代码中用@State和private声明了两个变量,下面看效果
https://i-blog.csdnimg.cn/direct/397d76161d4247e1b8f2c3c906797cda.png
在页面上表现出来了,再看按钮,绑定了点击事件,点击按钮改变两个声明的变量,下面我们点击按钮,看看效果
https://i-blog.csdnimg.cn/direct/d910b0b025b34189aa84b30e495c6f21.png
https://i-blog.csdnimg.cn/direct/0e27164532534ec7a46ccac6889846b9.png
发现两个变量的值都改变了,但是在页面上只改变了用@state声明的值
那么我们可以得出结论:用@state声明的状态变量改变后,页面会随之改变,但是用private声明的变量,大概不用private声明直接写变量的比方 num=1,这种改变不会使页面革新但是这种变量的值也确实会改变
那么我们用private声明的值盘算,把值赋给@State声明的呢?
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
private str="你好"
@State sum:number=0
private num1:number=0
private num2:string="0"
build() {
Column() {
Text(`message:${this.message}`)
Text(`str:${this.str}`)
Button("按钮")
.onClick(()=>{
this.message="你好世界"
this.str="hello "
console.log(`点击按钮后,message:${this.message},str:${this.str}`)
})
TextInput({placeholder:"请输入num1"}).onChange((value)=>{
this.num1=Number(value)
console.log(`nmum1:${this.num1.toString()}`)
})
TextInput({placeholder:"请输入num2",text:$$this.num2})
Text(`num1+num2= ${this.num1+Number(this.num2)}`)
Text(`sum= ${this.sum}`)
Button("按钮").onClick(()=>{
this.sum=this.num1+Number(this.num2)
console.log(`num1+num2= ${this.num1+Number(this.num2)}`)
})
}
.height('100%')
.width('100%')
}
} 这里我们声明两个变量举行输入,注意到num1是用的textinput的onchange函数来赋值,而num2则是用$$举行双向绑定,在这里$$相称于onchange的简写
那么我们看看效果
https://i-blog.csdnimg.cn/direct/8666e2aca7014f6bb5d79f0a906f6bae.png
发现,两个private数据相加也不会改变,但是点击按钮后会触发@State声明的变量改变来触发页面革新
https://i-blog.csdnimg.cn/direct/dc351ad0e30f41779ab2f245d23548ee.png
https://i-blog.csdnimg.cn/direct/72674401308a49028178873307164d03.png
同样有输出效果
那么我们想一想,现在是每次点击按钮页面才会革新,那么有没有一种方法不用点击按钮自动革新呢?
那就是我们下面介绍的
二.@Watch
由于@Watch必须与装饰器绑定,因此@Watch不能装饰private
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
private str="你好"
@State sum:number=0
private num1:number=0
@State @Watch("change") num2:string="0"
change(){
this.sum=this.num1+Number(this.num2)
}
build() {
Column() {
Text(`message:${this.message}`)
Text(`str:${this.str}`)
Button("按钮")
.onClick(()=>{
this.message="你好世界"
this.str="hello "
console.log(`点击按钮后,message:${this.message},str:${this.str}`)
})
TextInput({placeholder:"请输入num1"}).onChange((value)=>{
this.num1=Number(value)
console.log(`nmum1:${this.num1.toString()}`)
})
TextInput({placeholder:"请输入num2",text:$$this.num2})
Text(`num1+num2= ${this.num1+Number(this.num2)}`)
Text(`sum= ${this.sum}`)
Button("按钮").onClick(()=>{
this.sum=this.num1+Number(this.num2)
console.log(`num1+num2= ${this.num1+Number(this.num2)}`)
})
}
.height('100%')
.width('100%')
}
} 注意看,我们在@Watch后面加了一个change函数,也是必须加的,名字无所谓,每次改变num2的值会实行change函数,那么,现在我们每次改变输入num2的值就会重新盘算sum,也就不需要点击按钮了。效果如下。
https://i-blog.csdnimg.cn/direct/b7680ac109314034a305a4f686fbb648.png
除此之外,还意外发现了num1+num2也变化了,那也就是:private声明的与@State声明的值举行操作会改变页面,触发页面革新??
三.父子通报
页面之间的跳转携带参数我们知道是在router的params内里,那么现在,假如两个Component要通报通报参数呢?
下面先介绍一种通用的方法,也就是get set,本质上是通过一个中心人,这种方法实用于绝大部分的数据通报
起首新建一个类:
export class MyStore{
static str:string
static setStr(str:string){
MyStore.str=str
}
static getStr(){
return MyStore.str
}
} 再来看set:
import { MyStore } from '../store/myStore';
import { router } from '@kit.ArkUI';
@Entry
@Component
struct GetAndSet {
@State message: string = 'Hello World';
build() {
Column() {
Button("Set").onClick(()=>{
MyStore.setStr(this.message)
})
Button("Router").onClick(()=>{
router.pushUrl({
url:"pages/Get"
})
})
Button("ReSet").onClick(()=>{
MyStore.setStr("123")
})
}
.height('100%')
.width('100%')
}
} 在这里,我们利用set,把message的值赋给了对象中的str
再来看get
import { MyStore } from '../store/myStore';
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct Get {
@State message: string = 'Hello World';
build() {
Column() {
Button("Get").onClick(()=>{
promptAction.showToast({
message:`${MyStore.getStr()}`
})
setTimeout(()=>{
AlertDialog.show({
message:`${MyStore.getStr()}`
})
},2000)
})
}
.height('100%')
.width('100%')
}
} 在这边我们取出了str的值。
这种get/set的模式和鸿蒙的长期化存储中的首选项雷同
那么有没有简单一点的?固然有!!!
@Prop父子单向通报
不多说,先上代码
@Entry
@Component
struct PropAndLink {
@State message: string = 'Hello World';
@State num:number=1
build() {
Column() {
Column() {
Text("我是主页面")
Text(`num= ${this.num}`)
Button("主页面的按钮").onClick(()=>{
this.num++
})
}.height('50%')
.width('100%')
Column(){
child({num:this.num})
}.height('50%')
.width('100%')
}.height('100%')
.width('100%')
}
}
@Component
export struct child {
@Prop num:number
build() {
Column() {
Text("我是子页面")
Text(`num= ${this.num}`)
Button("子页面的按钮").onClick(()=>{
this.num++
})
}
}
} 在这个页面有两个component,在主页面上表现效果如下:
https://i-blog.csdnimg.cn/direct/f1d1883f35574b1d8a043cabce1f2172.png
在两个component中,都分别有一个按钮,都是给对应的component中的num+1,
现在我们点击下面的按钮两下:
https://i-blog.csdnimg.cn/direct/01fd4f3be6fc4048a0f8dcd0380f71db.png
发现,只有下面的变化了,上面的不会变化,
那么我们在点击上面的按钮一下:
https://i-blog.csdnimg.cn/direct/2b74f1c2140546f697e113370b02b544.png
发现上下都酿成2了,下面酿成2是由于上面的酿成2之后,把2传给了下面,因此下面才表现2
由此我们得出结论:@Prop修饰的变量只能父组件改变子组件,在子组件改变不影响父组件的改变。
注意:@Prop的传值方式,调用组件的时候传值,以对象的情势:像这里的
child({num:this.num})
@Link 父子双向通报
一样,先上代码:
@Entry
@Component
struct PropAndLink {
@State message: string = 'Hello World';
@State num: number = 1
@State num2: number = 100
build() {
Column() {
Column() {
Text("我是主页面")
Text(`num= ${this.num}`)
Button("主页面的按钮1").onClick(() => {
this.num++
})
Text(`num2= ${this.num2}`)
Button("主页面的按钮12").onClick(() => {
this.num2++
})
}.height('50%')
.width('100%')
Column() {
child({ num: this.num, num2: this.num2 })
}.height('50%')
.width('100%')
}.height('100%')
.width('100%')
}
}
@Component
export struct child {
@Prop num: number
@Link num2: number
build() {
Column() {
Text("我是子页面")
Text(`num= ${this.num}`)
Button("子页面的按钮").onClick(() => {
this.num++
})
Text(`num2= ${this.num2}`)
Button("子页面的按钮12").onClick(() => {
this.num2++
})
}
}
} 检察效果:
https://i-blog.csdnimg.cn/direct/ba1e605047324eb282d3f9b1bb7f8575.png
我们先点击下面的按钮:
https://i-blog.csdnimg.cn/direct/e70b3bb309594946abc479c62f32eee0.png
发现父组件,子组件都发生改变,
我们再点击父组件的按钮
https://i-blog.csdnimg.cn/direct/08188f7118c84162aba0f6190489ff98.png
发现也是,父组件改变,子组件也改变
因此我们得出结论:@Link修饰的变量可以在父组件改变子组件的值,也可以在子组件改变父组件的值,也就是父子双向通报
那么我们思索,有父子,有没有爷孙呢?但是本质上来说刚刚已经讲过了,也就是get/set方法,不过,我们介绍更简单方便的。
@Provide装饰器和@Consume装饰器:与后代组件双向同步
实在可不可以不用这两个,固然可以,我们给出以下例子
@Entry
@Component
struct GrandFather {
@State message: string = 'Hello World';
build() {
Column() {
Column() {
Text("GrandFather")
}.layoutWeight(1)
Father().layoutWeight(1)
}
.height('100%')
.width('100%')
}
}
@Component
export struct Father {
build() {
Column() {
Column() {
Text("Father")
}.layoutWeight(1)
Son().layoutWeight(1)
}.width("100%")
.height("100%")
}
}
@Component
export struct Son {
build() {
Column() {
Text("Son")
}
}
}
这是一个最根本的爷孙类型的组件,来看页面效果:
https://i-blog.csdnimg.cn/direct/fd93b359e18d41c7ac3b6840a36f9d65.png
下面我们在内里声明数据:
@Entry
@Component
struct GrandFather {
@State message: string = 'Hello World';
@State num: number = 1
build() {
Column() {
Column() {
Text("GrandFather")
Text(`num= ${this.num}`)
Button("按钮").onClick(() => {
this.num++
})
}.layoutWeight(1)
Father({ num: this.num }).layoutWeight(1)
}
.height('100%')
.width('100%')
}
}
@Component
export struct Father {
@Link num: number
build() {
Column() {
Column() {
Text("Father")
Text(`num= ${this.num}`)
}.layoutWeight(1)
Son({ num: this.num }).layoutWeight(1)
}.width("100%")
.height("100%")
}
}
@Component
export struct Son {
@Link num: number
build() {
Column() {
Text("Son")
Text(`num= ${this.num}`)
Button("按钮").onClick(() => {
this.num++
})
}
}
}
我们利用father这个组件做一个桥梁,吧爷爷Grandfather和孙子Son连接起来了
效果如下:
https://i-blog.csdnimg.cn/direct/2850f2cce8ea4038954e95e3e27a1c02.png
这就是初始情况,
我们点击一下爷爷的按钮:
https://i-blog.csdnimg.cn/direct/4ac7b8fc59a84c43b68a2a9d41467003.png
发现孙子的也在变化,那么我们点击孙子的按钮:
https://i-blog.csdnimg.cn/direct/64f554ad25e5417eb523b80cfab4368a.png
发现爷爷也变化了,实在也正常,毕竟@link是双向通报嘛
那么有没有简单易达的办法,固然有咯,那就是@Provide和@Consume
先看代码:
@Entry
@Component
struct GrandFather {
@State message: string = 'Hello World';
@State num: number = 1
@Provide num2: number = 100
build() {
Column() {
Column() {
Text("GrandFather")
Text(`num= ${this.num}`)
Button("按钮").onClick(() => {
this.num++
})
Text(`num2= ${this.num2}`)
Button("按钮").onClick(() => {
this.num2++
})
}.layoutWeight(1)
Father({ num: this.num }).layoutWeight(1)
}
.height('100%')
.width('100%')
}
}
@Component
export struct Father {
@Link num: number
build() {
Column() {
Column() {
Text("Father")
Text(`num= ${this.num}`)
}.layoutWeight(1)
Son({ num: this.num }).layoutWeight(1)
}.width("100%")
.height("100%")
}
}
@Component
export struct Son {
@Link num: number
@Consume num2: number
build() {
Column() {
Text("Son")
Text(`num= ${this.num}`)
Button("按钮").onClick(() => {
this.num++
})
Text(`num2= ${this.num2}`)
Button("按钮").onClick(() => {
this.num2++
})
}
}
}
实在也就是在GrandFather和Son对应的加了@provide和@consume,由爷爷提供(provide)由孙子吸收(consume)
下面给出初始状态,点击爷爷的按钮,点击孙子的按钮三种操作
https://i-blog.csdnimg.cn/direct/be56ac2a412d4b45ade7b28b96797037.png
https://i-blog.csdnimg.cn/direct/3be2b35ed1eb48d99aed1a4bbd069bc4.png
https://i-blog.csdnimg.cn/direct/e61c67d2781f4ca09bb2f7b7d45425d5.png
发现和@link一样是双向绑定的
那么这个时候有同砚就要问了,老师老师,你给的数据类型都太简单了,有没有复杂一点的,好比对象,看看这些能不能做到双向通报。
好,那就满足这位同砚的好奇心
export interface Person {
name: string,
age: number
}
@Entry
@Component
struct GrandFather {
@State message: string = 'Hello World';
@State num: number = 1
@Provide num2: number = 100
@Provide person: Person = { name: "张三", age: 20 }
build() {
Column() {
Column() {
Text("GrandFather")
Text(`num= ${this.num}`)
Button("按钮").onClick(() => {
this.num++
})
Text(`num2= ${this.num2}`)
Button("按钮").onClick(() => {
this.num2++
})
Text(`我叫${this.person.name},年龄是${this.person.age}`)
Button("按钮").onClick(() => {
this.person.name = "李四"
//this.person={name:"李四",age:30}
})
}.layoutWeight(1)
Father({ num: this.num }).layoutWeight(1)
}
.height('100%')
.width('100%')
}
}
@Component
export struct Father {
@Link num: number
build() {
Column() {
Column() {
Text("Father")
Text(`num= ${this.num}`)
}.layoutWeight(1)
Son({ num: this.num }).layoutWeight(1)
}.width("100%")
.height("100%")
}
}
@Component
export struct Son {
@Link num: number
@Consume num2: number
@Consume person: Person
build() {
Column() {
Text("Son")
Text(`num= ${this.num}`)
Button("按钮").onClick(() => {
this.num++
})
Text(`num2= ${this.num2}`)
Button("按钮").onClick(() => {
this.num2++
})
Text(`我叫${this.person.name},年龄是${this.person.age}`)
Button("按钮").onClick(() => {
this.person = { name: "王五", age: 40 }
})
}
}
}
这边声明一个Person类,在爷爷组件中赋初值,然后按钮改变,通报给孙子组件,在孙子组件中也可以改变,让我们同样看看三种效果:
https://i-blog.csdnimg.cn/direct/b5c25f70a15d4528a440fb9c6b829bbb.png
https://i-blog.csdnimg.cn/direct/3140ede6a7f940c79954791e5e953fb8.png
https://i-blog.csdnimg.cn/direct/5287c8f3c56b49f796f6d34c35861f75.png
我们看到,这种对象也能被捕捉,同样可以或许举行双向通报
那么复杂的数据类型呢,对象内里的某一个属性是另一个对象?
那么就是:
@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化
先看代码:
class Person {
public username: string
public userage: number
constructor(username: string, userage: number) {
this.username = username;
this.userage = userage;
}
}
@Entry
@Component
struct ObjectLinkLayout {
@State message: string = 'Hello World'
@State P: Person = new Person("张三", 18);
build() {
Column() {
Row() {
Text(`多层级数据${this.P.userage}`)
}
MyChild5({ P: $P })
}.width("100%")
.height("100%")
}
}
@Component
export default struct MyChild5 {
@Link P: Person;
build() {
Row() {
Text(`父组件的数据为${this.P.userage}`)
Button("修改父组件数据").onClick(() => {
this.P.userage++;
})
}
}
} 这是一个最简单的父子的通报对象的,那么我们变复杂一点
@Observed
class Info {
public info: number = 0;
constructor(info: number) {
this.info = info;
}
}
@Component
struct ObjectLinkChild {
@ObjectLink testNum: Info;
build() {
Text(`ObjectLinkChild testNum ${this.testNum.info}`)
.onClick(() => {
// 可以对ObjectLink装饰对象的属性赋值
this.testNum.info = 47;
})
}
}
@Entry
@Component
struct Parent {
@State testNum: Info[] = ;
build() {
Column() {
Text(`Parent testNum ${this.testNum.info}`)
.onClick(() => {
this.testNum.info += 1;
})
ObjectLinkChild({ testNum: this.testNum })
}
}
} 父组件中是一个对象数组,那么我们点击子组件对应的值会相对应的变化
https://i-blog.csdnimg.cn/direct/e1ae7a6d026743bfb624401875b8210e.png
说实话,感觉这个用的并不多,也就没有详细写
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]