程序员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 的使用:
// 子组件:魔法按钮
@Component
export 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
@Component
struct 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
// 子组件:能量水晶
@Component
export 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());
// 点击水晶增加能量
Button("点击水晶增加能量")
.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
@Component
struct 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开发旅程中,好好利用这两位信使,创造出更加精彩的应用吧!
好啦,本篇就到这里啦,加油哟!关注我,跟我一起成长哈!