做se要明白网站,cdn 加速 网站,响应网站模板下载,网站建设 书文章目录 组件状态管理一、State装饰器1. State装饰器的特点2. State装饰器的使用 二、Prop装饰器#xff08;父子单向通信#xff09;1. Prop装饰器的特点2. Prop装饰器的使用示例 三、Link装饰器#xff08;父子双向通信#xff09;1. Link装饰器的特点3. Link使用示例 四… 文章目录 组件状态管理一、State装饰器1. State装饰器的特点2. State装饰器的使用 二、Prop装饰器父子单向通信1. Prop装饰器的特点2. Prop装饰器的使用示例 三、Link装饰器父子双向通信1. Link装饰器的特点3. Link使用示例 四、Provide/Consume装饰器祖孙后代双向通信1. 特点2. 使用条件 五、Observed装饰器和ObjectLink装饰器1. 特点2. 使用说明代码示例 六、拓展装饰器组件状态管理案例练习 - 好友录 组件状态管理
一、State装饰器
1. State装饰器的特点 ● State装饰的变量与子组件中的Prop装饰变量之间建立单向数据同步,与Link、ObjectLink装饰变量之间建立双向数据同步。 ● State装饰的变量生命周期与其所属自定义组件的生命周期相同 2. State装饰器的使用
简单示例 以下示例为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;})}
}该装饰器修饰的变量将别 UI 框架监视。需要注意该变量访问权只在该组件中且必须初始化。
二、Prop装饰器父子单向通信
1. Prop装饰器的特点 ● 传递的是数据的深拷贝每次都会拷贝数据源然后流转到子组件 并且支持嵌套传递。 在父子组件中使用该装饰器实现单向数据流。 ● 父组件数据源修改数据Prop修饰的变量都会进行覆盖变化。 ● 子组件对Prop修饰的变量进行数据修改并不会影响到父组件数据源。 2. Prop装饰器的使用示例
父组件发生变化数据流向子组件实现单向同步而子组件修改数据不影响父组件数据源。子组件你数据使劲修改父组件最终修改数据都会同步到子组件 Entry
Component
struct CStatusPage {State age: number 0build() {Column({ space: 20 }) {Column({ space: 20 }) {Text(父组件: this.age).fontSize(20)// 给子组件传参ChildComponent({age: this.age})}.width(50%).height(200).justifyContent(FlexAlign.Center).padding(20).backgroundColor(Color.Pink)Row({space: 100 }) {Button(父组件 1).onClick(() {this.age})}.width(100%).justifyContent(FlexAlign.Center)}.height(100%).width(100%).justifyContent(FlexAlign.Center)}
}Component
struct ChildComponent {// 接收父组件参数Prop age: number 0build() {Column() {Row() {Text(子组件: this.age).fontSize(18)}.width(80%).height(100).backgroundColor(Color.Green)Button(子组件 1).onClick(() {this.age})}}
}
三、Link装饰器父子双向通信
1. Link装饰器的特点
双向数据流Link装饰的变量与其父组件中的数据源共享相同的值。 ● 浅拷贝直接将引用地址进行共享同样支持嵌套。
限制条件 ● Link装饰器不能在Entry装饰的组件中使用。 ● 禁止子组件在本地初始化数据父类数据直接流到子类允许访问和修改若是赋值就没有意义。 ● 私有只能在所属组件内访问。
3. Link使用示例 和上方 Prop 大差不差Link 是双向数据流父组件可以修改子子也可以修改父组件。 Entry
Component
struct CStatusPage {State age: number 0build() {Column({ space: 20 }) {Column({ space: 20 }) {Text(父组件: this.age).fontSize(20)// 给子组件传参ChildComponent({age: this.age})}.width(50%).height(200).justifyContent(FlexAlign.Center).padding(20).backgroundColor(Color.Pink)Row({space: 100 }) {Button(父组件 1).onClick(() {this.age})}.width(100%).justifyContent(FlexAlign.Center)}.height(100%).width(100%).justifyContent(FlexAlign.Center)}
}Component
struct ChildComponent {// 接收父组件参数 (需要注意不能有初始值因为和父组件共享一份有初始值就没有意义了)Link age: numberbuild() {Column() {Row() {Text(子组件: this.age).fontSize(18)}.width(80%).height(100).backgroundColor(Color.Green)Button(子组件 1).onClick(() {this.age})}}
}四、Provide/Consume装饰器祖孙后代双向通信
1. 特点
双向数据流、UI框架可以跨多层检测。 使用场景 一般在一个组件中嵌套两层一及以上的组件使用否则直接用Link就可以解决一层父子通信的问题。
ProvideProvide装饰的状态变量自动对其所有后代组件可用.
Consume后代通过使用Consume去获取Provide提供的变量建立在Provide和Consume之间的双向数据同步与State/Link不同的是他是多层级的父子组件之间传递。
2. 使用条件
使用说明熟
Consume修饰的状态变量不能主动初始化只能接受祖先Provide的初始化Provide修饰的状态变量必须初始化可以用于初始化子组件但不能被父组件初始化。两个组件之间状态变量名和类型需要保持一致。组件内变量名同名了当然进行取别名 Consume“别名”子组件直接使用别名即可 Provide“别名”子组件同样直接使用别名。 ● 需要注意随着新版本的更新优化组组件有别名的子组件就用别名有的子组件用了父组件原名的就用其原名不相互影响。
祖先组件代码
import { SonComponents } from ../components/SonComponents
Entry
Component
struct Index {State message: string component1;Provide user: string adminbuild() {Column({ space: 50}) {Text(this.message).fontSize(50)Row() {SonComponents()}}.height(100%).width(100%)}
}第一层组件代码
import { Sun } from ../components/Sun
Component
export struct SonComponents {build() {Column() {Text(SonComponents2).fontSize(40)Sun()}.width(100%).height(100%)}
}第三层组件代码
Component
export struct Sun {Consume user: stringbuild() {Column() {Text(this.user).fontSize(40)}.width(100%).height(100%)}
}五、Observed装饰器和ObjectLink装饰器
1. 特点 2. 使用说明
● ObjectLink装饰器不能在Entry装饰的自定义组件中使用。 ● ObjectLink中的属性可以被修改但是不能直接覆盖自身
代码示例
// 允许ObjectLink装饰的数据属性赋值
this.objLink.a ...
// 不允许ObjectLink装饰的数据自身赋值
this.objLink ...class ClassA {public c: number;constructor(c: number) {this.c c;}
}Observed
class ClassB {public a: ClassA;public b: number;constructor(a: ClassA, b: number) {this.a a;this.b b;}
}
ClassB被Observed装饰其成员变量的赋值的变化是可以被观察到的但对于ClassA没有被Observed装饰其属性的修改不能被观察到。
ObjectLink b: ClassB// 赋值变化可以被观察到
this.b.a new ClassA(5)
this.b.b 5// ClassA类没有被Observed装饰嵌套在ClassB类中其属性的变化观察不到
this.b.a.c 5
六、拓展装饰器
Require修饰符 ● 主要用于数据参数校验添加该修饰符后必须传递参数故此也可以不给初始值。 Track修饰符 主要用于做新能优化的 组件状态管理案例练习 - 好友录
可以跟着源码写一遍熟悉一下主要练习组件通信。 数据模型文件源码
let nextId 1// 随机姓名数组
const NameArr: string[] [子涵, 天宇, 雨欣, 晨曦, 思琪, 佳怡, 子轩, 浩然, 梦洁,文博, 子涵, 明轩, 诗涵, 子轩, 明轩, 子涵, 天宇, 雨欣,晨曦, 思琪, 佳怡, 子轩, 浩然, 梦洁, 文博, 诗涵, 子轩,明轩, 子涵, 天宇, 雨欣, 晨曦, 思琪, 佳怡, 子轩, 浩然,梦洁, 文博, 诗涵, 子轩, 明轩, 子涵, 天宇, 雨欣, 晨曦,思琪, 佳怡, 子轩, 浩然, 梦洁, 文博, 诗涵, 子轩, 明轩,子涵, 天宇, 雨欣, 晨曦, 思琪, 佳怡, 子轩, 浩然, 梦洁,文博, 诗涵, 子轩, 明轩, 子涵, 天宇, 雨欣, 晨曦, 思琪,佳怡, 子轩, 浩然, 梦洁, 文博, 诗涵, 子轩, 明轩, 小欣,梦洁, 文博, 诗涵, 子轩, 明轩, 子涵, 天宇, 雨欣, 晨曦,思琪, 佳怡, 子轩, 浩然, 梦洁, 文博, 诗涵, 子轩, 明轩,欣姚
]
// 随机生成的 手机号码Observed
export class Person {id: numbername: stringphone: stringisStar: boolean falseconstructor(name: string, phone: string) {this.id nextIdthis.name namethis.phone phone}
}export function getPhonePerson (): Person {let personArr new Person(randomNameHandle(), randomPhoneNumberHandle())return personArr
}// 随机生成姓名
export function randomNameHandle(): string {let name: string let randomNameNumber: number Math.floor(Math.random() * 100 )name NameArr[randomNameNumber]return name
}// 生成随机的手机号
export function randomPhoneNumberHandle(): string {// 生成 11 位随机数字let phoneNumber ;for (let i 0; i 11; i) {phoneNumber Math.floor(Math.random() * 10).toString();}return phoneNumber;
}index文件源码
import { Person, getPhonePerson } from ./model/DataModel
import { promptAction } from kit.ArkUIEntry
Component
struct Index {// 当前的id值State PhonePerson: Person[] [getPhonePerson(), getPhonePerson(), getPhonePerson()]// id容器我需要得到子组件给我的当前id值State currentContactID: number -1// false 选择 true 取消State titleTextBoolean: boolean falseState deleteArrList: number[] []build () {Column() {// 标题Row({ space: 10 }) {Text(联系人).fontSize(24).fontWeight(FontWeight.Bold)Blank()Button(this.titleTextBoolean ? 取消 : 选择).fontColor(Color.White).fontSize(14).backgroundColor(this.titleTextBoolean ? Color.Red : #007dfe).onClick(() {this.titleTextBoolean ! this.titleTextBooleanthis.deleteArrList []})Button( ).fontColor(Color.White).fontSize(14).onClick(() {// 新增联系人往数组追加对象this.PhonePerson.push(getPhonePerson())})}.width(100%)// 主体列表List({ space: 10 }) {ForEach(this.PhonePerson, (item: Person, index: number) {ListItem() {// 联系人项目ContactPersonComponent({// 将当前对象传递下去item: item,currentContactID: this.currentContactID,titleTextBoolean: this.titleTextBoolean,deleteArrList: this.deleteArrList})}})}.margin({ top: 10 }).layoutWeight(1)// 底部按钮if (this.titleTextBoolean) {Button(this.deleteArrList.length 0 ? 取消 : 删除).fontColor(Color.White).backgroundColor(this.deleteArrList.length 0 ? Color.Gray : Color.Red).onClick(() {if (this.deleteArrList.length 0) {promptAction.showToast({message: 操作取消,textColor: #FFCCAA})this.titleTextBoolean false} else {for(let item 0; item this.PhonePerson.length; item) {for(let i 0; i this.deleteArrList.length; i) {if (this.PhonePerson[item].id this.deleteArrList[i]) {this.PhonePerson.splice(item, 1)}}}// 复原操作this.titleTextBoolean false// 每次删除完成后重置数组this.deleteArrList []promptAction.showToast({message: 删除成功,textColor: #8ADAB2})}})}}.width(100%).height(100%).padding(15).backgroundColor(#ffd6d4d4)}
}Component
struct ContactPersonComponent {ObjectLink item: PersonState showFlag: boolean falseLink Watch(onClickContactChange) currentContactID: numberProp titleTextBoolean: booleanLink deleteArrList: number[]onClickContactChange() {// 只要id发生变化则将id 不等于当前的联系人详细信息项关闭if(this.currentContactID ! this.item.id) {this.showFlag false}}build() {Column({ space: 15 }) {Row({ space: 10 }) {if (this.titleTextBoolean) {Toggle({ type: ToggleType.Checkbox}) // {type: 按钮类型 isOn 按钮是否选中状态}.selectedColor(#FFB0B0) // Toggle按钮组件 选中时候的颜色.onChange((value: boolean) {// value值为true和false二者之间随时切换如果用户点击就为true在次点击就为falseif (value) {this.deleteArrList.push(this.item.id)} else {// 获取该元素在deleteArrList的位置以便后续删除操作let index: number this.deleteArrList.indexOf(this.item.id)this.deleteArrList.splice(index, 1)}})}Image($r(app.media.startIcon)).width(35).height(35)Text(this.item.name)Blank()Image(this.item.isStar ? $r(app.media.select_collection) : $r(app.media.collection)).width(24).onClick(() {this.item.isStar ! this.item.isStar// 弹框提示if (this.item.isStar) {promptAction.showToast({message: 收藏成功,alignment: Alignment.Bottom,offset: { dx: 0, dy: -200},textColor: #9ADE7B})} else {promptAction.showToast({message: 取消收藏,alignment: Alignment.Bottom,offset: { dx: 0, dy: -200},textColor: Color.Red})}})}.width(100%).height(60)if (this.showFlag) {Divider().strokeWidth(2).color(Color.Black)Row({ space: 20 }) {Text(手机号码)Text(this.item.phone)}.width(100%).justifyContent(FlexAlign.Start).padding(15)}}.backgroundColor(Color.White).padding({ top: 5, bottom: 5, left: 10, right: 10 }).borderRadius(15).onClick(() {this.showFlag ! this.showFlagthis.currentContactID this.item.id // 将当前点击的联系人 id 给父组件})}
}