华为HarmonyOS NEXT 原生应用开发:鸿蒙中组件的组件状态管理、组件通信 组件状态管理小案例(好友录)!

文章目录

  • 组件状态管理
      • 一、@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就可以解决一层父子通信的问题。

@Provide:@Provide装饰的状态变量自动对其所有后代组件可用.

@Consume:后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,他是多层级的父子组件之间传递。

2. 使用条件

使用说明:熟

  1. @Consume修饰的状态变量不能主动初始化,只能接受祖先Provide的初始化
  2. @Provide修饰的状态变量必须初始化,可以用于初始化子组件,但不能被父组件初始化。
  3. 两个组件之间状态变量名和类型需要保持一致。
  4. 组件内变量名同名了(当然,进行取别名 @Consume(“别名”)),子组件直接使用别名即可! @Provide(“别名”),子组件同样直接使用别名。
    需要注意:随着新版本的更新优化,组组件有别名的子组件就用别名,有的子组件用了父组件原名的就用其原名,不相互影响。
  • 祖先组件代码
import { SonComponents } from '../components/SonComponents'
@Entry
@Component
struct Index {@State message: string = 'component1';@Provide user: string = 'admin'build() {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 = nextId++this.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.ArkUI'@Entry
@Component
struct Index {// 当前的id值@State PhonePerson: Person[] = [getPhonePerson(), getPhonePerson(), getPhonePerson()]// id容器,我需要得到子组件给我的当前id值@State currentContactID: number = -1// false 选择, true 取消@State titleTextBoolean: boolean = false@State 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: Person@State showFlag: boolean = false@Link @Watch("onClickContactChange") currentContactID: number@Prop titleTextBoolean: boolean@Link 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 给父组件})}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/64239.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pytorch | 对比Pytorch中的十种优化器:基于CIFAR10上的ResNet分类器

Pytorch | 对比Pytorch中的十种优化器&#xff1a;基于CIFAR10上的ResNet分类器 CIFAR10数据集ResNet提出背景网络结构特点工作原理优势 代码实现分析utils.pymain.py导入必要的库设备选择与数据预处理定义加载训练集和测试集主函数部分训练部分测试部分 结果10种优化器对应的训…

Linux系统操作03|chmod、vim

上文&#xff1a; Linux系统操作02|基本命令-CSDN博客 目录 六、chmod&#xff1a;给文件设置权限 1、字母法 2、数字法&#xff08;用的最多&#xff09; 七、vim&#xff1a;代码编写和文本编辑 1、启动和退出 1️⃣启动 2️⃣退出 2、vim基本操作 六、chmod&#x…

徐州数字孪生工业互联网可视化技术,赋能新型工业化智能制造工厂

#徐州数字孪生工业互联网#在当下智能制造的热潮之下&#xff0c;徐州作为中国制造业的重要基地&#xff0c;正积极拥抱数字化转型&#xff0c;通过数字孪生工业互联网可视化技术&#xff0c;赋能新型工业化智能制造工厂&#xff0c;引领制造业向更高效、更智能、更绿色的方向发…

C# 探险之旅:第二十四节 - 类型class基础,一场“类”似的奇妙冒险

嘿&#xff0c;勇敢的探险家们&#xff01;欢迎来到C#王国的“类”似奇妙冒险&#xff01;今天&#xff0c;我们要深入探索一个神秘而强大的领域——class&#xff08;类&#xff09;。想象一下&#xff0c;class就像C#世界里的一块魔法土地&#xff0c;每块土地上都能孕育出独…

(五)机器学习 - 数据分布

数据分布&#xff08;Data Distribution&#xff09;是指数据在不同值或值区间内的分布情况&#xff0c;它描述了数据点在整个数据集中是如何分散或集中的。数据分布可以通过多种方式来分析和表示&#xff0c;包括图形和数值方法。 常见的数据分布特征和描述数据分布的方法&…

基于stm32的红外测温系统设计(论文+源码)

1总体方案设计 本课题为基于STM32的红外测温系统设计&#xff0c;在此将系统架构设计如图3.1所示&#xff0c; 整个系统包括STM32F103单片机&#xff0c;红外测温模块MLX90614&#xff0c;显示模块OLED12864&#xff0c;蜂鸣器以及按键等构成&#xff0c;在功能上&#xff0c;…

排序算法(5):归并排序

问题 排序 [30, 24, 5, 58, 18, 36, 12, 42, 39] 归并排序 归并排序采用分治法&#xff0c;将序列分成若干子序列&#xff0c;每个子序列有序后再合并成有序的完整序列。 在数组排序中&#xff0c;如果只有一个数&#xff0c;那么它本身就是有序的。如果有两个数&#xff0…

JSSIP的使用及问题(webRTC,WebSockets)

简介 项目中有一个需要拨打电话的功能&#xff0c;要求实时的进行音频接听&#xff0c;并且可以在电话接听或者挂断等情况下做出相应的操作。jssip作为一个强大的实现实时通信的javascript库&#xff0c;这不门当户对了嘛。 jssip&#xff08;官网&#xff1a; JsSIP - the J…

DP3复现代码运行逻辑全流程(六)—— gen_demonstration_adroit.sh 演示生成与可视化

用于生成演示、培训和评估的脚本都在 Scripts/ 文件夹中 DP3 通过 gen_demonstration 生成演示&#xff0c;即训练数据&#xff0c;例如: bash scripts/gen_demonstration_adroit.sh hammer 这将在 Adroit 环境中生成锤子任务的演示。数据将自动保存在 3D-Diffusion-Policy/…

Python常用字符串排序●sorted()函数--一行语句简洁实现

在Python等编程中&#xff0c;时常会用到字符串排序。 今天在这里只讲讲最常用的Python字符串排序。 同时&#xff0c;只讲sorted()函数方法。 给定一个字符串列表&#xff1a; sl [共和国, 中国, 中华人民共和国, 大中华, 人民共和国]。 第一种排序方法是不使用任何参数…

知从科技总经理受邀参加上海临港新片区商会“湖畔TECS”技术分享沙龙(第五期)

11月26日&#xff0c;上海知从科技有限公司创始人陈荣波先生受邀出席临港新片区商会 “湖畔TECS”技术分享沙龙&#xff08;第五期&#xff09;活动&#xff0c;并在活动上为参会嘉宾们做了主题分享。本次活动由临港新片区商会主办&#xff0c;智能网联汽车创新联盟协办&#x…

【MySQL数据库】Ubuntu下的mysql

目录 1&#xff0c;安装mysql数据库 2&#xff0c;mysql默认安装路径 3&#xff0c;my.cnf配置文件 4&#xff0c;mysql运用的相关指令及说明 5&#xff0c;数据库、表的备份和恢复 mysql是一套给我们提供数据存取的&#xff0c;更加有利于管理数据的服务的网络程序。下面…

Docker与虚拟机:虚拟化技术的差异解析

在信息技术飞速发展的今天&#xff0c;虚拟化技术已成为现代IT架构不可或缺的一部分。而虚拟化从技术层面划分则分为以下几种&#xff1a; 完全虚拟化&#xff1a;虚拟机能够完全模拟底层硬件的特权指令的执行过程&#xff0c;客户操作系统无须进行修改。 硬件辅助虚拟化&#…

2024.12.14 TCP/IP 网络模型有哪几层?

2024.12.14 TCP/IP 网络模型有哪几层? 2024.12.14 今天周六 看到大伙都在考六级&#xff0c;我来复盘小林coding的计算机网络的知识点&#xff1a; TCP/IP 网络模型有哪几层? 问大家&#xff0c;为什么要有 TCP/IP 网络模型? 对于同一台设备上的进程间通信&#xff0c;有…

一次Mysql查询踩坑经历(查询索引失效问题)

1、之前的sql建表脚本 CREATE TABLE crm_driver (id bigint(22) NOT NULL AUTO_INCREMENT COMMENT 主键,clue_id bigint(20) NOT NULL COMMENT 线索表id,driver_name varchar(128) NOT NULL COMMENT 试驾人姓名,driver_phone varchar(32) NOT NULL COMMENT 试驾人手机号,drive…

从 SSM 视角剖析校园一卡通密钥管理系统的技术架构演进

第2章 开发环境与技术 开发校园一卡通密钥管理系统需要搭建编程的环境&#xff0c;也需要通过调查&#xff0c;对各个相关技术进行分析&#xff0c;选取适合本系统开发的技术与工具。 2.1 MYSQL数据库 题目确定了是一个应用程序之后&#xff0c;就开始按部就班的进行设计与分析…

RabbitMQ中的Publish-Subscribe模式

在现代分布式系统中&#xff0c;消息队列&#xff08;Message Queue&#xff09;是实现异步通信和解耦系统的关键组件。RabbitMQ 是一个功能强大且广泛使用的开源消息代理&#xff0c;支持多种消息传递模式。其中&#xff0c;Publish/Subscribe&#xff08;发布/订阅&#xff0…

【iOS】OC高级编程 iOS多线程与内存管理阅读笔记——自动引用计数(四)

目录 ARC规则 规则 对象型变量不能作为C语言结构体的成员 显式转换id和void* 属性 数组 ARC规则 规则 在ARC有效的情况下编译源代码必须遵守一定的规则&#xff1a; 主要解释一下最后两条 对象型变量不能作为C语言结构体的成员 要把对象型变量加入到结构体成员中时&a…

路由引入问题(双点双向路由回馈问题)

简介 总所周知&#xff0c;路由引入import又称路由重分发redistribute&#xff0c;为了解决不同路由协议进程间路由信息不互通而使用的技术&#xff0c;由于不同路由协议的算法、机制、开销等因素的差异&#xff0c;它们之间无法直接交换路由信息。因此&#xff0c;路由引入技…

26. Three.js案例-自定义多面体

26. Three.js案例-自定义多面体 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染场景的主要类。它支持 WebGL 渲染&#xff0c;并提供了多种配置选项。 构造器 new THREE.WebGLRenderer(parameters) 参数类型描述parametersObject可选参数对象&…