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

#### 问题现象

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

#### 背景知识

*   [$$语法：系统组件双向同步](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-two-way-sync)：$$运算符为系统组件提供TS变量的引用，使得TS变量和系统组件的内部状态保持同步。
*   [!!语法：双向绑定](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-binding)：在状态管理V1中，使用$$实现系统组件的双向绑定。在状态管理V2中，使用!!语法糖统一处理双向绑定。

#### 解决方案

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

1.  方案一：在状态管理V1中，推荐使用[$$](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-two-way-sync)实现系统组件的双向绑定。
    
    *   当前$$支持基础类型变量，当该变量使用@State、@Link、@Prop、@Provide等状态管理V1装饰器装饰，或者@Local等状态管理V2装饰器装饰时，变量值的变化会触发UI刷新。
    *   当前$$支持的组件：
        
        | 
        组件
        
         | 
        
        支持的参数/属性
        
         | 
        
        起始API版本
        
         |
        | :-- | :-- | :-- |
        | 
        
        [Checkbox](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-checkbox)
        
         | 
        
        select
        
         | 
        
        10
        
         |
        | 
        
        [CheckboxGroup](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-checkboxgroup)
        
         | 
        
        selectAll
        
         | 
        
        10
        
         |
        | 
        
        [DatePicker](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-datepicker)
        
         | 
        
        selected
        
         | 
        
        10
        
         |
        | 
        
        [TimePicker](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-timepicker)
        
         | 
        
        selected
        
         | 
        
        10
        
         |
        | 
        
        [MenuItem](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-menuitem)
        
         | 
        
        selected
        
         | 
        
        10
        
         |
        | 
        
        [Panel](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-panel)
        
         | 
        
        mode
        
         | 
        
        10
        
         |
        | 
        
        [Radio](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-radio)
        
         | 
        
        checked
        
         | 
        
        10
        
         |
        | 
        
        [Rating](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-rating)
        
         | 
        
        rating
        
         | 
        
        10
        
         |
        | 
        
        [Search](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-search)
        
         | 
        
        value
        
         | 
        
        10
        
         |
        | 
        
        [SideBarContainer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-sidebarcontainer)
        
         | 
        
        showSideBar
        
         | 
        
        10
        
         |
        | 
        
        [Slider](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-slider)
        
         | 
        
        value
        
         | 
        
        10
        
         |
        | 
        
        [Stepper](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-stepper)
        
         | 
        
        index
        
         | 
        
        10
        
         |
        | 
        
        [Swiper](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper)
        
         | 
        
        index
        
         | 
        
        10
        
         |
        | 
        
        [Tabs](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-tabs)
        
         | 
        
        index
        
         | 
        
        10
        
         |
        | 
        
        [TextArea](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-textarea)
        
         | 
        
        text
        
         | 
        
        10
        
         |
        | 
        
        [TextInput](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-textinput)
        
         | 
        
        text
        
         | 
        
        10
        
         |
        | 
        
        [TextPicker](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-textpicker)
        
         | 
        
        selected、value
        
         | 
        
        10
        
         |
        | 
        
        [Toggle](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-toggle)
        
         | 
        
        isOn
        
         | 
        
        10
        
         |
        | 
        
        [AlphabetIndexer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-alphabet-indexer)
        
         | 
        
        selected
        
         | 
        
        10
        
         |
        | 
        
        [Select](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-select)
        
         | 
        
        selected、value
        
         | 
        
        10
        
         |
        | 
        
        [BindSheet](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-sheet-transition#bindsheet)
        
         | 
        
        isShow
        
         | 
        
        10
        
         |
        | 
        
        [BindContentCover](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-modal-transition#bindcontentcover)
        
         | 
        
        isShow
        
         | 
        
        10
        
         |
        | 
        
        [Refresh](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-refresh)
        
         | 
        
        refreshing
        
         | 
        
        8
        
         |
        | 
        
        [GridItem](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-griditem)
        
         | 
        
        selected
        
         | 
        
        10
        
         |
        | 
        
        [ListItem](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitem)
        
         | 
        
        selected
        
         | 
        
        10
        
         |
        
    
    示例代码如下：
    
    @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中，推荐使用[!!](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-two-way-sync)语法糖统一处理双向绑定。
    
    *   !!双向绑定语法不支持多层父子组件传递。
    *   不支持与@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);
      }
    }