目录

系统组件双向同步语法对深层对象是否兼容

问题现象

系统组件双向同步语法是否兼容深层嵌套对象?

背景知识

解决方案

ArkUI完全支持深层对象的双向同步,可以通过以下两种方案来实现:

  1. 方案一:在状态管理V1中,推荐使用$$实现系统组件的双向绑定。

    示例代码如下:

    @Component
    struct SyncPage {
      @State model: modelFirst = new modelFirst();
      @State message: string = '';
    
      build() {
        Column({ space: 20 }) {
          Text(this.message);
          TextInput({ text: $$this.model.modelThird.modelForth })
            .placeholderColor(Color.Grey)
            .placeholderFont({ size: 14, weight: 400 })
            .caretColor(Color.Blue)
            .width(300)
            .onChange(() => {
              this.message = this.model.modelThird.modelForth;
            });
        }.width('100%').justifyContent(FlexAlign.Center);
      }
    }

    实体类:

    interface ModelInterfaceFir {
      modelForth: string;
    }
    
    export class modelFirst {
      modelFirst: string = '';
      modelSecond: number = 0;
      modelThird: ModelInterfaceFir = { modelForth: 'modelForth' };
    }
  2. 方案二:在状态管理V2中,推荐使用!!语法糖统一处理双向绑定。
    • !!双向绑定语法不支持多层父子组件传递。
    • 不支持与@Event混用。从API version 18开始,当使用!!双向绑定语法给子组件传递参数时,给对应的@Event方法传参会编译报错。
    • 当使用3个或更多感叹号(!!!、!!!!、!!!!!等)时,不支持双向绑定功能。

    示例代码如下:

    @ComponentV2
    struct LocalChangePage {
      @Param model: modelSecond = new modelSecond('modelFirst', 10, new ModelInterfaceSec('modelForth'), new ModelIn(10));
      @Event $value: (val: modelSecond) => void = () => {
      };
      message: string = '';
    
      build() {
        Column({ space: 20 }) {
          Text(this.model.modelThird.modelForth);
          TextInput({ text: this.model.modelThird.modelForth!! })
            .placeholderColor(Color.Grey)
            .placeholderFont({ size: 14, weight: 400 })
            .caretColor(Color.Blue)
            .width(300)
            .onChange(() => {
              this.message = this.model.modelThird.modelForth;
            });
        };
      };
    }

    实体类:

    @ObservedV2
    export class ModelInterfaceSec {
      @Trace
      modelForth: string;
    
      constructor(modelForth: string) {
        this.modelForth = modelForth;
      }
    }
    
    @ObservedV2
    export class ModelIn {
      @Trace
      modelFifth: number;
    
      constructor(modelFifth: number) {
        this.modelFifth = modelFifth;
      }
    }
    
    @ObservedV2
    export class modelSecond {
      @Trace
      modelFirst: string = '';
      @Trace
      modelSecond: number = 0;
      @Trace
      modelThird: ModelInterfaceSec = new ModelInterfaceSec('modelForth');
      @Trace
      modelSixth: ModelIn = new ModelIn(10);
    
      constructor(modelFirst: string, modelSecond: number, modelThird: ModelInterfaceSec, modelSixth: ModelIn) {
        this.modelFirst = modelFirst;
        this.modelSecond = modelSecond;
        this.modelThird = modelThird;
        this.modelSixth = modelSixth;
      }
    }

    全量代码如下:

    interface ModelInterfaceFir {
      modelForth: string;
    }
    
    export class modelFirst {
      modelFirst: string = '';
      modelSecond: number = 0;
      modelThird: ModelInterfaceFir = { modelForth: 'modelForth' };
    }
    
    @ObservedV2
    export class ModelInterfaceSec {
      @Trace
      modelForth: string;
    
      constructor(modelForth: string) {
        this.modelForth = modelForth;
      }
    }
    
    @ObservedV2
    export class ModelIn {
      @Trace
      modelFifth: number;
    
      constructor(modelFifth: number) {
        this.modelFifth = modelFifth;
      }
    }
    
    @ObservedV2
    export class modelSecond {
      @Trace
      modelFirst: string = '';
      @Trace
      modelSecond: number = 0;
      @Trace
      modelThird: ModelInterfaceSec = new ModelInterfaceSec('modelForth');
      @Trace
      modelSixth: ModelIn = new ModelIn(10);
    
      constructor(modelFirst: string, modelSecond: number, modelThird: ModelInterfaceSec, modelSixth: ModelIn) {
        this.modelFirst = modelFirst;
        this.modelSecond = modelSecond;
        this.modelThird = modelThird;
        this.modelSixth = modelSixth;
      }
    }
    
    @Entry
    @ComponentV2
    struct LineBreakStrategyExample {
      build() {
        Column() {
          Column({ space: 15 }) {
            Text('方案一');
            SyncPage();
          }
          .height('50%')
          .margin({
            top: 30
          });
    
          Column({ space: 15 }) {
            Text('方案二');
            LocalChangePage();
          }
          .height('50%');
        };
      }
    }
    
    @ComponentV2
    struct LocalChangePage {
      @Param model: modelSecond = new modelSecond('modelFirst', 10, new ModelInterfaceSec('modelForth'), new ModelIn(10));
      @Event $value: (val: modelSecond) => void = () => {
      };
      message: string = '';
    
      build() {
        Column({ space: 20 }) {
          Text(this.model.modelThird.modelForth);
          TextInput({ text: this.model.modelThird.modelForth!! })
            .placeholderColor(Color.Grey)
            .placeholderFont({ size: 14, weight: 400 })
            .caretColor(Color.Blue)
            .width(300)
            .onChange(() => {
              this.message = this.model.modelThird.modelForth;
            });
        };
      };
    }
    
    @Component
    struct SyncPage {
      @State model: modelFirst = new modelFirst();
      @State message: string = '';
    
      build() {
        Column({ space: 20 }) {
          Text(this.message);
          TextInput({ text: $$this.model.modelThird.modelForth })
            .placeholderColor(Color.Grey)
            .placeholderFont({ size: 14, weight: 400 })
            .caretColor(Color.Blue)
            .width(300)
            .onChange(() => {
              this.message = this.model.modelThird.modelForth;
            });
        }.width('100%').justifyContent(FlexAlign.Center);
      }
    }