# !!语法：双向绑定

在状态管理V1中，推荐使用$$实现系统组件的双向绑定。

在状态管理V2中，推荐使用!!语法糖统一处理双向绑定。

!!语法从API version 12开始支持。

#### 概述

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

*   如果使用了!!双向绑定语法，表明父组件的变化会同步给子组件，子组件的变化也会同步给父组件。
*   父组件未使用!!时，变化是单向的。

#### 使用场景

#### 自定义组件间双向绑定

1.  在Index中构造Star子组件，双向绑定父子组件中的value属性，并初始化子组件的@Param value和@Event $value。
    
    @Param与@Event装饰器配合使用的双向绑定语法糖。
    
    ```
    Star({ value: this.value, $value: (val: number) => { this.value = val; } })
    ```
    
    上述语法可以简化为!!双向绑定语法糖。
    
    ```
    Star({ value: this.value!! })
    ```
    
2.  使用@Param value与@Event $value语法实现自定义组件双向绑定。
    
    ```
    @Entry
    @ComponentV2
    struct Index {
      @Local value: number = 0;
    
      build() {
        Column() {
          Text(`${this.value}`)
          // 点击Index中的Button改变value值，父组件Index和子组件Star中的Text将同步更新。
          Button(`change value in parent component`).onClick(() => {
            this.value++;
          })
          // 使用@Param与@Event语法实现自定义组件双向绑定。
          Star({ value: this.value, $value: (val: number) => { this.value = val; } })
          // ...
        // ···
        }
      }
    }
    
    @ComponentV2
    struct Star {
      @Param value: number = 0;
      @Event $value: (val: number) => void = (val: number) => {};
    
      build() {
        Column() {
          Text(`${this.value}`)
          // 点击子组件Star中的Button，调用`this.$value(10)`方法，父组件Index和子组件Star中的Text将同步更新。
          Button(`change value in child component`).onClick(() => {
            this.$value(10);
          })
        }
      }
    }
    ```
    
3.  使用!!语法糖实现自定义组件双向绑定。
    
    ```
    @Entry
    @ComponentV2
    struct Index {
      @Local value: number = 0;
    
      build() {
        Column() {
          Text(`${this.value}`)
          // 点击Index中的Button改变value值，父组件Index和子组件Star中的Text将同步更新。
          Button(`change value in parent component`).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}`)
          // 点击子组件Star中的Button，调用`this.$value(10)`方法，父组件Index和子组件Star中的Text将同步更新。
          Button(`change value in child component`).onClick(() => {
            this.$value(10);
          })
        }
      }
    }
    ```
    

**使用限制**

*   !!双向绑定语法不支持多层父子组件传递。
*   不支持与@Event混用。从API version 18开始，当使用!!双向绑定语法给子组件传递参数时，给对应的@Event方法传参会编译报错。
*   当使用3个或更多感叹号（!!!、!!!!、!!!!!等）时，不支持双向绑定功能。

#### 系统组件参数双向绑定

!!运算符为系统组件提供TS变量的引用，使得TS变量和系统组件的内部状态保持同步。添加方式是在变量名后添加，例如isShow!!。

内部状态的含义由组件或属性决定。例如：bindMenu属性的isShow参数。

```
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = 'click show Menu';
const DOMAIN = 0xFF00;

@Entry
@ComponentV2
struct BindMenuInterface {
  @Local isShow: boolean = false;

  build() {
    Column() {
      Row() {
        Text('click show Menu')
          .bindMenu(this.isShow!!, // 双向绑定。
            [
              {
                value: 'Menu1',
                action: () => {
                  hilog.info(DOMAIN, TAG, 'handle Menu1 click');
                }
              },
              {
                value: 'Menu2',
                action: () => {
                  hilog.info(DOMAIN, TAG, 'handle Menu2 click');
                }
              },
            ])
      }.height('50%')
      
      Text('isShow: ' + this.isShow).fontSize(18).fontColor(Color.Red)
      Row() {
        Button('Click')
          .onClick(() => {
            this.isShow = true;
          })
          .width(100)
          .fontSize(20)
          .margin(10)
      }
    }.width('100%')
  }
}
```

**使用规则**

*   当前!!双向绑定支持基础类型变量，当该变量使用@State等状态管理V1装饰器装饰，或者@Local等状态管理V2装饰器装饰时，变量值的变化会触发UI刷新。
    
    | 属性 | 支持的参数 | 起始API版本 |
    | --- | --- | --- |
    | bindMenu | isShow | 18 |
    | bindContextMenu | isShown | 18 |
    | bindPopup | show | 18 |
    | TextInput | text | 18 |
    | TextArea | text | 18 |
    | Search | value | 18 |
    | BindSheet | isShow | 18 |
    | BindContentCover | isShow | 18 |
    | SideBarContainer | sideBarWidth | 18 |
    | Navigation | navBarWidth | 18 |
    | Toggle | isOn | 18 |
    | Checkbox | select | 18 |
    | CheckboxGroup | selectAll | 18 |
    | Radio | checked | 18 |
    | Rating | rating | 18 |
    | Slider | value | 18 |
    | Select | selected | 18 |
    | Select | value | 18 |
    | MenuItem | selected | 18 |