amis2/docs/zh-CN/concepts/linkage.md
2021-02-07 14:39:46 +08:00

12 KiB
Executable File
Raw Blame History

title description type group menuName icon order
联动 0 💡 概念 联动 14

上一节我们介绍了表达式的概念,而表达式应用最多的场景,是实现页面的联动效果。

基本联动

元素的联动是页面开发中很常见的功能之一,类似于:

  • 某个条件下显示或隐藏某个组件
  • 某个条件下请求接口
  • 某个条件下轮询接口停止轮询
  • 等等...

联动配置项一般都是 表达式

组件配置联动

控制组件的显隐,表单项的禁用状态等,看下面这个例子:

{
    "type": "form",
    "controls": [
        {
            "type": "radios",
            "name": "foo",
            "label": false,
            "options": [
                {
                    "label": "类型1",
                    "value": 1
                },
                {
                    "label": "类型2",
                    "value": 2
                }
            ]
        },
        {
            "type": "text",
            "name": "text1",
            "label": false,
            "placeholder": "选中 类型1 时可见",
            "visibleOn": "this.foo == 1"
        },
        {
            "type": "text",
            "name": "text2",
            "label": false,
            "placeholder": "选中 类型2 时不可点",
            "disabledOn": "this.foo == 2"
        }
    ]
}

上面实例主要为一个表单,表单内有三个组件:一个radio, 两个text,通过配置联动配置项,实现下面联动效果:

  1. 只要当radio选中类型1时,才会显示text1
  2. radio选中类型2时,text2将会变为禁用状态

注意:

在表单项联动中,为了方便数据的读取,赋值后或者修改过的表单项,通过隐藏后,并不会在当前数据域中删除掉该字段值,因此默认提交的时候可能仍然会带上已隐藏表单项的值

如果想要在提交时去掉某个隐藏的字段,可以通过 数据映射 配置自定义数据体

接口联动

基本使用

接口联动是另外一种很常见的场景,查看下面这个例子:

{
    "title": "",
    "type": "form",
    "mode": "horizontal",
    "controls": [
      {
        "label": "选项1",
        "type": "radios",
        "name": "a",
        "inline": true,
        "options": [
          {
            "label": "选项A",
            "value": 1
          },
          {
            "label": "选项B",
            "value": 2
          },
          {
            "label": "选项C",
            "value": 3
          }
        ]
      },
      {
        "label": "选项2",
        "type": "select",
        "size": "sm",
        "name": "b",
        "source": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/options/level2?a=${a}",
        "description": "切换<code>选项1</code>的值,会触发<code>选项2</code>的<code>source</code> 接口重新拉取"
      }
    ],
    "actions": []
}

上面例子我们实现了这个逻辑:每次选择选项1的时候,会触发选项2source配置的接口重新请求,并返回不同的下拉选项。

是如何做到的?

