程序员Feri一名12年+的程序员,做过开发带过团队创过业,擅长Java、嵌入式、鸿蒙、人工智能等,专注于程序员成长那点儿事,希望在成长的路上有你相伴!君志所向,一往无前!
状态管理 V1 版本:父子组件数据传递装饰器的奇妙之旅
在HarmonyOS NEXT开发的奇妙世界里,组件就像是一个个独立的小王国,它们各自有着自己的职责和功能。但是,这些小王国之间并不是孤立存在的,它们需要相互交流、相互协作,才能构建出一个完整而强大的应用帝国。
而在这个过程中,数据传递就像是王国之间的信使,负责在不同的组件之间传递信息。
在状态管理的 V1 版本中,我们有两位强大的信使:@Prop
和 @Link
。它们各自有着独特的能力,能够帮助我们实现父子组件之间的数据传递。接下来,让我们一起踏上这场奇妙的旅程,探索它们的奥秘吧!
1. @Prop
:单向传递的快递员
1.1 基本概念
想象一下,有一个快递员叫 @Prop
,他负责从一个王国(父组件)向另一个王国(子组件)传递包裹(数据)。
这个快递员有一个特殊的规则:他只负责把包裹从父组件送到子组件,而子组件对包裹所做的任何修改,他都不会带回给父组件。
1.2 装饰器参数
@Prop
就像是一个不需要任何证件的快递员,他不需要任何参数就能工作。
1.3 同步类型
单向同步。这就好比父组件是包裹的发送者,子组件是包裹的接收者。
发送者可以随时发送新的包裹,接收者会收到最新的包裹内容。但是,接收者对包裹所做的任何修改,发送者都不会知道。
1.4 允许装饰的变量类型
@Prop
这个快递员非常能干,几乎什么类型的包裹都能送。
他可以送 Object
、class
、string
、number
、boolean
、enum
类型的包裹,甚至还可以送这些类型的数组包裹。
1.5 被装饰变量的初始值
@Prop
允许子组件在收到包裹之前,先给自己准备一个初始的包裹内容。但是,一旦收到父组件的包裹,这个初始内容就会被父组件的包裹内容覆盖。
1.6 示例代码
下面是一个有趣的示例,展示了 @Prop
的使用:
doubaocanvas
// 子组件:魔法按钮@Componentexport struct MagicButton { // 魔法按钮的图标库 magicIcons: Resource[] = [ $r("sys.media.star"), $r("sys.media.moon"), $r("sys.media.sun") ]; // 按钮的当前状态 @State currentState: number = 0; // 按钮的名称,由父组件传递 @Prop buttonName: string = "普通按钮"; build() { Column() { // 显示当前的魔法图标 Image(this.magicIcons[this.currentState]) .width(100) .height(100) .animation({ duration: 500, curve: "ease-in-out" }); // 魔法按钮 Button(this.buttonName) .onClick(() => { // 切换魔法状态 this.currentState = (this.currentState + 1) % 3; // 尝试修改按钮名称,但这不会影响父组件 this.buttonName = `魔法状态${this.currentState}`; console.log(`子组件将按钮名称改为:${this.buttonName}`); }) .width(150) .height(50) .backgroundColor("#6200EA") .fontColor(Color.White) .borderRadius(25); } .width("100%") .height("100%") .justifyContent(FlexAlign.Center); }}// 父组件:魔法控制中心@Entry@Componentstruct MagicControlCenter { // 控制中心的状态 @State magicWord: string = "魔法"; build() { Column() { // 输入魔法词 TextInput({ placeholder: "输入魔法词..." }) .onChange(v => { this.magicWord = v; console.log(`父组件设置魔法词为:${this.magicWord}`); }) .width("80%") .margin({ top: 50 }) .backgroundColor("#E0E0E0") .borderRadius(10) .padding(10); // 显示当前魔法词 Text(`当前魔法词:${this.magicWord}`) .fontSize(18) .margin({ top: 20 }); // 使用魔法按钮 MagicButton({ buttonName: this.magicWord }) .margin({ top: 50 }); } .width("100%") .height("100%") .padding(20); }}
1.7 代码解释
在这个魔法世界的示例中,我们有一个魔法控制中心(父组件)和一个魔法按钮(子组件)。控制中心可以通过输入框设置魔法词,然后将这个魔法词作为 buttonName
属性传递给魔法按钮。
当我们在控制中心输入新的魔法词时,魔法按钮会立即更新显示新的名称。但是,当我们点击魔法按钮时,虽然按钮内部会尝试修改 buttonName
,但这个修改不会影响到控制中心的 magicWord
。这就好比魔法按钮只是在自己的小世界里改变了按钮名称的副本,而真正的魔法词仍然掌握在控制中心手中。
2. @Link
:心灵感应的双胞胎
2.1 基本概念
现在,让我们认识另一位神奇的信使 @Link
。他就像是一对心灵感应的双胞胎,无论相隔多远,其中一个的想法和感受都会立即被另一个感知到。
在组件的世界里,@Link
可以让父组件和子组件共享同一个数据,任何一方对数据的修改都会立即反映到另一方。
2.2 装饰器参数
@Link
就像一对不需要任何介绍的双胞胎,他们之间的心灵感应是天生的,不需要任何参数来建立联系。
2.3 同步类型
双向同步。这意味着父组件和子组件就像双胞胎一样,任何一方对共享数据的修改都会立即被另一方感知到。
2.4 允许装饰的变量类型
@Link
这对双胞胎非常包容,几乎可以共享任何类型的数据。
他们可以共享 Object
、class
、string
、number
、boolean
、enum
类型的数据,甚至还可以共享这些类型的数组和 Date
类型的数据。
2.5 被装饰变量的初始值
@Link
这对双胞胎必须从同一个源头获得他们的初始数据,因此子组件不能自己初始化 @Link
装饰的变量,必须由父组件提供初始值。
2.6 示例代码
下面是一个有趣的示例,展示了 @Link
的使用:
doubaocanvas
// 子组件:能量水晶@Componentexport struct EnergyCrystal { // 水晶的不同形态 crystalForms: Resource[] = [ $r("sys.media.crystal_blue"), $r("sys.media.crystal_green"), $r("sys.media.crystal_purple") ]; // 水晶的当前状态 @State currentForm: number = 0; // 能量值,与父组件双向绑定 @Link energyLevel: number; // 上次点击时间,用于防止双击 @State lastClickTime: number = 0; build() { Column() { // 显示当前水晶形态 Image(this.crystalForms[this.currentForm]) .width(150) .height(150) .animation({ duration: 500, curve: "spring" }); // 显示当前能量值 Text(`能量值:${this.energyLevel}`) .fontSize(20) .fontWeight(FontWeight.Bold) .margin({ top: 20 }) .fontColor(this.getEnergyColor()); // 点击水晶增加能量 GestureDetector({ child: Container() .width(150) .height(150) .backgroundColor("#00000000") }) .onClick(() => { const now = Date.now(); // 防止双击 if (now - this.lastClickTime > 300) { this.lastClickTime = now; // 增加能量值 this.energyLevel += 10; // 根据能量值改变水晶形态 this.currentForm = Math.floor(this.energyLevel / 100) % 3; // 播放能量增加动画 this.playEnergyAnimation(); } }); } .width("100%") .height("100%") .justifyContent(FlexAlign.Center); } // 根据能量值获取颜色 getEnergyColor() { if (this.energyLevel < 50) return Color.Red; if (this.energyLevel < 100) return Color.Orange; return Color.Green; } // 播放能量增加动画 playEnergyAnimation() { // 这里可以添加更复杂的动画效果 console.log("能量增加动画播放"); }}// 父组件:能量监控站@Entry@Componentstruct EnergyMonitoringStation { // 总能量值 @State totalEnergy: number = 0; // 能量收集器数量 @State collectorCount: number = 1; build() { Column() { // 显示总能量 Text(`总能量:${this.totalEnergy}`) .fontSize(24) .fontWeight(FontWeight.Bold) .margin({ top: 30 }); // 能量收集器控制 Row() { Text("能量收集器数量:") .fontSize(18); Button("-") .onClick(() => { if (this.collectorCount > 1) { this.collectorCount--; } }) .width(40) .height(40) .backgroundColor("#B71C1C") .fontColor(Color.White) .margin({ left: 20 }); Text(`${this.collectorCount}`) .fontSize(18) .margin({ left: 10, right: 10 }); Button("+") .onClick(() => { if (this.collectorCount < 3) { this.collectorCount++; } }) .width(40) .height(40) .backgroundColor("#2E7D32") .fontColor(Color.White); } .margin({ top: 20 }); // 显示能量收集器 ForEach(Array(this.collectorCount).fill(0), (_, index) => { EnergyCrystal({ energyLevel: this.totalEnergy }) .margin({ top: 30 }); }); // 全局能量控制 Button("重置能量") .onClick(() => { this.totalEnergy = 0; }) .width("80%") .height(50) .backgroundColor("#1A237E") .fontColor(Color.White) .margin({ top: 50 }) .borderRadius(25); } .width("100%") .height("100%") .padding(20); }}
2.7 代码解释
在这个能量世界的示例中,我们有一个能量监控站(父组件)和一个或多个能量水晶(子组件)。
监控站负责监控总能量值,而能量水晶则负责收集能量。
当我们点击能量水晶时,水晶的能量值会增加。由于能量值是通过 @Link
与父组件双向绑定的,所以父组件的总能量值也会立即增加。
同样地,当我们在父组件中重置能量值时,所有子组件的能量值也会立即更新。
这就好比能量监控站和能量水晶是一对心灵感应的双胞胎,无论哪一方的能量发生变化,另一方都能立即感知到并做出相应的反应。
3. 浅拷贝和深拷贝的奇妙比喻
在我们的数据传递旅程中,还有两个重要的概念需要理解:浅拷贝和深拷贝。
让我们用一个有趣的比喻来解释它们。
假设你有一本非常珍贵的魔法书,里面有许多强大的咒语。浅拷贝就像是给这本书拍了一张照片,照片上的咒语看起来和原书一模一样,但实际上只是一个图像,如果你试图在照片上修改咒语,是不会有任何效果的。
而深拷贝则像是完全复制了一本魔法书,包括书中的每一个字、每一个魔法符号。这两本书是完全独立的,你可以在其中一本上随意修改咒语,而不会影响另一本。
在 @Prop
和 @Link
的使用中,如果传递的是引用类型的数据(如对象或数组),就需要注意是使用浅拷贝还是深拷贝,以避免意外的数据修改。
4. 总结
在这场奇妙的旅程中,我们认识了两位强大的信使:@Prop
和 @Link
。@Prop
就像是一个单向传递的快递员,负责将数据从父组件传递到子组件,但不会将子组件的修改带回给父组件。
而 @Link
则像是一对心灵感应的双胞胎,让父组件和子组件能够共享数据,任何一方的修改都会立即被另一方感知到。
通过这两位信使,我们可以在组件之间建立起高效、可靠的数据传递通道,让我们的应用帝国更加稳固和强大。
希望通过这个生动有趣的比喻,你对 @Prop
和 @Link
有了更深入的理解。在你的HarmonyOS NEXT开发旅程中,好好利用这两位信使,创造出更加精彩的应用吧!
好啦,本篇就到这里啦,加油哟!关注我,跟我一起成长哈!