diff --git a/fis-conf.js b/fis-conf.js index 4fff5754..8bb27c1b 100644 --- a/fis-conf.js +++ b/fis-conf.js @@ -243,9 +243,13 @@ if (fis.project.currentMedia() === 'publish') { return contents; } - return contents.replace(/(\\?(?:'|"))\/api\/mock2?\//g, function(_, qutoa) { - return qutoa + 'https://houtai.baidu.com/api/mock2/'; - }); + return contents + .replace(/(\\?(?:'|"))((?:get|post|delete|put)\:)?\/api\/mock2?/ig, function(_, qutoa, method) { + return qutoa + (method || '') + 'https://houtai.baidu.com/api/mock2'; + }) + .replace(/(\\?(?:'|"))((?:get|post|delete|put)\:)?\/api\/sample/ig, function(_, qutoa, method) { + return qutoa + (method || '') + 'https://houtai.baidu.com/api/sample'; + }); } }) diff --git a/gh-pages/docs/advanced.js b/gh-pages/docs/advanced.js index b385793c..51d6817f 100644 --- a/gh-pages/docs/advanced.js +++ b/gh-pages/docs/advanced.js @@ -3,7 +3,7 @@ define('docs/advanced.md', function(require, exports, module) { module.exports = { "title": "高级用法", "shortname": "advanced", - "html": "
在开始阅读之前,希望你已经阅读 快速开始文档 。
\n配置中很多地方都可以用变量如: tpl 类型的渲染器、API 中的 Url、FormItem 中的 source 配置、visibleOn、disabledOn 以及 Form 中的 redirect
配置等等。
那么都有哪些数据可以用?这取决于在哪个容器,关于容器中的数据说明如下:
\npage
等价于全局变量,因为顶级渲染器就是它,所以下面的所有组件都能用到这个里面的数据。amisPage
当前页面的数据信息,包含标题,id,key 之类的信息。amisUser
当前用户信息,包含邮箱和用户名信息。params 中的数据
如果地址栏中也携带了参数,也会 merge 到该层的数据中。initApi 返回的数据
如果 page 设置了 initApi
那么初始化的时候会从 API 中拉取数据,拉取到的数据可以用于整个页面。crud
api
返回的数据,crud 的 api 除了可以返回 rows
和 count
数据外,其他的数据会被 merge 到数据中,供容器使用。form
initApi
返回的数据。name
值获取。formItem
表单项中,所在的表单中的数据都能用。
wizard
同 formdialog
dialog 由 button 触发弹出,携带的数据根据按钮所在的位置来决定。servcie
api
, api
返回的数据可以用。取值过程,也跟 JS 作用域中取值一样,当前作用域中有,则直接返回当前作用域中,如果没有当前作用域没有,会一直往上找,直到找到了为止。如果存在同名变量,则返回就近作用域中数据。
\n需要注意的是,要取到值一定是在自己所在的作用域,或者上级作用域里面,同级的是取不到的,如果需要怎么办?可以往下看联动,比如:FormA 的数据发送给 formB, 另外一种方式,可以把接口拉取换到父级组件去操作,没有可拉取数据的组件,就一起包在一个 service 控件里面。
\n主要通过 visibleOn
、hiddenOn
和 disabledOn
来配置。
比如 select 中 options 可能根据某个值不同而不同。
\n\n他们是怎么关联的呢?注意看 select 的 source 配置 "/api/mock/getOptions?waitSeconds=1&type=$foo"
这里用了变量 $foo
这个 foo 正好是第一个表单的 name 值。只要这个值发生变化,source 就会重新获取一次。
这里有个问题就是,数据一旦变化就会出发重新拉取,如果是输入框岂不是拉取得很频繁?没关系,也可以主动拉取如:
\n\n注意,source 中的传参是通过 source 中的 data 关联的,不能写在 source 的 url 中,因为如果写了,就会自动监控值的变化而自动刷新,写在 data 里面关联则不会。如果对 source 中的配置规则不了解,请前往 API 说明
\n另外注意 button 的 target 值,正好是这个 form 的 name 值 lidong
的 formItem 的 name 值 select
。当按钮的对象是一个 formItem 时,会出发 formItem 的数据重新拉取。
Form 和 CRUD, CRUD 有个 filter 配置项,里面可以配置表单项,当他提交时 CRUD 自动就会携带接受到的表单数据然后重新获取数据。有个限制,就是 CRUD 和 filter 必须放在一起,不能分开,实际上完全可以分开,只要 Form 的 target 是 CRUD 的 name 值即可。
\n\nForm 的 target 还可以是另外一个 Form,当 A Form 把自己的数据提交给 B Form 时,A 的数据会被合并到 B Form 中,同时,B Form 会再次初始化,如:拉取 initApi, 重新拉取 formItem 上的 source 等等。 比如用户管理中的加入用户操作就是用这种方式实现的。
\n\n", + "html": "在开始阅读之前,希望你已经阅读 快速开始文档 。
\n配置中很多地方都可以用变量如: tpl 类型的渲染器、API 中的 Url、FormItem 中的 source 配置、visibleOn、disabledOn 以及 Form 中的 redirect
配置等等。
那么都有哪些数据可以用?这取决于在哪个容器,关于容器中的数据说明如下:
\npage
等价于全局变量,因为顶级渲染器就是它,所以下面的所有组件都能用到这个里面的数据。amisPage
当前页面的数据信息,包含标题,id,key 之类的信息。amisUser
当前用户信息,包含邮箱和用户名信息。params 中的数据
如果地址栏中也携带了参数,也会 merge 到该层的数据中。initApi 返回的数据
如果 page 设置了 initApi
那么初始化的时候会从 API 中拉取数据,拉取到的数据可以用于整个页面。crud
api
返回的数据,crud 的 api 除了可以返回 rows
和 count
数据外,其他的数据会被 merge 到数据中,供容器使用。form
initApi
返回的数据。name
值获取。formItem
表单项中,所在的表单中的数据都能用。
wizard
同 formdialog
dialog 由 button 触发弹出,携带的数据根据按钮所在的位置来决定。servcie
api
, api
返回的数据可以用。取值过程,也跟 JS 作用域中取值一样,当前作用域中有,则直接返回当前作用域中,如果没有当前作用域没有,会一直往上找,直到找到了为止。如果存在同名变量,则返回就近作用域中数据。
\n需要注意的是,要取到值一定是在自己所在的作用域,或者上级作用域里面,同级的是取不到的,如果需要怎么办?可以往下看联动,比如:FormA 的数据发送给 formB, 另外一种方式,可以把接口拉取换到父级组件去操作,没有可拉取数据的组件,就一起包在一个 service 控件里面。
\n主要通过 visibleOn
、hiddenOn
和 disabledOn
来配置。
比如 select 中 options 可能根据某个值不同而不同。
\n\n他们是怎么关联的呢?注意看 select 的 source 配置 "/api/mock/getOptions?waitSeconds=1&type=$foo"
这里用了变量 $foo
这个 foo 正好是第一个表单的 name 值。只要这个值发生变化,source 就会重新获取一次。
这里有个问题就是,数据一旦变化就会出发重新拉取,如果是输入框岂不是拉取得很频繁?没关系,也可以主动拉取如:
\n\n注意,source 中的传参是通过 source 中的 data 关联的,不能写在 source 的 url 中,因为如果写了,就会自动监控值的变化而自动刷新,写在 data 里面关联则不会。如果对 source 中的配置规则不了解,请前往 API 说明
\n另外注意 button 的 target 值,正好是这个 form 的 name 值 lidong
的 formItem 的 name 值 select
。当按钮的对象是一个 formItem 时,会出发 formItem 的数据重新拉取。
Form 和 CRUD, CRUD 有个 filter 配置项,里面可以配置表单项,当他提交时 CRUD 自动就会携带接受到的表单数据然后重新获取数据。有个限制,就是 CRUD 和 filter 必须放在一起,不能分开,实际上完全可以分开,只要 Form 的 target 是 CRUD 的 name 值即可。
\n\nForm 的 target 还可以是另外一个 Form,当 A Form 把自己的数据提交给 B Form 时,A 的数据会被合并到 B Form 中,同时,B Form 会再次初始化,如:拉取 initApi, 重新拉取 formItem 上的 source 等等。 比如用户管理中的加入用户操作就是用这种方式实现的。
\n\n", "toc": { "label": "目录", "type": "toc", diff --git a/gh-pages/docs/dev.js b/gh-pages/docs/dev.js index 7e7fc0fa..aa07d81d 100644 --- a/gh-pages/docs/dev.js +++ b/gh-pages/docs/dev.js @@ -1,47 +1,48 @@ define('docs/dev.md', function(require, exports, module) { - module.exports = { - title: '自定义组件', - shortname: 'dev', - html: - '自定义组件主要分两类。表单类和非表单类。
\n即表单类,它主要用来扩充表单项。先看个例子。
\nimport * as React from \'react\';\nimport {FormItem} from \'amis\';\nimport * as cx from \'classnames\';\n\n@FormItem({\n type: \'custom-checkbox\',\n})\nexport default class CustomCheckbox extends React.PureComponent {\n toggle = () => {\n const {value, onChange} = this.props;\n\n onChange(!value);\n };\n\n render() {\n const {value} = this.props;\n const checked = !!value;\n\n return (\n <div>\n <a\n className={cx(\'btn btn-default\', {\n \'btn-success\': checked,\n })}\n onClick={this.toggle}\n >\n {checked ? \'已勾选\' : \'请勾选\'}\n </a>\n <div className="inline m-l-xs">{checked ? \'已勾选\' : \'请勾选\'}</div>\n </div>\n );\n }\n}\n
\n有了这个代码后,页面配置 form 的 controls 里面就可以通过这样的配置启动了。
\n{\n // 其他信息省略了。。\n type: \'form\',\n controls: [\n {\n type: \'custom-checkbox\',\n name: \'变量名\',\n label: \'自定义组件。\'\n }\n ]\n}\n
\n表单项开发主要关心两件事。
\n已勾选
,否则显示请勾选
。至于其他功能如:label/description 的展示、表单验证功能、表单布局(常规、左右或者内联)等等,只要是通过 FormItem 注册进去的都无需自己实现。
\n非表单类的组件自定义,主要通过 Renderer
实现。在开始阅读之前,请先阅读 AMis 工作原理。
import * as React from \'react\';\nimport {Renderer} from \'amis\';\n\n@Renderer({\n test: /(^|\\/)my\\-renderer$/,\n})\nclass CustomRenderer extends React.Component {\n render() {\n const {tip, body, render} = this.props;\n\n return (\n <div>\n <p>这是自定义组件:{tip}</p>\n {body ? (\n <div className="container">\n {render(\'body\', body, {\n // 这里的信息会作为 props 传递给子组件,一般情况下都不需要这个\n })}\n </div>\n ) : null}\n </div>\n );\n }\n}\n
\n这里注册一个 React 组件,当节点的 path 信息是 my-renderer
结尾时,交给当前组件来完成渲染。
请注意 this.props
中的 render
方法,它用来实现容器功能,通过它可以让使用者动态的配置其他渲染模型。
目前主要提供以下工具。
\nimport {fetch} from \'amis/utils\';\n
\n用来做 ajax 请求。参数说明
\napi
字符串或者 api 对象,如: {url: 'http://www.baidu.com', method: 'get'}, api 地址支持变量。data
数据体返回一个 Promise。
\n如:
\nimport {fetch} from \'amis/utils\';\n\nfetch(\'http://www.baidu.com/api/xxx?a=${a}&b=${b}\', {\n a: \'aa\',\n b: \'bb\',\n}).then(function(result) {\n console.log(result);\n});\n
\nimport {filter} from \'amis/utils\';\n
\n主要用来做字符替换,如:
\nimport {filter} from \'amis/utils\';\n\nfilter(\'blabla?a={a}\', {a: 123}); // => \'blabla?a=123\'\n
\n',
- toc: {
- label: '目录',
- type: 'toc',
- children: [
- {
- label: 'FormItem',
- fragment: 'formitem',
- fullPath: '#formitem',
- level: 3,
- },
- {
- label: 'Renderer',
- fragment: 'renderer',
- fullPath: '#renderer',
- level: 3,
- },
- {
- label: '工具',
- fragment: '%E5%B7%A5%E5%85%B7',
- fullPath: '#%E5%B7%A5%E5%85%B7',
- level: 2,
- children: [
- {
- label: 'fetch',
- fragment: 'fetch',
- fullPath: '#fetch',
- level: 3,
- },
- {
- label: 'filter',
- fragment: 'filter',
- fullPath: '#filter',
- level: 3,
- },
- ],
- },
- ],
- level: 0,
+
+ module.exports = {
+ "title": "自定义组件",
+ "shortname": "dev",
+ "html": "自定义组件主要分两类。表单类和非表单类。
\n即表单类,它主要用来扩充表单项。先看个例子。
\nimport * as React from 'react';\nimport {FormItem} from 'amis';\nimport * as cx from 'classnames';\n\n@FormItem({\n type: 'custom-checkbox',\n})\nexport default class CustomCheckbox extends React.PureComponent {\n toggle = () => {\n const {value, onChange} = this.props;\n\n onChange(!value);\n };\n\n render() {\n const {value} = this.props;\n const checked = !!value;\n\n return (\n <div>\n <a\n className={cx('btn btn-default', {\n 'btn-success': checked,\n })}\n onClick={this.toggle}\n >\n {checked ? '已勾选' : '请勾选'}\n </a>\n <div className=\"inline m-l-xs\">{checked ? '已勾选' : '请勾选'}</div>\n </div>\n );\n }\n}\n
\n有了这个代码后,页面配置 form 的 controls 里面就可以通过这样的配置启动了。
\n{\n // 其他信息省略了。。\n type: 'form',\n controls: [\n {\n type: 'custom-checkbox',\n name: '变量名',\n label: '自定义组件。'\n }\n ]\n}\n
\n表单项开发主要关心两件事。
\n已勾选
,否则显示请勾选
。至于其他功能如:label/description 的展示、表单验证功能、表单布局(常规、左右或者内联)等等,只要是通过 FormItem 注册进去的都无需自己实现。
\n非表单类的组件自定义,主要通过 Renderer
实现。在开始阅读之前,请先阅读 AMis 工作原理。
import * as React from 'react';\nimport {Renderer} from 'amis';\n\n ({\n test: /(^|\\/)my\\-renderer$/,\n})\nclass CustomRenderer extends React.Component {\n render() {\n const {tip, body, render} = this.props;\n\n return (\n <div>\n <p>这是自定义组件:{tip}</p>\n {body ? (\n <div className=\"container\">\n {render('body', body, {\n // 这里的信息会作为 props 传递给子组件,一般情况下都不需要这个\n })}\n </div>\n ) : null}\n </div>\n );\n }\n}\n
\n这里注册一个 React 组件,当节点的 path 信息是 my-renderer
结尾时,交给当前组件来完成渲染。
请注意 this.props
中的 render
方法,它用来实现容器功能,通过它可以让使用者动态的配置其他渲染模型。
目前主要提供以下工具。
\nimport {fetch} from 'amis/utils';\n
\n用来做 ajax 请求。参数说明
\napi
字符串或者 api 对象,如: {url: 'http://www.baidu.com', method: 'get'}, api 地址支持变量。data
数据体返回一个 Promise。
\n如:
\nimport {fetch} from 'amis/utils';\n\nfetch('http://www.baidu.com/api/xxx?a=${a}&b=${b}', {\n a: 'aa',\n b: 'bb',\n}).then(function(result) {\n console.log(result);\n});\n
\nimport {filter} from 'amis/utils';\n
\n主要用来做字符替换,如:
\nimport {filter} from 'amis/utils';\n\nfilter('blabla?a={a}', {a: 123}); // => 'blabla?a=123'\n
\n",
+ "toc": {
+ "label": "目录",
+ "type": "toc",
+ "children": [
+ {
+ "label": "FormItem",
+ "fragment": "formitem",
+ "fullPath": "#formitem",
+ "level": 3
},
- };
+ {
+ "label": "Renderer",
+ "fragment": "renderer",
+ "fullPath": "#renderer",
+ "level": 3
+ },
+ {
+ "label": "工具",
+ "fragment": "%E5%B7%A5%E5%85%B7",
+ "fullPath": "#%E5%B7%A5%E5%85%B7",
+ "level": 2,
+ "children": [
+ {
+ "label": "fetch",
+ "fragment": "fetch",
+ "fullPath": "#fetch",
+ "level": 3
+ },
+ {
+ "label": "filter",
+ "fragment": "filter",
+ "fullPath": "#filter",
+ "level": 3
+ }
+ ]
+ }
+ ],
+ "level": 0
+ }
+ };
+
});
diff --git a/gh-pages/docs/renderers/CRUD-Cards.js b/gh-pages/docs/renderers/CRUD-Cards.js
index 30f45df7..5b1d2fd2 100644
--- a/gh-pages/docs/renderers/CRUD-Cards.js
+++ b/gh-pages/docs/renderers/CRUD-Cards.js
@@ -1,7 +1,7 @@
define('docs/renderers/CRUD-Cards.md', function(require, exports, module) {
module.exports = {
- "html": "请参考Cards
\n\n", + "html": "请参考Cards
\n\n", "toc": { "label": "目录", "type": "toc", diff --git a/gh-pages/docs/renderers/CRUD-List.js b/gh-pages/docs/renderers/CRUD-List.js index 9b637509..63bca962 100644 --- a/gh-pages/docs/renderers/CRUD-List.js +++ b/gh-pages/docs/renderers/CRUD-List.js @@ -1,7 +1,7 @@ define('docs/renderers/CRUD-List.md', function(require, exports, module) { module.exports = { - "html": "请参考List
\n\n", + "html": "请参考List
\n\n", "toc": { "label": "目录", "type": "toc", diff --git a/gh-pages/docs/renderers/CRUD-Table.js b/gh-pages/docs/renderers/CRUD-Table.js index 63467df0..e2e8a9b6 100644 --- a/gh-pages/docs/renderers/CRUD-Table.js +++ b/gh-pages/docs/renderers/CRUD-Table.js @@ -1,7 +1,7 @@ define('docs/renderers/CRUD-Table.md', function(require, exports, module) { module.exports = { - "html": "在 CRUD 中的 Table 主要增加了 Column 里面的以下配置功能,更多参数,请参考Table
\nsortable
开启后可以根据当前列排序(后端排序)。在 CRUD 中的 Table 主要增加了 Column 里面的以下配置功能,更多参数,请参考Table
\nsortable
开启后可以根据当前列排序(后端排序)。卡片集合。
\n属性名 | \n类型 | \n默认值 | \n说明 | \n
---|---|---|---|
type | \nstring | \n\n | "cards" 指定为卡片集合。 | \n
title | \nstring | \n\n | 标题 | \n
source | \nstring | \n${items} | \n数据源, 绑定当前环境变量 | \n
placeholder | \nstring | \n‘暂无数据’ | \n当没数据的时候的文字提示 | \n
className | \nstring | \n\n | 外层 CSS 类名 | \n
headerClassName | \nstring | \namis-grid-header | \n顶部外层 CSS 类名 | \n
footerClassName | \nstring | \namis-grid-footer | \n底部外层 CSS 类名 | \n
itemClassName | \nstring | \ncol-sm-4 col-md-3 | \n卡片 CSS 类名 | \n
card | \nCard | \n\n | 配置卡片信息 | \n
卡片集合。
\n属性名 | \n类型 | \n默认值 | \n说明 | \n
---|---|---|---|
type | \nstring | \n\n | "cards" 指定为卡片集合。 | \n
title | \nstring | \n\n | 标题 | \n
source | \nstring | \n${items} | \n数据源, 绑定当前环境变量 | \n
placeholder | \nstring | \n‘暂无数据’ | \n当没数据的时候的文字提示 | \n
className | \nstring | \n\n | 外层 CSS 类名 | \n
headerClassName | \nstring | \namis-grid-header | \n顶部外层 CSS 类名 | \n
footerClassName | \nstring | \namis-grid-footer | \n底部外层 CSS 类名 | \n
itemClassName | \nstring | \ncol-sm-4 col-md-3 | \n卡片 CSS 类名 | \n
card | \nCard | \n\n | 配置卡片信息 | \n
列表展示。
\n属性名 | \n类型 | \n默认值 | \n说明 | \n
---|---|---|---|
type | \nstring | \n\n | "list" 指定为列表展示。 | \n
title | \nstring | \n\n | 标题 | \n
source | \nstring | \n${items} | \n数据源, 绑定当前环境变量 | \n
placeholder | \nstring | \n‘暂无数据’ | \n当没数据的时候的文字提示 | \n
className | \nstring | \n\n | 外层 CSS 类名 | \n
headerClassName | \nstring | \namis-list-header | \n顶部外层 CSS 类名 | \n
footerClassName | \nstring | \namis-list-footer | \n底部外层 CSS 类名 | \n
listItem | \nArray | \n\n | 配置单条信息 | \n
listItem.title | \nstring | \n\n | 标题,支持模板语法如: \\${xxx} | \n
listItem.titleClassName | \nstring | \nh5 | \n标题 CSS 类名 | \n
listItem.subTitle | \nstring | \n\n | 副标题,支持模板语法如: \\${xxx} | \n
listItem.avatar | \nstring | \n\n | 图片地址,支持模板语法如: \\${xxx} | \n
listItem.avatarClassName | \nstring | \nthumb-sm avatar m-r | \n图片 CSS 类名 | \n
listItem.desc | \nstring | \n\n | 描述,支持模板语法如: \\${xxx} | \n
listItem.body | \nArray 或者 Field | \n\n | 内容容器,主要用来放置 Field | \n
listItem.actions | \nArray Of Button | \n\n | 按钮区域 | \n
列表展示。
\n属性名 | \n类型 | \n默认值 | \n说明 | \n
---|---|---|---|
type | \nstring | \n\n | "list" 指定为列表展示。 | \n
title | \nstring | \n\n | 标题 | \n
source | \nstring | \n${items} | \n数据源, 绑定当前环境变量 | \n
placeholder | \nstring | \n‘暂无数据’ | \n当没数据的时候的文字提示 | \n
className | \nstring | \n\n | 外层 CSS 类名 | \n
headerClassName | \nstring | \namis-list-header | \n顶部外层 CSS 类名 | \n
footerClassName | \nstring | \namis-list-footer | \n底部外层 CSS 类名 | \n
listItem | \nArray | \n\n | 配置单条信息 | \n
listItem.title | \nstring | \n\n | 标题,支持模板语法如: \\${xxx} | \n
listItem.titleClassName | \nstring | \nh5 | \n标题 CSS 类名 | \n
listItem.subTitle | \nstring | \n\n | 副标题,支持模板语法如: \\${xxx} | \n
listItem.avatar | \nstring | \n\n | 图片地址,支持模板语法如: \\${xxx} | \n
listItem.avatarClassName | \nstring | \nthumb-sm avatar m-r | \n图片 CSS 类名 | \n
listItem.desc | \nstring | \n\n | 描述,支持模板语法如: \\${xxx} | \n
listItem.body | \nArray 或者 Field | \n\n | 内容容器,主要用来放置 Field | \n
listItem.actions | \nArray Of Button | \n\n | 按钮区域 | \n
列表选取。可以静态数据,或者通过接口拉取动态数据。
\ntype
请设置成 picker
multiple
是否为多选。options
选项配置,类型为数组,成员格式如下。label
文字value
值source
Api 地址,如果选项不固定,可以通过配置 source
动态拉取。 另外也可以用 $xxxx
来获取当前作用域中的变量。joinValues
默认为 true
value
会通过 delimiter
连接起来,否则直接将以数组的形式提交值。extractValue
默认为 false
, joinValues
设置为false
时生效, 开启后将选中的选项 value 的值封装为数组,作为当前表单项的值。delimiter
默认为 ,
modalMode
设置 dialog
或者 drawer
,用来配置弹出方式。pickerSchema
默认为 {mode: 'list', listItem: {title: '${label}'}}
, 即用 List 类型的渲染,来展示列表信息。更多的玩法请参考 CRUD 的配置。列表选取。可以静态数据,或者通过接口拉取动态数据。
\ntype
请设置成 picker
multiple
是否为多选。options
选项配置,类型为数组,成员格式如下。label
文字value
值source
Api 地址,如果选项不固定,可以通过配置 source
动态拉取。 另外也可以用 $xxxx
来获取当前作用域中的变量。joinValues
默认为 true
value
会通过 delimiter
连接起来,否则直接将以数组的形式提交值。extractValue
默认为 false
, joinValues
设置为false
时生效, 开启后将选中的选项 value 的值封装为数组,作为当前表单项的值。delimiter
默认为 ,
modalMode
设置 dialog
或者 drawer
,用来配置弹出方式。pickerSchema
默认为 {mode: 'list', listItem: {title: '${label}'}}
, 即用 List 类型的渲染,来展示列表信息。更多的玩法请参考 CRUD 的配置。表格展示。
\n属性名 | \n类型 | \n默认值 | \n说明 | \n
---|---|---|---|
type | \nstring | \n\n | "table" 指定为 table 渲染器 | \n
title | \nstring | \n\n | 标题 | \n
source | \nstring | \n${items} | \n数据源, 绑定当前环境变量 | \n
affixHeader | \nboolean | \ntrue | \n是否固定表头 | \n
columnsTogglable | \nauto 或者 boolean | \nauto | \n展示列显示开关, 自动即:列数量大于或等于 5 个时自动开启 | \n
placeholder | \nstring | \n‘暂无数据’ | \n当没数据的时候的文字提示 | \n
className | \nstring | \npanel-default | \n外层 CSS 类名 | \n
tableClassName | \nstring | \ntable-db table-striped | \n表格 CSS 类名 | \n
headerClassName | \nstring | \nAction.md-table-header | \n顶部外层 CSS 类名 | \n
footerClassName | \nstring | \nAction.md-table-footer | \n底部外层 CSS 类名 | \n
toolbarClassName | \nstring | \nAction.md-table-toolbar | \n工具栏 CSS 类名 | \n
columns | \nArray of Column | \n\n | 用来设置列信息 | \n
表格展示。
\n属性名 | \n类型 | \n默认值 | \n说明 | \n
---|---|---|---|
type | \nstring | \n\n | "table" 指定为 table 渲染器 | \n
title | \nstring | \n\n | 标题 | \n
source | \nstring | \n${items} | \n数据源, 绑定当前环境变量 | \n
affixHeader | \nboolean | \ntrue | \n是否固定表头 | \n
columnsTogglable | \nauto 或者 boolean | \nauto | \n展示列显示开关, 自动即:列数量大于或等于 5 个时自动开启 | \n
placeholder | \nstring | \n‘暂无数据’ | \n当没数据的时候的文字提示 | \n
className | \nstring | \npanel-default | \n外层 CSS 类名 | \n
tableClassName | \nstring | \ntable-db table-striped | \n表格 CSS 类名 | \n
headerClassName | \nstring | \nAction.md-table-header | \n顶部外层 CSS 类名 | \n
footerClassName | \nstring | \nAction.md-table-footer | \n底部外层 CSS 类名 | \n
toolbarClassName | \nstring | \nAction.md-table-toolbar | \n工具栏 CSS 类名 | \n
columns | \nArray of Column | \n\n | 用来设置列信息 | \n
属性名 | \n类型 | \n默认值 | \n说明 | \n
---|---|---|---|
type | \nstring | \n"tabs" | \n指定为 Tabs 渲染器 | \n
className | \nstring | \n\n | 外层 Dom 的类名 | \n
tabsClassName | \nstring | \n\n | Tabs Dom 的类名 | \n
tabs | \nArray | \n\n | tabs 内容 | \n
tabs[x].title | \nstring | \n\n | Tab 标题 | \n
tabs[x].icon | \nicon | \n\n | Tab 的图标 | \n
tabs[x].tab | \nContainer | \n\n | 内容区 | \n
tabs[x].hash | \nstring | \n\n | 设置以后将跟 url 的 hash 对应 | \n
tabs[x].reload | \nboolean | \n\n | 设置以后内容每次都会重新渲染,对于 crud 的重新拉取很有用 | \n
tabs[x].className | \nstring | \n"bg-white b-l b-r b-b wrapper-md" | \nTab 区域样式 | \n
Container 不是一个特定的渲染器,而是 AMis 中一个特殊类型,它是以下类型的任何一种。
\nString
字符串,可以包含 html
片段。Object
指定一个渲染器如: {"type": "button", "label": "按钮"}
Array
还可以是一个数组,数组的成员可以就是一个 Container
.示例:
\n{\n "container": "普通一段字符串"\n}\n
\n{\n "container": {\n "type": "button",\n "label": "按钮"\n }\n}\n
\n{\n "container": [\n "普通一段字符串",\n\n {\n "type": "button",\n "label": "按钮"\n },\n\n ["普通一段字符串", "普通一段字符串"]\n ]\n}\n
\nApi 类型可以是字符串或者对象。API 中可以直接设置数据发送结构,注意看示例。
\nString
[<type>:]<url>
<type>
可以是: get
、post
、put
、delete
或者raw
<url>
即 api 地址,支持通过 $key
取变量。如:
\n * `get:http://imis.tieba.baidu.com/yule/list?start=$startTime&end=$endTime`\n * `get:http://imis.tieba.baidu.com/yule/list?$$` 拿所有可用数据。\n * `get:http://imis.tieba.baidu.com/yule/list?data=$$` 拿所有可用数据。\n
Object
url
api 地址method
可以是:get
、post
、put
或者delete
data
数据体headers
头部,配置方式和 data 配置一样,下面不详讲。如果要使用,请前往群组系统配置中,添加允许。如:
\n取某个变量。
\n{\n "url": "http://imis.tieba.baidu.com/yule/list",\n "method": "post",\n "data": {\n "start": "$startTime"\n }\n}\n
\n直接将所有可用数据映射给 all 变量。
\n{\n "url": "http://imis.tieba.baidu.com/yule/list",\n "method": "post",\n "data": {\n "all": "$$"\n }\n}\n
\n正常如果指定了 data,则只会发送 data 指定的数据了,如果想要保留原有数据,只定制修改一部分。
\n{\n "url": "http://imis.tieba.baidu.com/yule/list",\n "method": "post",\n "data": {\n "&": "$$", // 原来的数据先 copy 过来。\n "a": "123",\n "b": "${b}"\n }\n}\n
\n如果目标变量是数组,而发送的数据,有不希望把成员全部发送过去,可以这样配置。
\n{\n "url": "http://imis.tieba.baidu.com/yule/list",\n "method": "post",\n "data": {\n "all": {\n "$rows": {\n "a": "$a",\n "b": "$b"\n }\n }\n }\n}\n
\n如果 \\$rows 的结构为 [{a: 1, b: 2, c: 3, d: 4}, {a: 1, b: 2, c: 3, d: 4}]
, 经过上述映射后,实际发送的数据为 {all: [{a: 1, b:2}, {a: 1, b: 2}]}
注意
\nAMis 所有值为 url 的如: "http://www.baidu.com"
都会被替换成 proxy 代理,如果不希望这么做,请明确指示如: "raw:http://www.baidu.com"
。还有为了安全,AMis 默认只能转发公司内部 API 接口,如果您的接口在外网环境,也请明确指示如:"external:http://www.baidu.com"
配置项中,所有 boolean
类型的配置,都可以用 JS 表达式来配置。所有boolean
配置项,后面加个 On
则是表达式配置方式,可以用 js 语法来根据当前模型中的数据来决定是否启用。\n如:FormItem 中的 disabledOn
、hiddenOn
、visibleOn
、CRUD 中的 itemDraggableOn
等等。
为了能加入权限控制,表达是中允许可以用 acl.can
方法来检测当前用户是否拥有某个权限。\n如: {"disabledOn": "!can('some-resource')"}
。权限能力部分,请前往能力管理,\n权限配置请前往权限配置管理。
Container 不是一个特定的渲染器,而是 AMis 中一个特殊类型,它是以下类型的任何一种。
\nString
字符串,可以包含 html
片段。Object
指定一个渲染器如: {"type": "button", "label": "按钮"}
Array
还可以是一个数组,数组的成员可以就是一个 Container
.示例:
\n{\n \"container\": \"普通一段字符串\"\n}\n
\n{\n \"container\": {\n \"type\": \"button\",\n \"label\": \"按钮\"\n }\n}\n
\n{\n \"container\": [\n \"普通一段字符串\",\n\n {\n \"type\": \"button\",\n \"label\": \"按钮\"\n },\n\n [\"普通一段字符串\", \"普通一段字符串\"]\n ]\n}\n
\nApi 类型可以是字符串或者对象。API 中可以直接设置数据发送结构,注意看示例。
\nString
[<type>:]<url>
<type>
可以是: get
、post
、put
、delete
或者raw
<url>
即 api 地址,支持通过 $key
取变量。如:
\n * `get:http://imis.tieba.baidu.com/yule/list?start=$startTime&end=$endTime`\n * `get:http://imis.tieba.baidu.com/yule/list?$$` 拿所有可用数据。\n * `get:http://imis.tieba.baidu.com/yule/list?data=$$` 拿所有可用数据。\n
Object
url
api 地址method
可以是:get
、post
、put
或者delete
data
数据体headers
头部,配置方式和 data 配置一样,下面不详讲。如果要使用,请前往群组系统配置中,添加允许。如:
\n取某个变量。
\n{\n \"url\": \"http://imis.tieba.baidu.com/yule/list\",\n \"method\": \"post\",\n \"data\": {\n \"start\": \"$startTime\"\n }\n}\n
\n直接将所有可用数据映射给 all 变量。
\n{\n \"url\": \"http://imis.tieba.baidu.com/yule/list\",\n \"method\": \"post\",\n \"data\": {\n \"all\": \"$$\"\n }\n}\n
\n正常如果指定了 data,则只会发送 data 指定的数据了,如果想要保留原有数据,只定制修改一部分。
\n{\n \"url\": \"http://imis.tieba.baidu.com/yule/list\",\n \"method\": \"post\",\n \"data\": {\n \"&\": \"$$\", // 原来的数据先 copy 过来。\n \"a\": \"123\",\n \"b\": \"${b}\"\n }\n}\n
\n如果目标变量是数组,而发送的数据,有不希望把成员全部发送过去,可以这样配置。
\n{\n \"url\": \"http://imis.tieba.baidu.com/yule/list\",\n \"method\": \"post\",\n \"data\": {\n \"all\": {\n \"$rows\": {\n \"a\": \"$a\",\n \"b\": \"$b\"\n }\n }\n }\n}\n
\n如果 \\$rows 的结构为 [{a: 1, b: 2, c: 3, d: 4}, {a: 1, b: 2, c: 3, d: 4}]
, 经过上述映射后,实际发送的数据为 {all: [{a: 1, b:2}, {a: 1, b: 2}]}
注意
\nAMis 所有值为 url 的如: "http://www.baidu.com"
都会被替换成 proxy 代理,如果不希望这么做,请明确指示如: "raw:http://www.baidu.com"
。还有为了安全,AMis 默认只能转发公司内部 API 接口,如果您的接口在外网环境,也请明确指示如:"external:http://www.baidu.com"
配置项中,所有 boolean
类型的配置,都可以用 JS 表达式来配置。所有boolean
配置项,后面加个 On
则是表达式配置方式,可以用 js 语法来根据当前模型中的数据来决定是否启用。\n如:FormItem 中的 disabledOn
、hiddenOn
、visibleOn
、CRUD 中的 itemDraggableOn
等等。
为了能加入权限控制,表达是中允许可以用 acl.can
方法来检测当前用户是否拥有某个权限。\n如: {"disabledOn": "!can('some-resource')"}
。权限能力部分,请前往能力管理,\n权限配置请前往权限配置管理。
npm i amis\n
\n安装完后可以在 React Component 这么使用。
\nimport * as React from \'react\';\nimport {\n render as renderAmis\n} from \'amis\';\n\nclass MyComponent extends React.Component<any, any> {\n render() {\n return (\n <div>\n <p>通过 AMis 渲染页面</p>\n {renderAmis({\n // schema\n // 这里是 AMis 的 Json 配置。\n type: \'page\',\n title: \'简单页面\',\n body: \'内容\'\n }, {\n // props\n }, {\n // env\n // 这些是 AMis 需要的一些接口实现\n // 可以参考本项目里面的 Demo 部分代码。\n\n updateLocation: (location:string/*目标地址*/, replace:boolean/*是replace,还是push?*/) => {\n // 用来更新地址栏\n },\n\n jumpTo: (location:string/*目标地址*/) => {\n // 页面跳转, actionType: link、url 都会进来。\n },\n\n fetcher: ({\n url,\n method,\n data,\n config\n }:{\n url:string/*目标地址*/,\n method:\'get\' | \'post\' | \'put\' | \'delete\'/*发送方式*/,\n data: object | void/*数据*/,\n config: object/*其他配置*/\n }) => {\n // 用来发送 Ajax 请求,建议使用 axios\n },\n notify: (type:\'error\'|\'success\'/**/, msg:string/*提示内容*/) => {\n // 用来提示用户\n },\n alert: (content:string/*提示信息*/) => {\n // 另外一种提示,可以直接用系统框\n },\n confirm: (content:string/*提示信息*/) => {\n // 确认框。\n }\n });}\n </div>\n );\n }\n}\n
\nAMis 的渲染过程就是将 json
转成对应的 React 组件。先通过 json
的 type 找到对应的 Component
然后,然后把其他属性作为 props
传递过去完成渲染。
拿一个表单页面来说,如果用React组件调用大概是这样。
\n<Page\n title="页面标题"\n subTitle="副标题"\n>\n <Form\n title="用户登录"\n controls={[\n {\n type: \'text\',\n name: \'username\',\n label: \'用户名\'\n }\n ]}\n />\n</Page>\n
\n把以上配置方式换成 AMis JSON, 则是:
\n{\n "type": "page",\n "title": "页面标题",\n "subTitle": "副标题",\n "body": {\n "type": "form",\n "title": "用户登录",\n "controls": [\n {\n "type": "text",\n "name": "username",\n "label": "用户名"\n }\n ]\n }\n}\n
\n那么,AMis 是如何将 JSON 转成组件的呢?直接根据节点的 type 去跟组件一一对应?似乎很可能会重名比如在表格里面展示的类型 text
跟表单里面的 text
是完全不一样的,一个负责展示,一个却负责输入。所以说一个节点要被什么组件渲染,还需要携带上下文(context)信息。
如何去携带上下文(context)信息?AMis 中直接是用节点的路径(path)来作为上下文信息。从上面的例子来看,一共有三个节点,path 信息分别是。
\npage
页面节点page/body/form
表单节点page/body/form/controls/0/text
文本框节点。根据 path 的信息就能很容易注册组件跟节点对应了。
\nPage 组件的示例代码
\n@Renderer({\n test: /^page$/,\n // ... 其他信息隐藏了\n})\nexport class PageRenderer extends React.Component {\n // ... 其他信息隐藏了\n render() {\n const {\n title,\n body,\n render // 用来渲染孩子节点,如果当前是叶子节点则可以忽略。\n } = this.props;\n return (\n <div className="page">\n <h1>{title}</h1>\n <div className="body-container">\n {render(\'body\', body)/*渲染孩子节点*/}\n </div>\n </div>\n );\n }\n}\n
\nForm 组件的示例代码
\n@Renderer({\n test: /(^|\\/)form$/,\n // ... 其他信息隐藏了\n})\nexport class FormRenderer extends React.Component {\n // ... 其他信息隐藏了\n render() {\n const {\n title,\n controls,\n render // 用来渲染孩子节点,如果当前是叶子节点则可以忽略。\n } = this.props;\n return (\n <form className="form">\n {controls.map((control, index) => (\n <div className="form-item" key={index}>\n {render(`${index}/control`, control)}\n </div>\n ))}\n </form>\n );\n }\n}\n
\nText 组件的示例代码
\n@Renderer({\n test: /(^|\\/)form(?:\\/\\d+)?\\/control(?\\/\\d+)?\\/text$/\n // ... 其他信息隐藏了\n})\nexport class FormItemTextRenderer extends React.Component {\n // ... 其他信息隐藏了\n render() {\n const {\n label,\n name,\n onChange\n } = this.props;\n return (\n <div className="form-group">\n <label>{label}<label>\n <input type="text" onChange={(e) => onChange(e.currentTarget.value)} />\n </div>\n );\n }\n}\n
\n那么渲染过程就是根据节点 path 信息,跟组件池中的组件 test
(检测) 信息做匹配,如果命中,则把当前节点转给对应组件渲染,节点中其他属性将作为目标组件的 props。需要注意的是,如果是容器组件,比如以上例子中的 page
组件,从 props 中拿到的 body
是一个子节点,由于节点类型是不固定,由使用者决定,所以不能直接完成渲染,所以交给属性中下发的 render
方法去完成渲染,{render('body', body)}
,他的工作就是拿子节点的 path 信息去组件池里面找到对应的渲染器,然后交给对应组件去完成渲染。
如果 AMis 中组件不能满足你的需求,同时你又会 React 组件开发,那么就自己定制一个吧。
\n先来看个简单的例子
\nimport * as React from \'react\';\nimport {\n Renderer\n} from \'amis\';\n\n@Renderer({\n test: /(^|\\/)my\\-renderer$/,\n})\nclass CustomRenderer extends React.Component {\n render() {\n const {tip} = this.props;\n return (\n <div>这是自定义组件:{tip}</div>\n );\n }\n}\n
\n有了以上这段代码后,就可以这样使用了。
\n{\n "type": "page",\n "title": "自定义组件示例",\n "body": {\n "type": "my-renderer",\n "tip": "简单示例"\n }\n}\n
\n如果你看了AMis工作原理应该不难理解,这里注册一个 React 组件,当节点的 path 信息是 my-renderer
结尾时,交给当前组件来完成渲染。\n如果你只写叶子节点的渲染器,已经可以不用看了,如果你的渲染器中有容器需要可以放置其他节点,那么接着看以下这段代码。
import * as React from \'react\';\nimport {\n Renderer\n} from \'amis\';\n\n@Renderer({\n test: /(^|\\/)my\\-renderer2$/,\n})\nclass CustomRenderer extends React.Component {\n render() {\n const {\n tip,\n body,\n render\n } = this.props;\n return (\n <div>\n <p>这是自定义组件:{tip}</p>\n {body ? (\n <div className="container">\n {render(\'body\', body, {\n // 这里的信息会作为 props 传递给子组件,一般情况下都不需要这个\n })}\n </div>\n ) : null}\n </div>\n );\n }\n}\n
\n有了以上这段代码后,就可以这样使用了。
\n{\n "type": "page",\n "title": "自定义组件示例",\n "body": {\n "type": "my-renderer2",\n "tip": "简单示例",\n "body": {\n "type": "form",\n "controls": [\n {\n "type": "text",\n "label": "用户名",\n "name": "usename"\n }\n ]\n }\n }\n}\n
\n跟第一个列子不同的地方是,这里多了个 render
方法,这个方法就是专门用来渲染子节点的。来看下参数说明:
region
区域名称,你有可能有多个区域可以作为容器,请不要重复。node
子节点。props
可选,可以通过此对象跟子节点通信等。以上是普通渲染器的注册方式,如果是表单项,为了更简单的扩充,请使用 FormItem
注解,而不是 Renderer
。 原因是如果用 FormItem
是不用关心:label怎么摆,表单验证器怎么实现,如何适配表单的3中展现方式(水平、上下和内联模式),而只用关心:有了值后如何回显,响应用户交互设置新值。
import * as React from \'react\';\nimport {\n FormItem\n} from \'amis\';\n\n@FormItem({\n type: \'custom\'\n})\nclass MyFormItem extends React.Component {\n render() {\n const {\n value,\n onChange\n } = this.props;\n\n return (\n <div>\n <p>这个是个自定义组件</p>\n <p>当前值:{value}</p>\n <a className="btn btn-default" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a>\n </div>\n );\n }\n}\n
\n有了以上这段代码后,就可以这样使用了。
\n{\n "type": "page",\n "title": "自定义组件示例",\n "body": {\n "type": "form",\n "controls": [\n {\n "type": "text",\n "label": "用户名",\n "name": "usename"\n },\n\n {\n "type": "custom",\n "label": "随机值",\n "name": "randon"\n }\n ]\n }\n}\n
\n\n\n注意: 使用 FormItem 默认是严格模式,即只有必要的属性变化才会重新渲染,有可能满足不了你的需求,如果忽略性能问题,可以传入
\nstrictMode
:false
来关闭。
以上的例子都是需要先注册组件,然后再使用的,如果你在自己项目中使用,还有更简单的用法,以下示例直接无需注册。
\n{\n "type": "page",\n "title": "自定义组件示例",\n "body": {\n "type": "form",\n "controls": [\n {\n "type": "text",\n "label": "用户名",\n "name": "usename"\n },\n\n {\n "name": "a",\n "children": ({\n value,\n onChange\n }) => (\n <div>\n <p>这个是个自定义组件</p>\n <p>当前值:{value}</p>\n <a className="btn btn-default" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a>\n </div>\n )\n }\n ]\n }\n}\n
\n即:通过 children
传递一个React组件,这个示例是一个React Stateless Functional Component,也可以是传统的 React 组件。\n任何节点如果包含 children
这个属性,则都会把当前节点交给 children
来处理,跳过了从 AMis 渲染器池子中选择渲染器的过程。
npm i amis\n
\n安装完后可以在 React Component 这么使用。
\nimport * as React from 'react';\nimport {\n render as renderAmis\n} from 'amis';\n\nclass MyComponent extends React.Component<any, any> {\n render() {\n return (\n <div>\n <p>通过 AMis 渲染页面</p>\n {renderAmis({\n // schema\n // 这里是 AMis 的 Json 配置。\n type: 'page',\n title: '简单页面',\n body: '内容'\n }, {\n // props\n }, {\n // env\n // 这些是 AMis 需要的一些接口实现\n // 可以参考本项目里面的 Demo 部分代码。\n\n updateLocation: (location:string/*目标地址*/, replace:boolean/*是replace,还是push?*/) => {\n // 用来更新地址栏\n },\n\n jumpTo: (location:string/*目标地址*/) => {\n // 页面跳转, actionType: link、url 都会进来。\n },\n\n fetcher: ({\n url,\n method,\n data,\n config\n }:{\n url:string/*目标地址*/,\n method:'get' | 'post' | 'put' | 'delete'/*发送方式*/,\n data: object | void/*数据*/,\n config: object/*其他配置*/\n }) => {\n // 用来发送 Ajax 请求,建议使用 axios\n },\n notify: (type:'error'|'success'/**/, msg:string/*提示内容*/) => {\n // 用来提示用户\n },\n alert: (content:string/*提示信息*/) => {\n // 另外一种提示,可以直接用系统框\n },\n confirm: (content:string/*提示信息*/) => {\n // 确认框。\n }\n });}\n </div>\n );\n }\n}\n
\nAMis 的渲染过程就是将 json
转成对应的 React 组件。先通过 json
的 type 找到对应的 Component
然后,然后把其他属性作为 props
传递过去完成渲染。
拿一个表单页面来说,如果用React组件调用大概是这样。
\n<\"页面标题\"\n subTitle=\"副标题\"\n>\n <Form\n =\"用户登录\"\n controls={[\n {\n type: 'text',\n name: 'username',\n : '用户名'\n }\n ]}\n />\n</ >\n
\n =
\n把以上配置方式换成 AMis JSON, 则是:
\n{\n \"type\": \"page\",\n \"title\": \"页面标题\",\n \"subTitle\": \"副标题\",\n \"body\": {\n \"type\": \"form\",\n \"title\": \"用户登录\",\n \"controls\": [\n {\n \"type\": \"text\",\n \"name\": \"username\",\n \"label\": \"用户名\"\n }\n ]\n }\n}\n
\n那么,AMis 是如何将 JSON 转成组件的呢?直接根据节点的 type 去跟组件一一对应?似乎很可能会重名比如在表格里面展示的类型 text
跟表单里面的 text
是完全不一样的,一个负责展示,一个却负责输入。所以说一个节点要被什么组件渲染,还需要携带上下文(context)信息。
如何去携带上下文(context)信息?AMis 中直接是用节点的路径(path)来作为上下文信息。从上面的例子来看,一共有三个节点,path 信息分别是。
\npage
页面节点page/body/form
表单节点page/body/form/controls/0/text
文本框节点。根据 path 的信息就能很容易注册组件跟节点对应了。
\nPage 组件的示例代码
\n// ... 其他信息隐藏了\n})\nexport class PageRenderer extends React.Component {\n // ... 其他信息隐藏了\n render() {\n const {\n title,\n body,\n render // 用来渲染孩子节点,如果当前是叶子节点则可以忽略。\n } = this.props;\n return (\n <div className=\"page\">\n <h1>{title}</h1>\n <div className=\"body-container\">\n {render('body', body)/*渲染孩子节点*/}\n </div>\n </div>\n );\n }\n}\n
({\n test: /^page$/,\n
\nForm 组件的示例代码
\n// ... 其他信息隐藏了\n})\nexport class FormRenderer extends React.Component {\n // ... 其他信息隐藏了\n render() {\n const {\n title,\n controls,\n render // 用来渲染孩子节点,如果当前是叶子节点则可以忽略。\n } = this.props;\n return (\n <form className=\"form\">\n {controls.map((control, index) => (\n <div className=\"form-item\" key={index}>\n {render(`${index}/control`, control)}\n </div>\n ))}\n </form>\n );\n }\n}\n
({\n test: /(^|\\/)form$/,\n
\nText 组件的示例代码
\n// ... 其他信息隐藏了\n})\nexport class FormItemTextRenderer extends React.Component {\n // ... 其他信息隐藏了\n render() {\n const {\n label,\n name,\n onChange\n } = this.props;\n return (\n <div className=\"form-group\">\n <label>{label}<label>\n <input type=\"text\" onChange={(e) => onChange(e.currentTarget.value)} />\n </div>\n );\n }\n}\n
({\n test: /(^|\\/)form(?:\\/\\d+)?\\/control(?\\/\\d+)?\\/text$/\n
\n那么渲染过程就是根据节点 path 信息,跟组件池中的组件 test
(检测) 信息做匹配,如果命中,则把当前节点转给对应组件渲染,节点中其他属性将作为目标组件的 props。需要注意的是,如果是容器组件,比如以上例子中的 page
组件,从 props 中拿到的 body
是一个子节点,由于节点类型是不固定,由使用者决定,所以不能直接完成渲染,所以交给属性中下发的 render
方法去完成渲染,{render('body', body)}
,他的工作就是拿子节点的 path 信息去组件池里面找到对应的渲染器,然后交给对应组件去完成渲染。
如果 AMis 中组件不能满足你的需求,同时你又会 React 组件开发,那么就自己定制一个吧。
\n先来看个简单的例子
\nimport * as React from 'react';\nimport {\n Renderer\n} from 'amis';\n\n ({\n test: /(^|\\/)my\\-renderer$/,\n})\nclass CustomRenderer extends React.Component {\n render() {\n const {tip} = this.props;\n return (\n <div>这是自定义组件:{tip}</div>\n );\n }\n}\n
\n有了以上这段代码后,就可以这样使用了。
\n{\n \"type\": \"page\",\n \"title\": \"自定义组件示例\",\n \"body\": {\n \"type\": \"my-renderer\",\n \"tip\": \"简单示例\"\n }\n}\n
\n如果你看了AMis工作原理应该不难理解,这里注册一个 React 组件,当节点的 path 信息是 my-renderer
结尾时,交给当前组件来完成渲染。\n如果你只写叶子节点的渲染器,已经可以不用看了,如果你的渲染器中有容器需要可以放置其他节点,那么接着看以下这段代码。
import * as React from 'react';\nimport {\n Renderer\n} from 'amis';\n\n ({\n test: /(^|\\/)my\\-renderer2$/,\n})\nclass CustomRenderer extends React.Component {\n render() {\n const {\n tip,\n body,\n render\n } = this.props;\n return (\n <div>\n <p>这是自定义组件:{tip}</p>\n {body ? (\n <div className=\"container\">\n {render('body', body, {\n // 这里的信息会作为 props 传递给子组件,一般情况下都不需要这个\n })}\n </div>\n ) : null}\n </div>\n );\n }\n}\n
\n有了以上这段代码后,就可以这样使用了。
\n{\n \"type\": \"page\",\n \"title\": \"自定义组件示例\",\n \"body\": {\n \"type\": \"my-renderer2\",\n \"tip\": \"简单示例\",\n \"body\": {\n \"type\": \"form\",\n \"controls\": [\n {\n \"type\": \"text\",\n \"label\": \"用户名\",\n \"name\": \"usename\"\n }\n ]\n }\n }\n}\n
\n跟第一个列子不同的地方是,这里多了个 render
方法,这个方法就是专门用来渲染子节点的。来看下参数说明:
region
区域名称,你有可能有多个区域可以作为容器,请不要重复。node
子节点。props
可选,可以通过此对象跟子节点通信等。以上是普通渲染器的注册方式,如果是表单项,为了更简单的扩充,请使用 FormItem
注解,而不是 Renderer
。 原因是如果用 FormItem
是不用关心:label怎么摆,表单验证器怎么实现,如何适配表单的3中展现方式(水平、上下和内联模式),而只用关心:有了值后如何回显,响应用户交互设置新值。
import * as React from 'react';\nimport {\n FormItem\n} from 'amis';\n\n@FormItem({\n type: 'custom'\n})\nclass MyFormItem extends React.Component {\n render() {\n const {\n value,\n onChange\n } = this.props;\n\n return (\n <div>\n <p>这个是个自定义组件</p>\n <p>当前值:{value}</p>\n <a className=\"btn btn-default\" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a>\n </div>\n );\n }\n}\n
\n有了以上这段代码后,就可以这样使用了。
\n{\n \"type\": \"page\",\n \"title\": \"自定义组件示例\",\n \"body\": {\n \"type\": \"form\",\n \"controls\": [\n {\n \"type\": \"text\",\n \"label\": \"用户名\",\n \"name\": \"usename\"\n },\n\n {\n \"type\": \"custom\",\n \"label\": \"随机值\",\n \"name\": \"randon\"\n }\n ]\n }\n}\n
\n\n\n注意: 使用 FormItem 默认是严格模式,即只有必要的属性变化才会重新渲染,有可能满足不了你的需求,如果忽略性能问题,可以传入
\nstrictMode
:false
来关闭。
以上的例子都是需要先注册组件,然后再使用的,如果你在自己项目中使用,还有更简单的用法,以下示例直接无需注册。
\n{\n \"type\": \"page\",\n \"title\": \"自定义组件示例\",\n \"body\": {\n \"type\": \"form\",\n \"controls\": [\n {\n \"type\": \"text\",\n \"label\": \"用户名\",\n \"name\": \"usename\"\n },\n\n {\n \"name\": \"a\",\n \"children\": ({\n value,\n onChange\n }) => (\n <div>\n <p>这个是个自定义组件</p>\n <p>当前值:{value}</p>\n <a className=\"btn btn-default\" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a>\n </div>\n )\n }\n ]\n }\n}\n
\n即:通过 children
传递一个React组件,这个示例是一个React Stateless Functional Component,也可以是传统的 React 组件。\n任何节点如果包含 children
这个属性,则都会把当前节点交给 children
来处理,跳过了从 AMis 渲染器池子中选择渲染器的过程。