百度 amis 低代码
amis 是一个低代码前端框架,它使用 JSON 配置来生成页面,可以减少页面开发工作量,极大提升效率。
参考:https://aisuda.bce.baidu.com/amis/zh-CN/docs/concepts/linkage
为了实现用最简单方式来生成大部分页面,amis 的解决方案是基于 JSON 来配置,它的独特好处是:
- 不需要懂前端
- 不受技术更新的影响
- 可以使用可视化页面编辑器来制作页面:一般前端可视化编辑器只能用来做静态原型,而 amis 可视化编辑器做出的页面是可以直接上线的。
amis 的其它亮点:
- 提供完整的界面解决方案:其它 UI 框架必须使用 JavaScript 来组装业务逻辑,而 amis 只需 JSON 配置就能完成完整功能开发,包括数据获取、表单提交及验证等功能,做出来的页面不需要经过二次开发就能直接上线;
- 大量的内置组件:其它 UI 框架大部分都只有最通用的组件,如果遇到一些稍微不常用的组件就得自己找第三方,而这些第三方组件往往在展现和交互上不一致,整合起来效果不好,而 amis 则内置大量组件,包括了富文本编辑器、代码编辑器、diff、条件组合、实时日志等业务组件,绝大部分中后台页面开发只需要了解 amis 就足够了;
- 支持扩展:除了低代码模式,还可以通过 自定义组件 来扩充组件,实际上 amis 可以当成普通 UI 库来使用,实现 90% 低代码,10% 代码开发的混合模式,既提升了效率,又不失灵活性;
- 容器支持无线嵌套:可以通过嵌套来满足各种布局及展现需求;
- 经历长时间的实战考验:amis 在百度内部得到了广泛使用,在 6 年多的时间里创建了 5 万页面,从内容审核到机器管理,从数据分析到模型训练,amis 满足了各种各样的页面需求,最复杂的页面有超过 1 万行 JSON 配置。
JSON 配置使得 amis 更适合做有大量常见 UI 组件的页面,但对于面向普通客户(toC)的页面,往往追求个性化的视觉效果,这种情况下用 amis 就不合适,实际上绝大部分前端 UI 组件库也都不适合,只能定制开发。有些复杂的前端功能,比如 可视化编辑器,其中有大量定制的拖拽操作,这种需要依赖原生 DOM 实现的功能无法使用 amis。但对于某些交互固定的领域,比如图连线,amis 后续会有专门的组件来实现。
一个普通的页面大致这个样子: 对应的 json 数据如下:
json
{
"title": "浏览器内核对 CSS 的支持情况",
"remark": "嘿,不保证数据准确性",
"type": "page", // 组件类型:也是渲染器类型
"body": {
"type": "crud", // 组件类型
"draggable": true, // 是否可拖动排序
"syncLocation": false,//是否过滤条件参数同步到地址栏
"api": "/amis/api/mock2/sample",//初始化数据api
"keepItemSelectionOnPageChange": true,//分页时是否保留用户的选择
//是否根据列元素的searchable属性,自动生成查询条件表单
"autoGenerateFilter": true,
"bulkActions": [ // 配置工具栏左侧的批量操作
{
"type": "button", //组件类型button
"label": "批量删除", // 组件显示文案
"data": { // 组件绑定的数据
"a": "1",
"b": "2",
"c": {
"e": "3",
"f": "4",
"g": "5"
},
"actionType": "ajax", // 动作类型:进行Ajax请求
//请求接口,可以是对象形式,可以获取其他name的参数
"api": "delete:/amis/api/mock2/sample/${ids|raw}",
"api": {
"url": "/amis/api/mock2/form/saveForm",
"method": "post",
"data": {
"name": "${name}",
"email": "${email}",
"&": "${c}",
"描述:":"可以获取json中其他name的变量,&映射data数据c"
}
},
"confirmText": "确定要批量删除?" // 确认文本
},
{
"type": "button",
"label": "批量修改",
"actionType": "dialog", //动作类型:需要弹窗
"dialog": {
"title": "批量编辑",
"name": "sample-bulk-edit",
"body": {
"type": "form",
"api": "/amis/api/mock2/sample/bulkUpdate2",
"body": [
{
"type": "hidden",
"name": "ids"
},
{
"type": "input-text",
"name": "engine",
"label": "Engine"
}
]
}
}
}
],
// 快速编辑后用来批量保存的api
"quickSaveApi": "/amis/api/mock2/sample/bulkUpdate",
// 快速编辑配置成及时保存时的api
"quickSaveItemApi": "/amis/api/mock2/sample/$id",
"headerToolbar": [ // 配置顶部工具栏
"bulkActions",
{
"type": "button",
"label": "重置测试数据",
"actionType": "ajax",
"size": "sm", // 组件大小
"api": "/amis/api/mock2/sample/reset"
},
"export-excel",
{
"type": "tpl", // 组件类型:导出模板
"tpl": "一共有 ${count} 行数据。",
"className": "v-middle"
},
{
"type": "columns-toggler", // 控制列的按钮
"align": "right",//对齐方式
"draggable": true
},
{
"type": "drag-toggler", // 进行排序的按钮
"align": "right"
}
],
"footerToolbar": [ // 配置底部工具栏
"statistics", // 显示数据统计
"switch-per-page", // 显示切换每页大小的组件
"pagination" // 显示分页组件
],
"columns": [ // 表格列的配置
{
"name": "id", // 对应数据字段
"label": "ID", // 显示文案
"width": 20, // 列的宽度
"sortable": true, //是否可排序
"type": "text", //组件类型——渲染器类型
"searchable": { // 可根据此字段进行搜索
"type": "input-text",
"name": "id",
"label": "主键",
"placeholder": "输入id"
}
},
{
"name": "browser",
"label": "Browser",
"searchable": {
"type": "select",
"name": "browser",
"label": "浏览器",
"placeholder": "选择浏览器",
"options": [ // 配置搜索选项
{
"label": "Internet Explorer ",
"value": "ie"
},
{
"label": "AOL browser",
"value": "aol"
},
{
"label": "Firefox",
"value": "firefox"
}
]
}
},
{
"name": "platform",
"label": "平台",
"popOver": { // 显示popover弹窗
"trigger": "hover", // 触发方式:hover
"body": {
"type": "tpl",
"tpl": "就是为了演示有个叫 popOver 的功能"
}
},
"sortable": true,
"type": "text"
},
{
"name": "grade",
"label": "CSS 等级",
"type": "select",
"options": [
"A",
"B",
"C",
"D",
"X"
]
},
{
"type": "operation", // 配置最后一列的操作按钮
"label": "操作",
"width": 100,
"buttons": [
{
"type": "button",
"actionType": "ajax",
"label": "删除",
"confirmText": "您确认要删除?",
"api": "delete:/amis/api/mock2/sample/$id"
}
]
}
]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
另一个例子: json 为:
json
{
"type": "page",
"toolbar": [
{
"type": "form",
"panelClassName": "mb-0",
"title": "",
"body": [
{
"type": "select", //select组件
"label": "区域",
"name": "businessLineId",
"selectFirst": true, // 默认选中第一个
"mode": "inline", //内容区的展示模式
"options": ["北京", "上海"],
"checkAll": false // 多选条件下,是否可全选
},
{
"label": "时间范围",
"type": "input-date-range", //时间范围选择器
"name": "dateRange",
"inline": true,
//支持相对值。-2mins: 2分钟前 +2days:2天后。可用单位: `min`、`hour`、`day`、`week`、`month`、`year`。所有单位支持复数形式。
"value": "-1month,+0month",
"inputFormat": "YYYY-MM-DD", //显示的时间格式
"format": "YYYY-MM-DD", //提交的时间格式
"closeOnSelect": true,
"clearable": false
}
],
"actions": [], //按钮集合,会固定在底部显示
"mode": "inline",
"target": "mainPage",
"submitOnChange": true,
"submitOnInit": true
}
],
"body": [
{
"type": "grid",
"columns": [
{
"type": "panel",
"className": "h-full",
"body": {
"type": "tabs",
"tabs": [
{
"title": "消费趋势",
"tab": [
{
"type": "chart", //chart图表组件,默认Echarts图表库
"config": {
// 图表配置
"title": {
"text": "消费趋势"
},
"tooltip": {},
"xAxis": {
"type": "category",
"boundaryGap": false,
"data": ["一月", "二月", "三月", "四月", "五月", "六月"]
},
"yAxis": {},
"series": [
{
"name": "销量",
"type": "line",
"areaStyle": {
"color": {
"type": "linear",
"x": 0,
"y": 0,
"x2": 0,
"y2": 1,
"colorStops": [
{
"offset": 0,
"color": "rgba(84, 112, 197, 1)"
},
{
"offset": 1,
"color": "rgba(84, 112, 197, 0)"
}
],
"global": false
}
},
"data": [5, 20, 36, 10, 10, 20]
}
]
}
}
]
},
{ "title": "账户余额", "tab": "0" }
]
}
},
{
"type": "panel",
"className": "h-full",
"body": [
{
"type": "chart",
"config": {
"title": { "text": "使用资源占比" },
"series": [
{
"type": "pie",
"data": [
{ "name": "BOS", "value": 70 },
{ "name": "CDN", "value": 68 },
{ "name": "BCC", "value": 48 },
{ "name": "DCC", "value": 40 },
{ "name": "RDS", "value": 32 }
]
}
]
}
}
]
}
]
},
{
"type": "crud",
"className": "m-t-sm",
"api": "/amis/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" },
{ "name": "grade", "label": "CSS grade" }
]
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
Amis 的使用
amis 有两种使用方法:
- JS SDK,可以用在任意页面中
- React,可以用在 React 项目中
SDK 版本适合对前端或 React 不了解的开发者,它不依赖 npm 及 webpack,可以像 Vue/jQuery 那样外链代码就能使用。
html
<!-- 引入CSS样式文件 -->
<head>
<link rel="stylesheet" href="sdk.css" />
</head>
<body>
<!-- 配置挂载点 -->
<div id="root" class="app-wrapper"></div>
<!-- 引入Amis SDK -->
<script src="sdk.js"></script>
<script type="text/javascript">
(function () {
let amis = amisRequire('amis/embed');
// 通过替换下面这个配置来生成不同页面
let amisJSON = {
type: 'page',
title: '表单页面',
body: {
type: 'form',
name:'formname',
mode: 'horizontal',
api: '/saveForm',
body: [
{ label: 'Name',type: 'input-text',name: 'name'},
{ label: 'Email',type: 'input-email',name: 'email'}
]
}
};
// 这里是初始 props,一般不用传。 默认是中文
let initProps= { locale: 'en-US' }
// 下面是一些可选的外部控制函数
let config= {
// 在 sdk 中可以不传,用来实现 ajax 请求,但在 npm 中这是必须提供的
fetcher: (url, method, data,responseType, config,headers) => {},
// 全局 api 请求适配器,也可以针对某个特定接口单独处理。
requestAdaptor(api) {
// 支持异步,可以通过 api.mockResponse 来设置返回结果,跳过真正的请求发送
// 此功能自定义 fetcher 的话会失效
// api.context 中包含发送请求前的上下文信息
return api;
}
// 全局 api 适配器。 也可以针对某个特定接口单独处理。
responseAdaptor(api, payload, query, request, response) {
return payload;
}
// 用来接管页面跳转,比如用 location.href 或 window.open,或者自己实现 amis 配置更新
jumpTo: (to: string, action?: Action, ctx?: object) => { location.href = to; },
// 用来实现地址栏更新
updateLocation: (to, replace) => {},
//设置阻止路由跳转的钩子函数,用来实现 form 未保存提前离开时出现确认框。
blockRouting:(fn: (nextLocation:any) => void | string) => () => void,
// 用来判断是否目标地址当前地址。
isCurrentUrl: url => boolean,
// 用来配置弹窗等组件的挂载位置
getModalContainer: () => document.getElementsByTagName('body')[0],
// 可以通过它懒加载自定义组件
loadRenderer:(schema: any, path: string) => Promise<Function>,
// Form 表单验证失败时在 notify 消息提示中是否隐藏详细信息
hideValidateFailedDetail: boolean,
// 用来实现复制到剪切板
copy: (contents: string, options?: {silent: boolean, format?: string})=>{},
// 用来实现通知
notify: (type, msg) => {},
// 用来实现提示
alert: content => {},
// 用来实现确认框。
confirm: content => {},
// 主题,默认是 default,还可以设置成 cxd 或 dark,但记得引用它们的 css,比如 sdk 目录下的 cxd.css
theme: 'cxd'
// 用来实现用户行为跟踪,详细请查看左侧高级中的说明
tracker: (eventTracker) => {},
// 开发时使用 localhost 地址,而线上使用 xxx.com.
replaceText: {
HOST: 'http://localhost'
},
// Toast提示弹出位置,默认为'top-center'
toastPosition: 'top-right' | 'top-center' | 'top-left' | 'bottom-center' | 'bottom-left' | 'bottom-right' | 'center'
}
/**
* 生成页面并挂载到指定dom
* schemeJSON
* initProps
* config
* @return 可以获取到 amis 渲染的内部信息
*/
let amisScoped = amis.embed('#root', amisJSON,initProps,config);
//来获取到所有表单的值,需要注意 page 和 form 都需要有 name 属性。
amisScoped.getComponentByName('page.formname').getValues()
//修改表单中的值。
amisScoped.getComponentByName('page.formname').setValues({'name1': 'othername'})
//调用 amis 中的通用动作和目标组件的动作
amisScoped.doAction(actions, ctx)
//依次执行了toast提示、ajax请求、dialog弹窗、给目标组件赋值动作
amisScoped.doAction(
[
{
actionType: 'toast',
args: {
msg: '${amisUser.name}, ${myName}'
}
},
{
actionType: 'ajax',
api: {
url: '/amis/api/mock2/form/saveForm',
method: 'post'
}
},
{
actionType: 'dialog',
dialog: {
type: 'dialog',
title: '弹窗',
body: [
{
type: 'tpl',
tpl: '<p>对,你打开了弹窗</p>',
inline: false
}
]
}
},
{
actionType: 'setValue',
componentId: 'name',
args: {
value: '${myName}'
}
}
],
{
myName: 'amis'
}
);
// updateProps 方法来更新下发到 amis 的属性
// udpateSchema 方法来更新更新内容配置。
amisScoped.updateProps(
{
// 新的属性对象
} /*, () => {} 更新回调 */
);
//单页应用,在离开当前页面的时候通常需要销毁实例
amisScoped.unmount();
// 可以基于 SDK 版本封装成 component 供 vue 使用,具体请参考示例:https://github.com/aisuda/vue2-amis-demo
})();
</script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161