13 KiB
Executable File
title | description | type | group | menuName | icon | order |
---|---|---|---|---|---|---|
联动 | 0 | 💡 概念 | 联动 | 14 |
上一节我们介绍了表达式的概念,而表达式应用最多的场景,是实现页面的联动效果。
基本联动
元素的联动是页面开发中很常见的功能之一,类似于:
- 某个条件下显示或隐藏某个组件
- 某个条件下请求接口
- 某个条件下轮询接口停止轮询
- 等等...
联动配置项一般都是 表达式
组件配置联动
控制组件的显隐,表单项的禁用状态等,看下面这个例子:
{
"type": "form",
"body": [
{
"type": "radios",
"name": "foo",
"label": false,
"options": [
{
"label": "类型1",
"value": 1
},
{
"label": "类型2",
"value": 2
}
]
},
{
"type": "input-text",
"name": "text1",
"label": false,
"placeholder": "选中 类型1 时可见",
"visibleOn": "${foo == 1}"
},
{
"type": "input-text",
"name": "text2",
"label": false,
"placeholder": "选中 类型2 时不可点",
"disabledOn": "${foo == 2}"
}
]
}
上面实例主要为一个表单,表单内有三个组件:一个radio
, 两个text
,通过配置联动配置项,实现下面联动效果:
- 只要当
radio
选中类型1
时,才会显示text1
; - 当
radio
选中类型2
时,text2
将会变为禁用状态
注意:
在表单项联动中,为了方便数据的读取,赋值后或者修改过的表单项,通过隐藏后,并不会在当前数据域中删除掉该字段值,因此默认提交的时候可能仍然会带上已隐藏表单项的值。
如果想要在提交时去掉某个隐藏的字段,可以通过添加 clearValueOnHidden 属性实现。
接口联动
基本使用
接口联动是另外一种很常见的场景,查看下面这个例子:
{
"title": "",
"type": "form",
"mode": "horizontal",
"body": [
{
"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": "/api/mock2/options/level2?a=${a}",
"description": "切换<code>选项1</code>的值,会触发<code>选项2</code>的<code>source</code> 接口重新拉取"
}
],
"actions": []
}
上面例子我们实现了这个逻辑:每次选择选项1
的时候,会触发选项2
的source
配置的接口重新请求,并返回不同的下拉选项。
是如何做到的?
实际上,所有初始化接口链接上使用数据映射获取参数的形式时,例如下面的query=${query}
,在当前数据域中,所引用的变量值(即 query)发生变化时,自动重新请求该接口。
{
"initApi": "/api/initData?query=${query}"
}
tip:
触发所引用变量值发生变化的方式有以下几种:
- 通过对表单项的修改,可以更改表单项
name
属性值所配置变量的值;- 通过组件间联动,将其他组件的值发送到目标组件,进行数据域的更新,从而触发联动效果
接口联动一般只适用于初始化接口,例如:
form
组件中的initApi
;select
组件中的source
选项源接口url
,data
只能用于主动联动;service
组件中的api
和schemaApi
;crud
组件中的api
;(crud 默认是跟地址栏联动,如果要做请关闭同步地址栏 syncLocation: false)- 等等...
如果 api 地址中有变量,比如
/api/mock2/sample/${id}
,amis 就不会自动加上分页参数,需要自己加上,改成/api/mock2/sample/${id}?page=${page}&perPage=${perPage}
配置请求条件
默认在变量变化时,总是会去请求联动的接口,你也可以配置请求条件,当只有当前数据域中某个值符合特定条件才去请求该接口。
{
"title": "",
"type": "form",
"mode": "horizontal",
"body": [
{
"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": "/api/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",
"body": [
{
"type": "input-text",
"name": "keyword",
"addOn": {
"label": "搜索",
"type": "button",
"actionType": "reload",
"target": "my_form.select"
}
},
{
"type": "select",
"name": "select",
"label": "Select",
"source": {
"method": "get",
"url": "/api/mock2/form/getOptions?waitSeconds=1",
"data": {
"a": "${keyword}"
}
}
}
]
}
- 通过
api
对象形式,将获取变量值配置到data
请求体中。 - 配置搜索按钮,并配置该行为是刷新目标组件,并配置目标组件
target
- 这样我们只有在点击搜索按钮的时候,才会将
keyword
值发送给select
组件,重新拉取选项
表单提交返回数据
表单提交后会将返回结果合并到当前表单数据域,因此可以基于它实现提交按钮后显示结果,比如
{
"type": "form",
"api": "/api/mock2/form/saveForm",
"title": "查询用户 ID",
"body": [
{
"type": "input-group",
"name": "input-group",
"body": [
{
"type": "input-text",
"name": "name",
"label": "姓名"
},
{
"type": "submit",
"label": "查询",
"level": "primary"
}
]
},
{
"type": "static",
"name": "id",
"visibleOn": "typeof data.id !== 'undefined'",
"label": "返回 ID"
}
],
"actions": []
}
上面的例子首先用 "actions": []
将表单默认的提交按钮去掉,然后在 input-group
里放一个 submit
类型的按钮来替代表单查询。
这个查询结果返回类似如下的数据
{
"status": 0,
"msg": "保存成功",
"data": {
"id": 1
}
}
amis 会将返回的 data
写入表单数据域,因此下面的 static
组件就能显示了。
其他联动
还有一些组件特有的联动效果,例如 form 的 disabledOn,crud 中的 itemDraggableOn 等等,可以参考相应的组件文档。
组件间联动
联动很可能会出现跨组件的形式,思考下面这种场景:
有一个表单form
组件,还有一个列表组件crud
,我们想要把form
提交的数据,可以用作crud
的查询条件,并请求crud
的接口,由于form
和crud
位于同一层级,因此没法使用数据链的方式进行取值。
[
{
"title": "查询条件",
"type": "form",
"body": [
{
"type": "input-text",
"name": "keywords",
"label": "关键字:"
}
],
"submitText": "搜索"
},
{
"type": "crud",
"api": "/api/mock2/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",
"body": [
{
"type": "input-text",
"name": "keywords",
"label": "关键字:"
}
],
"submitText": "搜索"
},
{
"type": "crud",
"name": "my_crud",
"api": "/api/mock2/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"
}
]
}
]
我们进行两个调整:
- 为
crud
组件设置了name
属性为my_crud
- 为
form
组件配置了target
属性为crud
的name
:my_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",
"body": [
{
"label": "Name",
"type": "input-text",
"name": "name"
},
{
"label": "Email",
"type": "input-text",
"name": "email"
},
{
"label": "Company",
"type": "input-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",
"body": [
{
"label": "MyName",
"type": "input-text",
"name": "name"
},
{
"label": "MyEmail",
"type": "input-text",
"name": "email"
},
{
"label": "Company",
"type": "input-text",
"name": "company"
}
]
}
]
上例中我们给按钮上配置了"target": "form2?name=${name}&email=${email}"
,可以把当前数据链中的name
变量和email
变量发送给form2
配置多个目标
target
支持配置多个目标组件 name,用逗号隔开,例如:
{
"type": "action",
"actionType": "reload",
"label": "刷新目标组件",
"target": "target1,target2"
}
上例中点击按钮会刷新target1
和target2
组件。
事实上,组件间联动也可以实现上述任意的 基本联动效果(显隐联动、接口联动等其他联动)。