实际上,所有初始化接口链接上使用数据映射获取参数的形式时,例如下面的query=${query},在当前数据域中,所引用的变量值(即 query发生变化时,自动重新请求该接口。

{
  "initApi": "/api/initData?query=${query}"
}

tip:

触发所引用变量值发生变化的方式有以下几种:

  1. 通过对表单项的修改,可以更改表单项name属性值所配置变量的值;
  2. 通过组件间联动,将其他组件的值发送到目标组件,进行数据域的更新,从而触发联动效果

接口联动一般只适用于初始化接口,例如:

  • form组件中的initApi
  • select组件中的source选项源接口url, data只能用于主动联动;
  • service组件中的apischemaApi
  • crud组件中的apicrud 默认是跟地址栏联动,如果要做请关闭同步地址栏 syncLocation: false
  • 等等...

配置请求条件

默认在变量变化时,总是会去请求联动的接口,你也可以配置请求条件,当只有当前数据域中某个值符合特定条件才去请求该接口。

{
    "title": "",
    "type": "form",
    "mode": "horizontal",
    "controls": [
      {
        "label": "选项1",
        "type": "radios",
        "name": "a",
        "inline": true,
        "options": [
          {
            "label": "选项A",
            "value": 1
          },
          {
            "label": "选项B",
            "value": 2
          },
          {
            "label": "选项C",
            "value": 3
          }
        ]
      },
      {
        "label": "选项2",
        "type": "select",
        "size": "sm",
        "name": "b",
        "source": {
            "method": "get",
            "url": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/options/level2?a=${a}",
            "sendOn": "this.a === 2"
        },
        "description": "只有<code>选项1</code>选择<code>B</code>的时候,才触发<code>选项2</code>的<code>source</code>接口重新拉取"
      }
    ],
    "actions": []
}

更多用法,见:Api-配置请求条件

主动触发

上面示例有个问题,就是数据一旦变化就会出发重新拉取,而输入框的频繁变化值会导致频繁的拉取?没关系,也可以配置主动拉取如:

{
    "type": "form",
    "name": "my_form",
    "controls": [
      {
        "type": "text",
        "name": "keyword",
        "addOn": {
          "label": "搜索",
          "type": "button",
          "actionType": "reload",
          "target": "my_form.select"
        }
      },
      {
        "type": "select",
        "name": "select",
        "label": "Select",
        "source": {
          "method": "get",
          "url": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/getOptions?waitSeconds=1",
          "data": {
            "a": "${keyword}"
          }
        }
      }
    ]
}
  1. 通过api对象形式,将获取变量值配置到data请求体中。
  2. 配置搜索按钮,并配置该行为是刷新目标组件,并配置目标组件target
  3. 这样我们只有在点击搜索按钮的时候,才会将keyword值发送给select组件,重新拉取选项

其他联动

还有一些组件特有的联动效果,例如 form 的 disabledOncrud 中的 itemDraggableOn 等等,可以参考相应的组件文档。

组件间联动

联动很可能会出现跨组件的形式,思考下面这种场景:

有一个表单form组件,还有一个列表组件crud,我们想要把form提交的数据,可以用作crud的查询条件,并请求crud的接口,由于formcrud位于同一层级,因此没法使用数据链的方式进行取值。

[
    {
      "title": "查询条件",
      "type": "form",
      "controls": [
        {
          "type": "text",
          "name": "keywords",
          "label": "关键字:"
        }
      ],
      "submitText": "搜索"
    },
    {
      "type": "crud",
      "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/sample",
      "columns": [
            {
                "name": "id",
                "label": "ID"
            },
            {
                "name": "engine",
                "label": "Rendering engine"
            },
            {
                "name": "browser",
                "label": "Browser"
            },
            {
                "name": "platform",
                "label": "Platform(s)"
            },
            {
                "name": "version",
                "label": "Engine version"
            }
        ]
    }
]

现在更改配置如下:

[
    {
      "title": "查询条件",
      "type": "form",
      "target": "my_crud",
      "controls": [
        {
          "type": "text",
          "name": "keywords",
          "label": "关键字:"
        }
      ],
      "submitText": "搜索"
    },
    {
      "type": "crud",
      "name": "my_crud",
      "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/sample",
      "columns": [
            {
                "name": "id",
                "label": "ID"
            },
            {
                "name": "engine",
                "label": "Rendering engine"
            },
            {
                "name": "browser",
                "label": "Browser"
            },
            {
                "name": "platform",
                "label": "Platform(s)"
            },
            {
                "name": "version",
                "label": "Engine version"
            }
        ]
    }
]

我们进行两个调整:

  1. crud组件设置了name属性为my_crud
  2. form组件配置了target属性为crudnamemy_crud

更改配置后,提交表单时,如果有配置提交接口,会先请求提交,之后 amis 会寻找target所配置的目标组件,把form中所提交的数据,发送给该目标组件中,并将该数据合并到目标组件的数据域中,并触发目标组件的刷新操作,对于 CRUD 组件来说,刷新即重新拉取数据接口。

当然,crud组件内置已经支持此功能,你只需要配置crud中的filter属性,就可以实现上面的效果,更多内容查看 crud -> filter 文档。

我们再来一个例子,这次我们实现 两个 form 之间的联动

发送指定数据

target属性支持通过配置参数来发送指定数据,例如:"target" :"xxx?a=${a}&b=${b}",这样就会把当前数据域中的a变量和b变量发送给目标组件

[
  {
    "type": "form",
    "title": "form1",
    "mode": "horizontal",
    "api": "/api/mock2/form/saveForm",
    "controls": [
      {
        "label": "Name",
        "type": "text",
        "name": "name"
      },

      {
        "label": "Email",
        "type": "text",
        "name": "email"
      },

      {
        "label": "Company",
        "type": "text",
        "name": "company"
      }
    ],
    "actions": [
      {
        "type": "action",
        "actionType": "reload",
        "label": "发送到 form2",
        "target": "form2?name=${name}&email=${email}"
      }
    ]
  },
  {
    "type": "form",
    "title": "form2",
    "name": "form2",
    "mode": "horizontal",
    "api": "/api/mock2/form/saveForm",
    "controls": [
      {
        "label": "MyName",
        "type": "text",
        "name": "name"
      },

      {
        "label": "MyEmail",
        "type": "text",
        "name": "email"
      },

      {
        "label": "Company",
        "type": "text",
        "name": "company"
      }
    ]
  }
]

上例中我们给按钮上配置了"target": "form2?name=${name}&email=${email}",可以把当前数据链中的name变量和email变量发送给form2

配置多个目标

target支持配置多个目标组件 name用逗号隔开例如

{
  "type": "action",
  "actionType": "reload",
  "label": "刷新目标组件",
  "target": "target1,target2"
}

上例中点击按钮会刷新target1target2组件。

事实上,组件间联动也可以实现上述任意的 基本联动效果(显隐联动、接口联动等其他联动)。