鸿蒙ACE-V2状态分析!!双向绑定

110 阅读1分钟

!!语法:双向绑定

developer.huawei.com/consumer/cn…

!!双向绑定语法,是一个语法糖方便开发者实现数据双向绑定,用于初始化子组件的@Param和@Event。其中@Event方法名需要声明为“$”+ @Param属性名

  • 双向绑定语法糖可视为:
  1. Star({ value: this.value, $value: (val: number) => { this.value = val }})

转换前

/**
 *
 * TwoWayCmp.ets
 * Created by unravel on 2024/6/18
 * @abstract
 */

@Entry
@ComponentV2
export struct TwoWayCmp {
  @Local value: number = 0;

  build() {
    Column() {
      Text(`${this.value}`)
      Button(`change value`).onClick(() => {
        this.value++;
      })
      Star({ value: this.value!! })
    }
  }
}


@ComponentV2
struct Star {
  @Param value: number = 0;
  @Event $value: (val: number) => void = (val: number) => {
  };

  build() {
    Column() {
      Text(`${this.value}`)
      Button(`change value `).onClick(() => {
        this.$value(10);
      })
    }
  }
}

转换后

if (!("finalizeConstruction" in ViewPU.prototype)) {
    Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { });
}
export class TwoWayCmp extends ViewV2 {
    constructor(parent, params, __localStorage, elmtId = -1, paramsLambda, extraInfo) {
        super(parent, elmtId, extraInfo);
        this.value = 0;
        this.finalizeConstruction();
    }
    @Local
    value: number;
    initialRender() {
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Column.create();
        }, Column);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create(`${this.value}`);
        }, Text);
        Text.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Button.createWithLabel(`change value`);
            Button.onClick(() => {
                this.value++;
            });
        }, Button);
        Button.pop();
        {
            this.observeComponentCreation2((elmtId, isInitialRender) => {
                if (isInitialRender) {
                    let componentCall = new Star(this, { value: this.value!!, $value: value => { this.value = value; } }, undefined, elmtId, () => { }, { page: "entry/src/main/ets/pages/statev2/TwoWayCmp.ets", line: 19 });
                    ViewV2.create(componentCall);
                    let paramsLambda = () => {
                        return {
                            value: this.value!!
                        };
                    };
                    componentCall.paramsGenerator_ = paramsLambda;
                }
                else {
                    this.updateStateVarsOfChildByElmtId(elmtId, {
                        value: this.value!!
                    });
                }
            }, { name: "Star" });
        }
        Column.pop();
    }
    rerender() {
        this.updateDirtyElements();
    }
    static getEntryName(): string {
        return "TwoWayCmp";
    }
}
class Star extends ViewV2 {
    constructor(parent, params, __localStorage, elmtId = -1, paramsLambda, extraInfo) {
        super(parent, elmtId, extraInfo);
        this.initParam("value", (params && "value" in params) ? params.value : 0);
        this.$value = "$value" in params ? params.$value : (val: number) => {
        };
        this.finalizeConstruction();
    }
    @Param
    readonly value: number;
    @Event
    $value: (val: number) => void;
    initialRender() {
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Column.create();
        }, Column);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create(`${this.value}`);
        }, Text);
        Text.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Button.createWithLabel(`change value `);
            Button.onClick(() => {
                this.$value(10);
            });
        }, Button);
        Button.pop();
        Column.pop();
    }
    public updateStateVars(params) {
        if (params === undefined) {
            return;
        }
        if ("value" in params) {
            this.updateParam("value", params.value);
        }
    }
    rerender() {
        this.updateDirtyElements();
    }
}
registerNamedRoute(() => new TwoWayCmp(undefined, {}), "", { bundleName: "com.unravel.myapplication", moduleName: "entry", pagePath: "pages/statev2/TwoWayCmp", pageFullPath: "entry/src/main/ets/pages/statev2/TwoWayCmp", integratedHsp: "false" });

对比

!!的确是个语法糖

本来我们传的是 {value:this.value!!}

被转换成了 { value: this.value!!, $value: value => { this.value = value; } }

image.png

编译器只负责生成对应的语法。我们自定义组件内部还需要自己写对应类型的参数。感觉似乎也不便捷

image.png