
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
@Link和@ObservedLink都是用来双向同步父组件和子组件的状态,那它们有什么区别呢?本文做一些浅析比较他们的使用场景和区别以及使用@ObservedLink注意事项,起到抛砖引玉的效果
@Link往往与@State搭配使用,前者在子组件,后者在父组件
@Entry
@Component
struct Player {
@State isPlaying: boolean = false
build() {
Column() {
PlayButton({buttonPlaying: $isPlaying})
Text(`Player is ${this.isPlaying? '':'not'} playing`)
}
}
}
@Component
struct PlayButton {
@Link buttonPlaying: boolean
build() {
Column() {
Button() {
Image(this.buttonPlaying? 'play.png' : 'pause.png')
}.onClick(() => {
this.buttonPlaying = !this.buttonPlaying
})
}
}
}
@Link和@ObservedLink很类似,都可以理解成一个指针,子组件的对象指向父组件的对象,但是什么时候用@Link,什么时候用@ObservedLink呢?
官方解释给出了一大段说明引入的动机,我看的比较懵逼,有理解的小伙伴不妨评论解释下。按照我的理解是单个变量用@Link,一组变量用@ObservedLink
注:@Link也可以修饰自定义的class
class CircleBean {
radius: number
offsetX: number = 0
offsetY: number = 0
}
@Entry
@Component
struct Index {
@State bean: CircleBean = new CircleBean()
build() {
Stack() {
MyCircle({ bean: $bean, onTouch: this.onBeanTouch.bind(this) })
}
.width('100%')
.height('100%')
}
}
@Component
struct MyCircle {
@Link bean: CircleBean
build() {
Circle()
.size({ width: this.bean.radius, height: this.bean.radius })
.offset({ x: this.bean.offsetX, y: this.bean.offsetY })
.backgroundColor("#ff0")
}
}
如果是用到Foreach的情况下就需要用到@ObservedLink,因为@Link需要一个@State的变量来连接,而我们需要渲染一堆组件,往往把这一对数据放到一个集合中,然后使用ForEach,这时就不能使用@Link而用@ObservedLink了
@Observed
class CircleBean {
radius: number = 0
offsetX: number = 0
offsetY: number = 0
}
@Entry
@Component
struct Index {
@State beans: Array<CircleBean> = new Array<CircleBean>()
onPageShow() {
let offset = 0
for (let i = 0;i < 3; i++) {
let b = new CircleBean()
b.radius = (i + 1) * 50
b.offsetX = 0
offset += b.radius
b.offsetY = offset
this.beans.push(b)
}
}
build() {
Stack() {
ForEach(this.beans, (b) => {
MyCircle({ bean: b, onTouch: this.onBeanTouch.bind(this) })
})
}
.width('100%')
.height('100%')
}
}
@Component
struct MyCircle {
@ObjectLink bean: CircleBean
build() {
Circle()
.size({ width: this.bean.radius, height: this.bean.radius })
.offset({ x: this.bean.offsetX, y: this.bean.offsetY })
.backgroundColor("#ff0")
}
}
解释
总结:@Link适用于单个对象,@ObservedLinked适用于集合对象
@Observed
class CircleBean {
radius: number
}
@Observed
class RingBean extends CircleBean {
thickness: number
}
@Observed
class CircleBean {
radius: number
}
class RingBean extends CircleBean {
thickness: number
}
let b = new CircleBean()
console.log("b instanceof CircleBean:"+(b instanceof CircleBean)) //false
b = new RingBean()
console.log("b instanceof CircleBean:"+(b instanceof CircleBean)) //false
console.log("b instanceof CircleBean:"+(b instanceof RingBean)) //false
@Observed
class CircleBean {
radius: number
fun1(){
console.log("fun1")
}
}
class RingBean extends CircleBean {
thickness: number
fun2(){
console.log("fun2")
}
}
let b = new CircleBean()
b.fun1()
let rb: RingBean = new RingBean()
rb.fun2()
@Observed
class CircleBean {
radius: number
static print() {
console.log('print')
}
}
@Entry
@Component
struct Index {
onPageShow() {
RingBean.print()
}
}
TypeError: not a function
总结:Observed会影响类的继承,类的静态方法
@Component
struct MyCircle {
@ObjectLink bean: CircleBean
build() {
Circle()
.size({ width: this.bean.radius, height: this.bean.radius })
.onTouch(e => {
this.onBeanTouch(this.bean, e)
this.onBeanTouch2(e)
})
.offset({ x: this.bean.offsetX, y: this.bean.offsetY })
.backgroundColor("#ff0")
}
onBeanTouch(b: CircleBean, e: TouchEvent) {
console.log("b==this.bean:"+(b==this.bean)+",b====this.bean:"+(b===this.bean))
console.log("onBeanTouch:" + b.offsetX + "," + b.offsetY + ",type:" + e.type)
switch (e.type) {
case TouchType.Down: {
this.screenX = e.touches[0].screenX
this.screenY = e.touches[0].screenY
break
}
case TouchType.Move: {
let x = e.touches[0].screenX - this.screenX
let y = e.touches[0].screenY - this.screenY
b.offsetX += x;
b.offsetY += y;
break
}
case TouchType.Up: {
let x = e.touches[0].screenX - this.screenX
let y = e.touches[0].screenY - this.screenY
b.offsetX += x;
b.offsetY += y;
break
}
}
this.screenX = e.touches[0].screenX
this.screenY = e.touches[0].screenY
}
解释:Line8调用onBeanTouch时将this.bean作为形参传递过去,并在onBeanTouch中用b来代替,经过测试对b的内容进行修改不会引起重绘,经过打印比较b和this.bean,无论比较内容还是比较地址都是false,我们可以得出函数调用会改变我们的对象
onBeanTouch2(e: TouchEvent) {
let b = this.bean
console.log("b==this.bean:"+(b==this.bean)+",b====this.bean:"+(b===this.bean))
console.log("onBeanTouch:" + b.offsetX + "," + b.offsetY + ",type:" + e.type)
switch (e.type) {
case TouchType.Down: {
this.screenX = e.touches[0].screenX
this.screenY = e.touches[0].screenY
break
}
case TouchType.Move: {
let x = e.touches[0].screenX - this.screenX
let y = e.touches[0].screenY - this.screenY
b.offsetX += x;
b.offsetY += y;
break
}
case TouchType.Up: {
let x = e.touches[0].screenX - this.screenX
let y = e.touches[0].screenY - this.screenY
b.offsetX += x;
b.offsetY += y;
break
}
}
this.screenX = e.touches[0].screenX
this.screenY = e.touches[0].screenY
}