forked from p96170835/amis
差不多了
This commit is contained in:
parent
62a3956026
commit
d34c5c707e
|
@ -179,9 +179,8 @@ module.exports = function (content, file) {
|
||||||
return placeholder[id] || '';
|
return placeholder[id] || '';
|
||||||
});
|
});
|
||||||
|
|
||||||
content =
|
content = fis.compile.partial(content, file, 'html');
|
||||||
fis.compile.partial(content, file, 'html') +
|
// + `\n\n<div class="m-t-lg b-l b-info b-3x wrapper bg-light dk">文档内容有误?欢迎大家一起来编写,文档地址:<i class="fa fa-github"></i><a href="https://github.com/baidu/amis/tree/master${file.subpath}">${file.subpath}</a>。</div>`;
|
||||||
`\n\n<div class="m-t-lg b-l b-info b-3x wrapper bg-light dk">文档内容有误?欢迎大家一起来编写,文档地址:<i class="fa fa-github"></i><a href="https://github.com/baidu/amis/tree/master${file.subpath}">${file.subpath}</a>。</div>`;
|
|
||||||
info.html = content;
|
info.html = content;
|
||||||
info.toc = toc;
|
info.toc = toc;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ menuName: Page 页面
|
||||||
icon:
|
icon:
|
||||||
order: 23
|
order: 23
|
||||||
---
|
---
|
||||||
Page 组件是 amis 页面结构中,**必须也是唯一的** 顶级容器组件,是整个页面配置的入口组件。
|
|
||||||
|
Page 组件是 amis 页面 JSON 配置中,**唯一的** 顶级容器组件,是整个页面配置的入口组件。
|
||||||
|
|
||||||
## 基本用法
|
## 基本用法
|
||||||
|
|
||||||
|
@ -85,14 +86,14 @@ Page 默认将页面分为几个区域,分别是**内容区(`body`)**、**
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
具体 API 规范查看 [API文档](./api)。
|
具体 API 规范查看 [API 文档](./api)。
|
||||||
|
|
||||||
## 轮训初始化接口
|
## 轮训初始化接口
|
||||||
|
|
||||||
想要在页面渲染后,轮训请求初始化接口,步骤如下:
|
想要在页面渲染后,轮训请求初始化接口,步骤如下:
|
||||||
|
|
||||||
1. 配置 initApi;
|
1. 配置 initApi;
|
||||||
2. 配置 interval:单位为ms,最低值3000,低于该值按3000处理。
|
2. 配置 interval:单位为 ms,最低值 3000,低于该值按 3000 处理。
|
||||||
|
|
||||||
```schema:height="200"
|
```schema:height="200"
|
||||||
{
|
{
|
||||||
|
@ -147,8 +148,3 @@ Page 默认将页面分为几个区域,分别是**内容区(`body`)**、**
|
||||||
| interval | `number` | `3000` | 刷新时间(最低 3000) |
|
| interval | `number` | `3000` | 刷新时间(最低 3000) |
|
||||||
| silentPolling | `boolean` | `false` | 配置刷新时是否显示加载动画 |
|
| silentPolling | `boolean` | `false` | 配置刷新时是否显示加载动画 |
|
||||||
| stopAutoRefreshWhen | [表达式](./expression) | `""` | 通过表达式来配置停止刷新的条件 |
|
| stopAutoRefreshWhen | [表达式](./expression) | `""` | 通过表达式来配置停止刷新的条件 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
219
docs/index.md
219
docs/index.md
|
@ -1 +1,218 @@
|
||||||
## 欢迎来到 amis 的世界
|
---
|
||||||
|
title: 起步
|
||||||
|
description: ddsaad
|
||||||
|
type: 0
|
||||||
|
group: 💡 概念
|
||||||
|
menuName: 起步
|
||||||
|
icon:
|
||||||
|
order: 8
|
||||||
|
---
|
||||||
|
|
||||||
|
## 什么是 amis
|
||||||
|
|
||||||
|
amis 是一个低代码前端框架,它使用 JSON 配置来生成页面,可以节省页面开发工作量,极大提升开发前端页面的效率。
|
||||||
|
|
||||||
|
## 为什么要做 amis?🤔
|
||||||
|
|
||||||
|
在经历了十几年的发展后,前端开发变得越来越复杂,门槛也越来越高,要使用当下流行的 UI 组件库,你必须懂 npm、webpack、react/vue,必须熟悉 ES 6 语法,最好还了解状态管理(比如 Redux),如果没接触过函数式编程,一开始入门就很困难,而它还有巨大的 [生态](https://github.com/markerikson/redux-ecosystem-links),相关的库有 2347 个。
|
||||||
|
|
||||||
|
然而前端技术的发展不会停滞,等学完这些后可能会发现大家都用 Hooks 了、某个打包工具取代 Webpack 了。。。
|
||||||
|
|
||||||
|
而有时候你只是为了做个普通的增删改查界面,用于系统管理,类似下面这种:
|
||||||
|
|
||||||
|
```schema:height="900"
|
||||||
|
{
|
||||||
|
"title": "浏览器内核对 CSS 的支持情况",
|
||||||
|
"remark": "嘿,不保证数据准确性",
|
||||||
|
"type": "page",
|
||||||
|
"body": {
|
||||||
|
"type": "crud",
|
||||||
|
"draggable": true,
|
||||||
|
"api": "https://houtai.baidu.com/api/sample",
|
||||||
|
"keepItemSelectionOnPageChange": true,
|
||||||
|
"filter": {
|
||||||
|
"title": "筛选",
|
||||||
|
"submitText": "",
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"name": "keywords",
|
||||||
|
"placeholder": "关键字",
|
||||||
|
"addOn": {
|
||||||
|
"label": "搜索",
|
||||||
|
"type": "submit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"bulkActions": [
|
||||||
|
{
|
||||||
|
"label": "批量删除",
|
||||||
|
"actionType": "ajax",
|
||||||
|
"api": "delete:https://houtai.baidu.com/api/sample/${ids|raw}",
|
||||||
|
"confirmText": "确定要批量删除?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "批量修改",
|
||||||
|
"actionType": "dialog",
|
||||||
|
"dialog": {
|
||||||
|
"title": "批量编辑",
|
||||||
|
"name": "sample-bulk-edit",
|
||||||
|
"body": {
|
||||||
|
"type": "form",
|
||||||
|
"api": "https://houtai.baidu.com/api/sample/bulkUpdate2",
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"type": "hidden",
|
||||||
|
"name": "ids"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"name": "engine",
|
||||||
|
"label": "Engine"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"quickSaveApi": "https://houtai.baidu.com/api/sample/bulkUpdate",
|
||||||
|
"quickSaveItemApi": "https://houtai.baidu.com/api/sample/$id",
|
||||||
|
"filterTogglable": true,
|
||||||
|
"headerToolbar": [
|
||||||
|
"filter-toggler",
|
||||||
|
"bulkActions",
|
||||||
|
{
|
||||||
|
"type": "tpl",
|
||||||
|
"tpl": "一共有 ${count} 行数据。",
|
||||||
|
"className": "v-middle"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "columns-toggler",
|
||||||
|
"align": "right"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "drag-toggler",
|
||||||
|
"align": "right"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "pagination",
|
||||||
|
"align": "right"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"footerToolbar": ["statistics", "switch-per-page", "pagination"],
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"label": "ID",
|
||||||
|
"width": 20,
|
||||||
|
"sortable": true,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "engine",
|
||||||
|
"label": "Rendering engine",
|
||||||
|
"sortable": true,
|
||||||
|
"searchable": true,
|
||||||
|
"type": "text",
|
||||||
|
"remark": "Trident 就是 IE,Gecko 就是 Firefox"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "platform",
|
||||||
|
"label": "Platform(s)",
|
||||||
|
"popOver": {
|
||||||
|
"body": {
|
||||||
|
"type": "tpl",
|
||||||
|
"tpl": "就是为了演示有个叫 popOver 的功能"
|
||||||
|
},
|
||||||
|
"offset": {
|
||||||
|
"y": 50
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sortable": true,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "grade",
|
||||||
|
"label": "CSS grade",
|
||||||
|
"quickEdit": {
|
||||||
|
"mode": "inline",
|
||||||
|
"type": "select",
|
||||||
|
"options": ["A", "B", "C", "D", "X"]
|
||||||
|
},
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "operation",
|
||||||
|
"label": "操作",
|
||||||
|
"width": 100,
|
||||||
|
"buttons": [
|
||||||
|
{
|
||||||
|
"type": "button",
|
||||||
|
"icon": "fa fa-times text-danger",
|
||||||
|
"actionType": "ajax",
|
||||||
|
"tooltip": "删除",
|
||||||
|
"confirmText": "您确认要删除?",
|
||||||
|
"api": "delete:https://houtai.baidu.com/api/sample/$id"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这个界面虽然用 Bootstrap 也能快速搭起来,但要想体验好就需要加很多细节功能,比如:
|
||||||
|
|
||||||
|
- 数据动态加载
|
||||||
|
- 编辑单行数据
|
||||||
|
- 批量删除和修改
|
||||||
|
- 查询某列
|
||||||
|
- 按某列排序
|
||||||
|
- 隐藏某列
|
||||||
|
- 开启整页内容拖拽排序
|
||||||
|
- 表格有分页(页数还会同步到地址栏,刷新页面试试)
|
||||||
|
- 如果往下拖动还有首行冻结来方便查看表头等
|
||||||
|
全部实现这些需要大量的代码。
|
||||||
|
|
||||||
|
然而上面也看到了,在 amis 里只需要 150 行 JSON 配置(嘿,其中 40 多行只有一个括号),你不需要了解 React/Vue、Webpack,甚至不需要了解 JavaScript,即便没学过 amis 也能猜到大部分配置的作用,只需要简单配置就能完成所有页面开发
|
||||||
|
|
||||||
|
这正是建立 amis 的初衷,我们认为:**对于大部分常用页面,应该使用最简单的方法来实现**,而不是越来越复杂。
|
||||||
|
|
||||||
|
## 用 JSON 写页面有什么好处 ❓
|
||||||
|
|
||||||
|
为了实现用最简单方式来生成大部分页面,amis 的解决方案是基于 JSON 来配置,它的独特好处是:
|
||||||
|
|
||||||
|
- **不需要懂前端**:在百度内部,大部分 amis 用户之前从来没写过前端页面,也不会 `JavaScript`,就能做出专业且复杂的后台界面,这是所有其他前端 UI 库都无法做到的;
|
||||||
|
- **不受前端技术更新的影响**:百度内部最老的 amis 页面是 4 年多前创建的,至今还在使用,而当年的 `Angular/Vue/React` 版本现在都废弃了,当年流行的 `Gulp` 也被 `Webpack` 取代了,如果这些页面不是用 amis,现在的维护成本会很高,同时还能享受 amis 升级带来的界面改进;
|
||||||
|
- 可以 **完全** 使用 [可视化页面编辑器](https://fex-team.github.io/amis-editor/#/edit/0) 来制作页面:一般前端可视化编辑器只能用来做静态原型,而 amis 可视化编辑器做出的页面是可以直接上线的。
|
||||||
|
|
||||||
|
> JSON 是一种轻量级的数据交换格式,简洁和清晰的层次结构使得它成为理想的数据交换语言。它易于人阅读和编写,同时也易于机器解析和生成,能够有效地提升网络传输效率。
|
||||||
|
>
|
||||||
|
> 更多关于 JSON 的知识,可以阅读[百度百科](https://baike.baidu.com/item/JSON)
|
||||||
|
|
||||||
|
## amis 的其它亮点 ✨
|
||||||
|
|
||||||
|
- **提供完整的界面解决方案**:其它 UI 框架必须使用 JavaScript 来组装业务逻辑,而 amis 只需 JSON 配置就能完成完整功能开发,包括数据获取、表单提交及验证等功能;
|
||||||
|
- **内置 100+ 种 UI 组件**:包括其它 UI 框架都会不提供的富文本编辑器、代码编辑器等,能满足各种页面组件展现的需求,而且对于特殊的展现形式还可以通过 [自定义组件](./start/custom.md) 来扩充;
|
||||||
|
- **容器支持无限级嵌套**:可以通过组合来满足各种布局需求;
|
||||||
|
- **经历了长时间的实战考验**:amis 在百度内部得到了广泛使用,在 4 年多的时间里创建了 **3w** 多页面,从内容审核到机器管理,从数据分析到模型训练,amis 满足了各种各样的页面需求。
|
||||||
|
|
||||||
|
## amis 不适合做什么?😶
|
||||||
|
|
||||||
|
使用 JSON 有优点但也有明显缺点,在以下场合并不适合 amis:
|
||||||
|
|
||||||
|
- 大量定制 UI,尤其是面向普通客户(toC)的产品页面
|
||||||
|
- JSON 配置使得 amis 更适合做有大量常见 UI 组件的页面,但对于面向普通客户的页面,往往追求个性化的视觉效果,这种情况下用 amis 就不合适,实际上绝大部分前端 UI 组件库也都不适合,只能定制开发。
|
||||||
|
- 有极为复杂的交互,或者对交互有很特殊的要求
|
||||||
|
- 有些复杂的前端功能,比如可视化编辑器,其中有大量定制的拖拽操作,这种需要依赖原生 DOM 实现的功能无法使用 amis。
|
||||||
|
- 但对于某些交互固定的领域,比如图连线,amis 后续会有专门的组件来实现。
|
||||||
|
|
||||||
|
## 阅读建议 👆
|
||||||
|
|
||||||
|
- 如果你是第一次接触 amis 的新同学,那么请 **务必认真阅读完概念部分**,它会让你对 amis 有个整体的认识
|
||||||
|
- 如果你已经掌握 amis 基本概念,且有一定的开发经验,需要参考 amis 组件相关文档的同学,那么请移步 [组件文档](./components/component)
|
||||||
|
|
||||||
|
## 让我们马上开始吧!
|
||||||
|
|
||||||
|
点击页面底部的下一篇,继续后续部分的阅读。
|
||||||
|
|
|
@ -0,0 +1,433 @@
|
||||||
|
---
|
||||||
|
title: 自定义组件
|
||||||
|
---
|
||||||
|
|
||||||
|
如果默认的组件不能满足需求,可以通过自定义组件来进行扩展,在 amis 中有两种方法:
|
||||||
|
|
||||||
|
1. 临时扩展,适合无需复用的组件。
|
||||||
|
2. 注册自定义类型,适合需要在很多地方复用的组件。
|
||||||
|
|
||||||
|
> 注意,自定义组件只支持 npm 方式,不支持 SDK
|
||||||
|
|
||||||
|
## 临时扩展
|
||||||
|
|
||||||
|
amis 的 JSON 配置最终会转成 React 组件来执行,所以如果只是想在某个配置中加入定制功能,可以直接在这个 JSON 配置里写 React 代码,比如下面这个例子:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"title": "自定义组件示例",
|
||||||
|
"body": {
|
||||||
|
"type": "form",
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "用户名",
|
||||||
|
"name": "usename"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mycustom",
|
||||||
|
"children": ({
|
||||||
|
value,
|
||||||
|
onChange
|
||||||
|
}) => (
|
||||||
|
<div>
|
||||||
|
<p>这个是个自定义组件</p>
|
||||||
|
<p>当前值:{value}</p>
|
||||||
|
<a className="btn btn-default" onClick={
|
||||||
|
() => onChange(Math.round(Math.random() * 10000))
|
||||||
|
}>随机修改</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
其中的 `mycustom` 就是一个临时扩展,它的 `children` 属性是一个函数,它的返回内容和 React 的 Render 方法一样,即 jsx,在这个方法里你可以写任意 JavaScript 来实现自己的定制需求,这个函数有两个参数 `value` 和 `onChange`,`value` 就是组件的值,`onChange` 方法用来改变这个值,比如上面的例子中,点击链接后就会修改 `mycustom` 为一个随机数,在提交表单的时候就变成了这个随机数。
|
||||||
|
|
||||||
|
与之类似的还有个 `component` 属性,这个属性可以传入 React Component,如果想用 React Hooks,请通过 `component` 传递,而不是 `children`。
|
||||||
|
|
||||||
|
这种扩展方式既简单又灵活,但它是写在配置中的,如果需要在很多地方,可以使用下面的「注册自定义类型」方式:
|
||||||
|
|
||||||
|
## 注册自定义类型
|
||||||
|
|
||||||
|
注册自定义类型需要了解 amis 的工作原理。
|
||||||
|
|
||||||
|
### 工作原理
|
||||||
|
|
||||||
|
amis 的渲染过程是将 `json` 转成对应的 React 组件。先通过 `json` 的 type 找到对应的 `Component` 然后,然后把其他属性作为 `props` 传递过去完成渲染。
|
||||||
|
|
||||||
|
拿一个表单页面来说,如果用 React 组件开发一般长这样。
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<Page title="页面标题" subTitle="副标题">
|
||||||
|
<Form
|
||||||
|
title="用户登录"
|
||||||
|
controls={[
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'username',
|
||||||
|
label: '用户名'
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Page>
|
||||||
|
```
|
||||||
|
|
||||||
|
把以上配置方式换成 amis JSON, 则是:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"title": "页面标题",
|
||||||
|
"subTitle": "副标题",
|
||||||
|
"body": {
|
||||||
|
"type": "form",
|
||||||
|
"title": "用户登录",
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"name": "username",
|
||||||
|
"label": "用户名"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
那么,amis 是如何将 JSON 转成组件的呢?直接根据节点的 type 去跟组件一一对应?这样会重名,比如在表格里面展示的类型 `text` 跟表单里面的 `text` 是完全不一样的,一个负责展示,一个却负责输入。所以说一个节点要被什么组件渲染,还需要携带上下文(context)信息。
|
||||||
|
|
||||||
|
如何携带上下文(context)信息?amis 中是用节点的路径(path)来作为上下文信息。从上面的例子来看,一共有三个节点,path 信息分别是。
|
||||||
|
|
||||||
|
- `page` 页面节点
|
||||||
|
- `page/body/form` 表单节点
|
||||||
|
- `page/body/form/controls/0/text` 文本框节点。
|
||||||
|
|
||||||
|
根据 path 的信息就能很容易注册组件跟节点对应了。
|
||||||
|
|
||||||
|
Page 组件的示例代码
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
@Renderer({
|
||||||
|
test: /^page$/
|
||||||
|
// ... 其他信息隐藏了
|
||||||
|
})
|
||||||
|
export class PageRenderer extends React.Component {
|
||||||
|
// ... 其他信息隐藏了
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
render // 用来渲染孩子节点,如果当前是叶子节点则可以忽略。
|
||||||
|
} = this.props;
|
||||||
|
return (
|
||||||
|
<div className="page">
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<div className="body-container">
|
||||||
|
{render('body', body) /*渲染孩子节点*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Form 组件的示例代码
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
@Renderer({
|
||||||
|
test: /(^|\/)form$/
|
||||||
|
// ... 其他信息隐藏了
|
||||||
|
})
|
||||||
|
export class FormRenderer extends React.Component {
|
||||||
|
// ... 其他信息隐藏了
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
controls,
|
||||||
|
render // 用来渲染孩子节点,如果当前是叶子节点则可以忽略。
|
||||||
|
} = this.props;
|
||||||
|
return (
|
||||||
|
<form className="form">
|
||||||
|
{controls.map((control, index) => (
|
||||||
|
<div className="form-item" key={index}>
|
||||||
|
{render(`${index}/control`, control)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Text 组件的示例代码
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
@Renderer({
|
||||||
|
test: /(^|\/)form(?:\/\d+)?\/control(?\/\d+)?\/text$/
|
||||||
|
// ... 其他信息隐藏了
|
||||||
|
})
|
||||||
|
export class FormItemTextRenderer extends React.Component {
|
||||||
|
// ... 其他信息隐藏了
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
onChange
|
||||||
|
} = this.props;
|
||||||
|
return (
|
||||||
|
<div className="form-group">
|
||||||
|
<label>{label}<label>
|
||||||
|
<input type="text" onChange={(e) => onChange(e.currentTarget.value)} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
那么渲染过程就是根据节点 path 信息,跟组件池中的组件 `test` (检测) 信息做匹配,如果命中,则把当前节点转给对应组件渲染,节点中其他属性将作为目标组件的 props。需要注意的是,如果是容器组件,比如以上例子中的 `page` 组件,从 props 中拿到的 `body` 是一个子节点,由于节点类型是不固定,由使用者决定,所以不能直接完成渲染,所以交给属性中下发的 `render` 方法去完成渲染,`{render('body', body)}`,他的工作就是拿子节点的 path 信息去组件池里面找到对应的渲染器,然后交给对应组件去完成渲染。
|
||||||
|
|
||||||
|
### 编写自定义组件
|
||||||
|
|
||||||
|
了解了基本原理后,来看个简单的例子:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import * as React from 'react';
|
||||||
|
import {Renderer} from 'amis';
|
||||||
|
|
||||||
|
@Renderer({
|
||||||
|
test: /(^|\/)my\-renderer$/
|
||||||
|
})
|
||||||
|
class CustomRenderer extends React.Component {
|
||||||
|
render() {
|
||||||
|
const {tip} = this.props;
|
||||||
|
return <div>这是自定义组件:{tip}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
有了以上这段代码后,就可以这样使用了。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"title": "自定义组件示例",
|
||||||
|
"body": {
|
||||||
|
"type": "my-renderer",
|
||||||
|
"tip": "简单示例"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
看了前面[amis 工作原理](#工作原理)应该不难理解,这里注册一个 React 组件,当节点的 path 信息是 `my-renderer` 结尾时,交给当前组件来完成渲染。
|
||||||
|
|
||||||
|
如果这个组件还能通过 `children` 属性添加子节点,则需要使用下面这种写法:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import * as React from 'react';
|
||||||
|
import {Renderer} from 'amis';
|
||||||
|
|
||||||
|
@Renderer({
|
||||||
|
test: /(^|\/)my\-renderer2$/
|
||||||
|
})
|
||||||
|
class CustomRenderer extends React.Component {
|
||||||
|
render() {
|
||||||
|
const {tip, body, render} = this.props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>这是自定义组件:{tip}</p>
|
||||||
|
{body ? (
|
||||||
|
<div className="container">
|
||||||
|
{render('body', body, {
|
||||||
|
// 这里的信息会作为 props 传递给子组件,一般情况下都不需要这个
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
有了以上这段代码后,就可以这样使用了。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"title": "自定义组件示例",
|
||||||
|
"body": {
|
||||||
|
"type": "my-renderer2",
|
||||||
|
"tip": "简单示例",
|
||||||
|
"body": {
|
||||||
|
"type": "form",
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "用户名",
|
||||||
|
"name": "usename"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
跟第一个列子不同的地方是,这里多了个 `render` 方法,这个方法就是专门用来渲染子节点的。来看下参数说明:
|
||||||
|
|
||||||
|
- `region` 区域名称,你有可能有多个区域可以作为容器,请不要重复。
|
||||||
|
- `node` 子节点。
|
||||||
|
- `props` 可选,可以通过此对象跟子节点通信等。
|
||||||
|
|
||||||
|
### 表单项的扩展
|
||||||
|
|
||||||
|
以上是普通渲染器的注册方式,如果是表单项,为了更简单的扩充,请使用 `FormItem` 注解,而不是 `Renderer`。 原因是如果用 `FormItem` 是不用关心:label 怎么摆,表单验证器怎么实现,如何适配表单的 3 中展现方式(水平、上下和内联模式),而只用关心:有了值后如何回显,响应用户交互设置新值。
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import * as React from 'react';
|
||||||
|
import {FormItem} from 'amis';
|
||||||
|
|
||||||
|
@FormItem({
|
||||||
|
type: 'custom'
|
||||||
|
})
|
||||||
|
class MyFormItem extends React.Component {
|
||||||
|
render() {
|
||||||
|
const {value, onChange} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>这个是个自定义组件</p>
|
||||||
|
<p>当前值:{value}</p>
|
||||||
|
<a
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={() => onChange(Math.round(Math.random() * 10000))}
|
||||||
|
>
|
||||||
|
随机修改
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
有了以上这段代码后,就可以这样使用了。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"title": "自定义组件示例",
|
||||||
|
"body": {
|
||||||
|
"type": "form",
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "用户名",
|
||||||
|
"name": "usename"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "custom",
|
||||||
|
"label": "随机值",
|
||||||
|
"name": "random"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 注意: 使用 FormItem 默认是严格模式,即只有必要的属性变化才会重新渲染,有可能满足不了你的需求,如果忽略性能问题,可以传入 `strictMode`: `false` 来关闭。
|
||||||
|
|
||||||
|
表单项开发主要关心两件事。
|
||||||
|
|
||||||
|
1. 呈现当前值。如以上例子,通过 `this.props.value` 判定如果勾选了则显示`已勾选`,否则显示`请勾选`。
|
||||||
|
2. 接收用户交互,通过 `this.props.onChange` 修改表单项值。如以上例子,当用户点击按钮时,切换当前选中的值。
|
||||||
|
|
||||||
|
至于其他功能如:label/description 的展示、表单验证功能、表单布局(常规、左右或者内联)等等,只要是通过 FormItem 注册进去的都无需自己实现。
|
||||||
|
|
||||||
|
需要注意,获取或者修改的是什么值跟配置中 `type` 并列的 `name` 属性有关,也就是说直接关联某个变量,自定义中直接通过 props 下发了某个指定变量的值和修改的方法。如果你想获取其他数据,或者设置其他数据可以看下以下说明:
|
||||||
|
|
||||||
|
- `获取其他数据` 可以通过 `this.props.data` 查看,作用域中所有的数据都在这了。
|
||||||
|
- `设置其他数据` 可以通过 `this.props.onBulkChange`, 比如: `this.props.onBulkChange({a: 1, b: 2})` 等于同时设置了两个值。当做数据填充的时候,这个方法很有用。
|
||||||
|
|
||||||
|
### 其它高级定制
|
||||||
|
|
||||||
|
下面是一些不太常用的 amis 扩展方式及技巧。
|
||||||
|
|
||||||
|
#### 自定义验证器
|
||||||
|
|
||||||
|
如果 amis [自带的验证](./renderers/Form/FormItem.md#)能满足需求了,则不需要关心。组件可以有自己的验证逻辑。
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import * as React from 'react';
|
||||||
|
import {FormItem} from 'amis';
|
||||||
|
import * as cx from 'classnames';
|
||||||
|
|
||||||
|
@FormItem({
|
||||||
|
type: 'custom-checkbox'
|
||||||
|
})
|
||||||
|
export default class CustomCheckbox extends React.Component {
|
||||||
|
validate() {
|
||||||
|
// 通过 this.props.value 可以知道当前值。
|
||||||
|
|
||||||
|
return isValid ? '' : '不合法,说明不合法原因。';
|
||||||
|
}
|
||||||
|
// ... 其他省略了
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上面的栗子只是简单说明,另外可以做`异步验证`,validate 方法可以返回一个 promise。
|
||||||
|
|
||||||
|
#### OptionsControl
|
||||||
|
|
||||||
|
如果你的表单组件性质和 amis 的 Select、Checkboxes、List 差不多,用户配置配置 source 可通过 API 拉取选项,你可以用 OptionsControl 取代 FormItem 这个注解。
|
||||||
|
|
||||||
|
用法是一样,功能方面主要多了以下功能。
|
||||||
|
|
||||||
|
- 可以配置 options,options 支持配置 visibleOn hiddenOn 等表达式
|
||||||
|
- 可以配置 `source` 换成动态拉取 options 的功能,source 中有变量依赖会自动重新拉取。
|
||||||
|
- 下发了这些 props,可以更方便选项。
|
||||||
|
- `options` 不管是用户配置的静态 options 还是配置 source 拉取的,下发到组件已经是最终的选项了。
|
||||||
|
- `selectedOptions` 数组类型,当前用户选中的选项。
|
||||||
|
- `loading` 当前选项是否在加载
|
||||||
|
- `onToggle` 切换一个选项的值
|
||||||
|
- `onToggleAll` 切换所有选项的值,类似于全选。
|
||||||
|
|
||||||
|
#### 组件间通信
|
||||||
|
|
||||||
|
关于组件间通信,amis 中有个机制就是,把需要被引用的组件设置一个 name 值,然后其他组件就可以通过这个 name 与其通信,比如这个[栗子](./advanced.md#组件间通信)。其实内部是依赖于内部的一个 Scoped Context。你的组件希望可以被别的组件引用,你需要把自己注册进去,默认自定义的非表单类组件并没有把自己注册进去,可以参考以下代码做添加。
|
||||||
|
|
||||||
|
```js
|
||||||
|
import * as React from 'react';
|
||||||
|
import {Renderer, ScopedContext} from 'amis';
|
||||||
|
@Renderer({
|
||||||
|
test: /(?:^|\/)my\-renderer$/
|
||||||
|
})
|
||||||
|
export class CustomRenderer extends React.Component {
|
||||||
|
static contextType = ScopedContext;
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
const scoped = this.context;
|
||||||
|
scoped.registerComponent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
const scoped = this.context;
|
||||||
|
scoped.unRegisterComponent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他部分省略了。
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
把自己注册进去了,其他组件就能引用到了。同时,如果你想找别的组件,也同样是通过 scoped 这个 context,如: `scoped.getComponentByName("xxxName")` 这样就能拿到目标组件的实例了(前提是目标组件已经配置了 name 为 `xxxName`)。
|
||||||
|
|
||||||
|
#### 其他功能方法
|
||||||
|
|
||||||
|
自定义的渲染器 props 会下发一个非常有用的 env 对象。这个 env 有以下功能方法。
|
||||||
|
|
||||||
|
- `env.fetcher` 可以用来做 ajax 请求如: `this.props.env.fetcher('xxxAPi', this.props.data).then((result) => console.log(result))`
|
||||||
|
- `env.confirm` 确认框,返回一个 promise 等待用户确认如: `this.props.env.confirm('你确定要这么做?').then((confirmed) => console.log(confirmed))`
|
||||||
|
- `env.alert` 用 Modal 实现的弹框,个人觉得更美观。
|
||||||
|
- `env.notify` toast 某个消息 如: `this.props.env.notify("error", "出错了")`
|
||||||
|
- `env.jumpTo` 页面跳转。
|
|
@ -1,215 +0,0 @@
|
||||||
---
|
|
||||||
title: 起步
|
|
||||||
description: ddsaad
|
|
||||||
type: 0
|
|
||||||
group: 💡 概念
|
|
||||||
menuName: 起步
|
|
||||||
icon:
|
|
||||||
order: 8
|
|
||||||
---
|
|
||||||
## 什么是 amis
|
|
||||||
|
|
||||||
amis 是一个前端低代码框架,它使用 JSON 配置来生成页面,可以极大节省页面开发工作量,极大提升开发前端界面的效率。
|
|
||||||
|
|
||||||
## 为什么要做 amis?🤔
|
|
||||||
|
|
||||||
在经历了十几年的发展后,前端开发变得越来越复杂,门槛也越来越高,要使用当下流行的 UI 组件库,你必须懂 npm、webpack、react/vue,必须熟悉 ES 6 语法,最好还了解状态管理,比如 Redux,如果没接触过函数式编程,一开始入门就很困难,而它还有巨大的 [生态](https://github.com/markerikson/redux-ecosystem-links),相关的库有 2347 个,然而前端技术的发展不会停滞,等学完这些后可能会发现大家都用 Hooks 了、某个打包工具取代 WebPack 了。。。
|
|
||||||
|
|
||||||
而有时候你只是为了做个普通的增删改查界面,用于系统管理,类似下面这种:
|
|
||||||
|
|
||||||
```schema:height="900"
|
|
||||||
{
|
|
||||||
"title": "浏览器内核对 CSS 的支持情况",
|
|
||||||
"remark": "嘿,不保证数据准确性",
|
|
||||||
"type": "page",
|
|
||||||
"body": {
|
|
||||||
"type": "crud",
|
|
||||||
"draggable": true,
|
|
||||||
"api": "https://houtai.baidu.com/api/sample",
|
|
||||||
"keepItemSelectionOnPageChange": true,
|
|
||||||
"filter": {
|
|
||||||
"title": "筛选",
|
|
||||||
"submitText": "",
|
|
||||||
"controls": [
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"name": "keywords",
|
|
||||||
"placeholder": "关键字",
|
|
||||||
"addOn": {
|
|
||||||
"label": "搜索",
|
|
||||||
"type": "submit"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"bulkActions": [
|
|
||||||
{
|
|
||||||
"label": "批量删除",
|
|
||||||
"actionType": "ajax",
|
|
||||||
"api": "delete:https://houtai.baidu.com/api/sample/${ids|raw}",
|
|
||||||
"confirmText": "确定要批量删除?"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "批量修改",
|
|
||||||
"actionType": "dialog",
|
|
||||||
"dialog": {
|
|
||||||
"title": "批量编辑",
|
|
||||||
"name": "sample-bulk-edit",
|
|
||||||
"body": {
|
|
||||||
"type": "form",
|
|
||||||
"api": "https://houtai.baidu.com/api/sample/bulkUpdate2",
|
|
||||||
"controls": [
|
|
||||||
{
|
|
||||||
"type": "hidden",
|
|
||||||
"name": "ids"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"name": "engine",
|
|
||||||
"label": "Engine"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"quickSaveApi": "https://houtai.baidu.com/api/sample/bulkUpdate",
|
|
||||||
"quickSaveItemApi": "https://houtai.baidu.com/api/sample/$id",
|
|
||||||
"filterTogglable": true,
|
|
||||||
"headerToolbar": [
|
|
||||||
"filter-toggler",
|
|
||||||
"bulkActions",
|
|
||||||
{
|
|
||||||
"type": "tpl",
|
|
||||||
"tpl": "一共有 ${count} 行数据。",
|
|
||||||
"className": "v-middle"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "columns-toggler",
|
|
||||||
"align": "right"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "drag-toggler",
|
|
||||||
"align": "right"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "pagination",
|
|
||||||
"align": "right"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"footerToolbar": [
|
|
||||||
"statistics",
|
|
||||||
"switch-per-page",
|
|
||||||
"pagination"
|
|
||||||
],
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "id",
|
|
||||||
"label": "ID",
|
|
||||||
"width": 20,
|
|
||||||
"sortable": true,
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "engine",
|
|
||||||
"label": "Rendering engine",
|
|
||||||
"sortable": true,
|
|
||||||
"searchable": true,
|
|
||||||
"type": "text",
|
|
||||||
"remark": "Trident 就是 IE,Gecko 就是 Firefox"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "platform",
|
|
||||||
"label": "Platform(s)",
|
|
||||||
"popOver": {
|
|
||||||
"body": {
|
|
||||||
"type": "tpl",
|
|
||||||
"tpl": "就是为了演示有个叫 popOver 的功能"
|
|
||||||
},
|
|
||||||
"offset": {
|
|
||||||
"y": 50
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sortable": true,
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "grade",
|
|
||||||
"label": "CSS grade",
|
|
||||||
"quickEdit": {
|
|
||||||
"mode": "inline",
|
|
||||||
"type": "select",
|
|
||||||
"options": [
|
|
||||||
"A",
|
|
||||||
"B",
|
|
||||||
"C",
|
|
||||||
"D",
|
|
||||||
"X"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "operation",
|
|
||||||
"label": "操作",
|
|
||||||
"width": 100,
|
|
||||||
"buttons": [
|
|
||||||
{
|
|
||||||
"type": "button",
|
|
||||||
"icon": "fa fa-times text-danger",
|
|
||||||
"actionType": "ajax",
|
|
||||||
"tooltip": "删除",
|
|
||||||
"confirmText": "您确认要删除?",
|
|
||||||
"api": "delete:https://houtai.baidu.com/api/sample/$id"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
这个界面虽然用 Bootstrap 也能快速搭起来,但要想体验好就需要加很多细节功能,比如数据动态加载、编辑单行数据、批量删除和修改、查询某列、按某列排序、隐藏某列、开启整页内容拖拽排序、表格有分页(页数还会同步到地址栏,刷新页面试试)、如果往下拖动还有首行冻结来方便查看表头等,全部实现这些需要大量的代码。
|
|
||||||
|
|
||||||
然而上面也看到了,在 amis 里只需要 150 行 JSON 配置(嘿,其中 40 多行只有一个括号),你不需要了解 `React/Vue`、`Webpack`,甚至不需要了解 `JavaScript`,即便没学过 amis 也能猜到大部分配置的作用,只需要简单配置就能完成所有页面开发,这正是建立 amis 的初衷,我们认为**对于大部分常用页面,应该使用最简单的方法来实现**,而不是越来越复杂。
|
|
||||||
|
|
||||||
## 用 JSON 写页面有什么好处❓
|
|
||||||
|
|
||||||
为了实现用最简单方式来生成大部分页面,amis 的解决方案是基于 JSON 来配置,它的独特好处是:
|
|
||||||
|
|
||||||
- **不需要懂前端**就能做出专业且复杂的后台界面,这是所有其他前端 UI 库都无法做到的。在百度内部,大部分 amis 用户之前从来没写过前端页面,也不会 `JavaScript`。
|
|
||||||
- **不受前端技术更新的影响**,同时还能享受 amis 升级带来的界面改进,百度内部最老的 amis 页面是 4 年多前创建的,至今还在使用,而当年的 `Angular/Vue/React` 版本现在都废弃了,当年流行的 `Gulp` 也被 `Webpack` 取代了,如果这些页面不是用 amis,现在的维护成本会很高。
|
|
||||||
- 可以**完全**使用 [可视化页面编辑器](https://fex-team.github.io/amis-editor/#/edit/0) 来制作页面,一般前端可视化编辑器只能用来做静态原型,而 amis 可视化编辑器做出的页面是可以直接上线的。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
> JSON 是一种轻量级的数据交换格式,简洁和清晰的层次结构使得它成为理想的数据交换语言。它易于人阅读和编写,同时也易于机器解析和生成,能够有效地提升网络传输效率。
|
|
||||||
>
|
|
||||||
> 更多关于 JSON 的知识,可以阅读[百度百科](https://baike.baidu.com/item/JSON)
|
|
||||||
|
|
||||||
## amis 的其它亮点✨
|
|
||||||
|
|
||||||
- **提供完整的界面解决方案**,其它 UI 框架必须使用 JavaScript 来组装业务逻辑,而 amis 只需 JSON 配置就能完成完整功能开发,包括数据获取、表单提交及验证等功能。
|
|
||||||
- 内置 **92** 种 UI 组件,包括其它 UI 框架都会不提供的富文本编辑器、代码编辑器等,能满足各种页面组件展现的需求,而且对于特殊的展现形式还可以通过[自定义组件](./custom.md)来扩充。
|
|
||||||
- 容器组件支持**无限层级嵌套**,可以通过组合来满足各种布局需求。
|
|
||||||
- 经历了长时间的实战考验,amis 在百度内部得到了广泛使用,在 4 年多的时间里创建了 3w 多页面,从内容审核到机器管理,从数据分析到模型训练,amis 满足了各种各样的页面需求。
|
|
||||||
|
|
||||||
## amis 不适合做什么?😶
|
|
||||||
|
|
||||||
使用 JSON 有优点但也有明显缺点,在以下场合并不适合 amis:
|
|
||||||
|
|
||||||
- 大量定制 UI,尤其是面向普通客户(toC)的产品页面
|
|
||||||
- JSON 配置使得 amis 更适合做有大量常见 UI 组件的页面,但对于面向普通客户的页面,往往追求个性化的视觉效果,这种情况下用 amis 就不合适,实际上绝大部分前端 UI 组件库也都不适合,只能定制开发。
|
|
||||||
- 有极为复杂的交互,或者对交互有很特殊的要求
|
|
||||||
- 有些复杂的前端功能,比如可视化编辑器,其中有大量定制的拖拽操作,这种需要依赖原生 DOM 实现的功能无法使用 amis。
|
|
||||||
- 但对于某些交互固定的领域,比如图连线,amis 后续会有专门的组件来实现。
|
|
||||||
|
|
||||||
## 阅读建议👆
|
|
||||||
|
|
||||||
- 如果你是第一次接触 amis 的新同学,那么请**务必认真阅读完概念部分**,它会让你对 amis 有个整体的认识
|
|
||||||
- 如果你已经掌握 amis 基本概念,且有一定的开发经验,需要参考 amis 组件相关文档的同学,那么请移步 [组件文档](./component)
|
|
||||||
|
|
||||||
## 让我们马上开始吧!
|
|
||||||
|
|
||||||
点击页面底部的下一篇,继续概念部分的阅读。
|
|
||||||
|
|
|
@ -0,0 +1,280 @@
|
||||||
|
---
|
||||||
|
title: 快速开始
|
||||||
|
description:
|
||||||
|
---
|
||||||
|
|
||||||
|
## 速搭
|
||||||
|
|
||||||
|
suda
|
||||||
|
|
||||||
|
## npm
|
||||||
|
|
||||||
|
### 安装
|
||||||
|
|
||||||
|
```
|
||||||
|
npm i amis
|
||||||
|
```
|
||||||
|
|
||||||
|
### 使用说明
|
||||||
|
|
||||||
|
可以在 React Component 这么使用(TypeScript)。
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import * as React from 'react';
|
||||||
|
import {
|
||||||
|
render as renderAmis
|
||||||
|
} from 'amis';
|
||||||
|
|
||||||
|
class MyComponent extends React.Component<any, any> {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>通过 amis 渲染页面</p>
|
||||||
|
{renderAmis({
|
||||||
|
// schema
|
||||||
|
// 这里是 amis 的 Json 配置。
|
||||||
|
type: 'page',
|
||||||
|
title: '简单页面',
|
||||||
|
body: '内容'
|
||||||
|
}, {
|
||||||
|
// props
|
||||||
|
}, {
|
||||||
|
// env
|
||||||
|
// 这些是 amis 需要的一些接口实现
|
||||||
|
// 可以参考本项目里面的 Demo 部分代码。
|
||||||
|
|
||||||
|
updateLocation: (location:string/*目标地址*/, replace:boolean/*是replace,还是push?*/) => {
|
||||||
|
// 用来更新地址栏
|
||||||
|
},
|
||||||
|
|
||||||
|
jumpTo: (location:string/*目标地址*/) => {
|
||||||
|
// 页面跳转, actionType: link、url 都会进来。
|
||||||
|
},
|
||||||
|
|
||||||
|
fetcher: ({
|
||||||
|
url,
|
||||||
|
method,
|
||||||
|
data,
|
||||||
|
config
|
||||||
|
}:{
|
||||||
|
url:string/*目标地址*/,
|
||||||
|
method:'get' | 'post' | 'put' | 'delete'/*发送方式*/,
|
||||||
|
data: object | void/*数据*/,
|
||||||
|
config: object/*其他配置*/
|
||||||
|
}) => {
|
||||||
|
// 用来发送 Ajax 请求,建议使用 axios
|
||||||
|
},
|
||||||
|
notify: (type:'error'|'success'/**/, msg:string/*提示内容*/) => {
|
||||||
|
// 用来提示用户
|
||||||
|
},
|
||||||
|
alert: (content:string/*提示信息*/) => {
|
||||||
|
// 另外一种提示,可以直接用系统框
|
||||||
|
},
|
||||||
|
confirm: (content:string/*提示信息*/) => {
|
||||||
|
// 确认框。
|
||||||
|
}
|
||||||
|
});}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`(schema:Schema, props?:any, env?: any) => JSX.Element`
|
||||||
|
|
||||||
|
参数说明:
|
||||||
|
|
||||||
|
- `schema` 即页面配置,请前往[基本用法](./basic.md)了解.
|
||||||
|
- `props` 一般都用不上,如果你想传递一些数据给渲染器内部使用,可以传递 data 数据进去。如:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
() =>
|
||||||
|
renderAmis(schema, {
|
||||||
|
data: {
|
||||||
|
username: 'amis'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
这样,内部所有组件都能拿到 `username` 这个变量的值。
|
||||||
|
|
||||||
|
- `env` 环境变量,可以理解为这个渲染器工具的配置项,需要调用者实现部分接口。
|
||||||
|
|
||||||
|
- `session: string` 默认为 'global',决定 store 是否为全局共用的,如果想单占一个 store,请设置不同的值。
|
||||||
|
- `fetcher: (config: fetcherConfig) => Promise<fetcherResult>` 用来实现 ajax 发送。
|
||||||
|
|
||||||
|
示例
|
||||||
|
|
||||||
|
```js
|
||||||
|
fetcher: ({
|
||||||
|
url,
|
||||||
|
method,
|
||||||
|
data,
|
||||||
|
responseType,
|
||||||
|
config,
|
||||||
|
headers
|
||||||
|
}: any) => {
|
||||||
|
config = config || {};
|
||||||
|
config.withCredentials = true;
|
||||||
|
responseType && (config.responseType = responseType);
|
||||||
|
|
||||||
|
if (config.cancelExecutor) {
|
||||||
|
config.cancelToken = new (axios as any).CancelToken(config.cancelExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.headers = headers || {};
|
||||||
|
|
||||||
|
if (method !== 'post' && method !== 'put' && method !== 'patch') {
|
||||||
|
if (data) {
|
||||||
|
config.params = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (axios as any)[method](url, config);
|
||||||
|
} else if (data && data instanceof FormData) {
|
||||||
|
// config.headers = config.headers || {};
|
||||||
|
// config.headers['Content-Type'] = 'multipart/form-data';
|
||||||
|
} else if (data
|
||||||
|
&& typeof data !== 'string'
|
||||||
|
&& !(data instanceof Blob)
|
||||||
|
&& !(data instanceof ArrayBuffer)
|
||||||
|
) {
|
||||||
|
data = JSON.stringify(data);
|
||||||
|
// config.headers = config.headers || {};
|
||||||
|
config.headers['Content-Type'] = 'application/json';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (axios as any)[method](url, data, config);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `isCancel: (e:error) => boolean` 判断 ajax 异常是否为一个 cancel 请求。
|
||||||
|
|
||||||
|
示例
|
||||||
|
|
||||||
|
```js
|
||||||
|
isCancel: (value: any) => (axios as any).isCancel(value)
|
||||||
|
```
|
||||||
|
|
||||||
|
- `notify: (type:string, msg: string) => void` 用来实现消息提示。
|
||||||
|
- `alert: (msg:string) => void` 用来实现警告提示。
|
||||||
|
- `confirm: (msg:string) => boolean | Promise<boolean>` 用来实现确认框。
|
||||||
|
- `jumpTo: (to:string, action?: Action, ctx?: object) => void` 用来实现页面跳转,因为不清楚所在环境中是否使用了 spa 模式,所以用户自己实现吧。
|
||||||
|
- `updateLocation: (location:any, replace?:boolean) => void` 地址替换,跟 jumpTo 类似。
|
||||||
|
- `isCurrentUrl: (link:string) => boolean` 判断目标地址是否为当前页面。
|
||||||
|
- `theme: 'default' | 'cxd'` 目前支持两种主题。
|
||||||
|
- `copy: (contents:string, options?: {shutup: boolean}) => void` 用来实现,内容复制。
|
||||||
|
- `getModalContainer: () => HTMLElement` 用来决定弹框容器。
|
||||||
|
- `loadRenderer: (chema:any, path:string) => Promise<Function>` 可以通过它懒加载自定义组件,比如: https://github.com/baidu/amis/blob/master/__tests__/factory.test.tsx#L64-L91。
|
||||||
|
- `affixOffsetTop: number` 固顶间距,当你的有其他固顶元素时,需要设置一定的偏移量,否则会重叠。
|
||||||
|
- `affixOffsetBottom: number` 固底间距,当你的有其他固底元素时,需要设置一定的偏移量,否则会重叠。
|
||||||
|
- `richTextToken: string` 内置 rich-text 为 frolaEditor,想要使用,请自行购买,或者自己实现 rich-text 渲染器。
|
||||||
|
|
||||||
|
## SDK
|
||||||
|
|
||||||
|
SDK 适合对前端或 React 不了解的开发者,它不依赖 npm 及 webpack,直接引入代码就能使用,但需要注意这种方式不支持[定制组件](../sdk),只能使用 amis 内置的组件。
|
||||||
|
|
||||||
|
JSSDK 的代码从以下地址获取:
|
||||||
|
|
||||||
|
- JS: https://houtai.baidu.com/v2/jssdk
|
||||||
|
- CSS: https://houtai.baidu.com/v2/csssdk
|
||||||
|
|
||||||
|
然后在页面中插入下面的代码就能渲染出来了:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(function () {
|
||||||
|
var amis = amisRequire('amis/embed');
|
||||||
|
amis.embed(
|
||||||
|
'#container',
|
||||||
|
{
|
||||||
|
type: 'page',
|
||||||
|
title: 'AMIS Demo',
|
||||||
|
body: 'This is a simple amis page.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// props 一般不用传。
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// env
|
||||||
|
fetcher: () => {
|
||||||
|
// 可以不传,用来实现 ajax 请求
|
||||||
|
},
|
||||||
|
|
||||||
|
jumpTo: () => {
|
||||||
|
// 可以不传,用来实现页面跳转
|
||||||
|
},
|
||||||
|
|
||||||
|
updateLocation: () => {
|
||||||
|
// 可以不传,用来实现地址栏更新
|
||||||
|
},
|
||||||
|
|
||||||
|
isCurrentUrl: () => {
|
||||||
|
// 可以不传,用来判断是否目标地址当前地址。
|
||||||
|
},
|
||||||
|
|
||||||
|
copy: () => {
|
||||||
|
// 可以不传,用来实现复制到剪切板
|
||||||
|
},
|
||||||
|
|
||||||
|
notify: () => {
|
||||||
|
// 可以不传,用来实现通知
|
||||||
|
},
|
||||||
|
|
||||||
|
alert: () => {
|
||||||
|
// 可以不传,用来实现提示
|
||||||
|
},
|
||||||
|
|
||||||
|
confirm: () => {
|
||||||
|
// 可以不传,用来实现确认框。
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:以上的 SDK 地址是一个页面跳转,会跳转到一个 CDN 地址,而且每次跳转都是最新的版本,随着 amis 的升级这个地址会一直变动,如果你的页面已经完成功能回归,请直接使用某个固定地址,这样才不会因为 amis 升级而导致你的页面不可用。
|
||||||
|
|
||||||
|
另外,sdk 代码也伴随 npm 一起发布了,不使用 CDN 版本,直接替换成 npm 包里面的 `amis/sdk.js` 和 `amis/sdk.css` 即可。
|
||||||
|
|
||||||
|
完整示例:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>AMIS Demo</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, maximum-scale=1"
|
||||||
|
/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||||
|
<link rel="stylesheet" href="amis/sdk.css" />
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
.app-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root" class="app-wrapper"></div>
|
||||||
|
<script src="amis/sdk.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function () {
|
||||||
|
var amis = amisRequire('amis/embed');
|
||||||
|
amis.embed('#root', {
|
||||||
|
type: 'page',
|
||||||
|
title: 'AMIS Demo',
|
||||||
|
body: 'hello world'
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
|
@ -7,6 +7,7 @@ menuName: API
|
||||||
icon:
|
icon:
|
||||||
order: 20
|
order: 20
|
||||||
---
|
---
|
||||||
|
|
||||||
API 类型用于配置请求接口的格式,涉及请求方式、请求地址、请求数据体等等相关配置
|
API 类型用于配置请求接口的格式,涉及请求方式、请求地址、请求数据体等等相关配置
|
||||||
|
|
||||||
## 简单配置
|
## 简单配置
|
||||||
|
@ -16,17 +17,18 @@ API 类型用于配置请求接口的格式,涉及请求方式、请求地址
|
||||||
```
|
```
|
||||||
[<method>:]<url>
|
[<method>:]<url>
|
||||||
```
|
```
|
||||||
- **method**:get、post、put、delete,默认为get
|
|
||||||
|
- **method**:get、post、put、delete,默认为 get
|
||||||
- **url**:接口地址,即模板字符串
|
- **url**:接口地址,即模板字符串
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"api": "get:/api/initData", // get 请求
|
"api": "get:/api/initData", // get 请求
|
||||||
"api": "post:/api/initData", // post 请求
|
"api": "post:/api/initData", // post 请求
|
||||||
"api": "put:/api/initData", // put 请求
|
"api": "put:/api/initData", // put 请求
|
||||||
"api": "delete:/api/initData", // delete 请求
|
"api": "delete:/api/initData" // delete 请求
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -56,7 +58,8 @@ API 类型用于配置请求接口的格式,涉及请求方式、请求地址
|
||||||
{
|
{
|
||||||
"status": 0,
|
"status": 0,
|
||||||
"msg": "",
|
"msg": "",
|
||||||
"data": { // 正确
|
"data": {
|
||||||
|
// 正确
|
||||||
"text": "World!"
|
"text": "World!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +160,7 @@ API 还支持配置对象类型
|
||||||
|
|
||||||
可以配置`dataType`,来指定请求的数据体格式,默认为`json`
|
可以配置`dataType`,来指定请求的数据体格式,默认为`json`
|
||||||
|
|
||||||
> 下面例子中api没有配置`data`属性,因为`form`会默认将所有表单项的值进行提交。
|
> 下面例子中 api 没有配置`data`属性,因为`form`会默认将所有表单项的值进行提交。
|
||||||
|
|
||||||
#### application/json
|
#### application/json
|
||||||
|
|
||||||
|
@ -346,7 +349,7 @@ API 还支持配置对象类型
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
查看 **选项2** 的`source`属性,他是API类型值,支持配置`sendOn` [表达式](./expression),实现根据条件请求接口。
|
查看 **选项 2** 的`source`属性,他是 API 类型值,支持配置`sendOn` [表达式](./expression),实现根据条件请求接口。
|
||||||
|
|
||||||
### 配置接口缓存
|
### 配置接口缓存
|
||||||
|
|
||||||
|
@ -408,13 +411,13 @@ API 还支持配置对象类型
|
||||||
|
|
||||||
### 配置请求适配器
|
### 配置请求适配器
|
||||||
|
|
||||||
amis的API配置,如果无法配置出你想要的请求结构,那么可以配置`requestAdaptor`发送适配器
|
amis 的 API 配置,如果无法配置出你想要的请求结构,那么可以配置`requestAdaptor`发送适配器
|
||||||
|
|
||||||
**发送适配器**是指在接口请求前,对请求进行一些自定义处理,例如修改发送数据体、添加请求头、等等,基本用法是,获取暴露的`api`参数,并且对该参数进行一些修改,并`return`出去:
|
**发送适配器**是指在接口请求前,对请求进行一些自定义处理,例如修改发送数据体、添加请求头、等等,基本用法是,获取暴露的`api`参数,并且对该参数进行一些修改,并`return`出去:
|
||||||
|
|
||||||
#### 字符串形式
|
#### 字符串形式
|
||||||
|
|
||||||
如果在JSON文件中配置的话,`requestAdaptor`只支持字符串形式,如下:
|
如果在 JSON 文件中配置的话,`requestAdaptor`只支持字符串形式,如下:
|
||||||
|
|
||||||
```schema:height="330" scope="body"
|
```schema:height="330" scope="body"
|
||||||
{
|
{
|
||||||
|
@ -443,17 +446,17 @@ amis的API配置,如果无法配置出你想要的请求结构,那么可以
|
||||||
|
|
||||||
```js
|
```js
|
||||||
return {
|
return {
|
||||||
...api,
|
...api,
|
||||||
data: {
|
data: {
|
||||||
...api.data, // 获取暴露的 api 中的 data 变量
|
...api.data, // 获取暴露的 api 中的 data 变量
|
||||||
foo: 'bar' // 新添加数据
|
foo: 'bar' // 新添加数据
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数形式
|
#### 函数形式
|
||||||
|
|
||||||
如果你的使用环境为js文件,则可以直接传入函数,如下:
|
如果你的使用环境为 js 文件,则可以直接传入函数,如下:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const schema = {
|
const schema = {
|
||||||
|
@ -461,7 +464,7 @@ const schema = {
|
||||||
api: {
|
api: {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: 'https://houtai.baidu.com/api/mock2/form/saveForm',
|
url: 'https://houtai.baidu.com/api/mock2/form/saveForm',
|
||||||
requestAdaptor: function(api) {
|
requestAdaptor: function (api) {
|
||||||
return {
|
return {
|
||||||
...api,
|
...api,
|
||||||
data: {
|
data: {
|
||||||
|
@ -499,53 +502,52 @@ const schema = {
|
||||||
|
|
||||||
### 配置接收适配器
|
### 配置接收适配器
|
||||||
|
|
||||||
同样的,如果后端返回的响应结构不符合amis的[接口格式要求](./types-api#%E6%8E%A5%E5%8F%A3%E8%BF%94%E5%9B%9E%E6%A0%BC%E5%BC%8F-%E9%87%8D%E8%A6%81-),而后端不方便调整时,可以配置`adaptor`实现接收适配器
|
同样的,如果后端返回的响应结构不符合 amis 的[接口格式要求](./types-api#%E6%8E%A5%E5%8F%A3%E8%BF%94%E5%9B%9E%E6%A0%BC%E5%BC%8F-%E9%87%8D%E8%A6%81-),而后端不方便调整时,可以配置`adaptor`实现接收适配器
|
||||||
|
|
||||||
**接受欧适配器**是指在接口请求后,对响应进行一些自定义处理,例如修改响应的数据结构、修改响应的数据等等。
|
**接受欧适配器**是指在接口请求后,对响应进行一些自定义处理,例如修改响应的数据结构、修改响应的数据等等。
|
||||||
|
|
||||||
例如:接口正确返回的格式中,会返回`"code": 200`,而amis中,接口返回格式需要`"status": 0`,这时候就需要接收适配器进行调整结构。
|
例如:接口正确返回的格式中,会返回`"code": 200`,而 amis 中,接口返回格式需要`"status": 0`,这时候就需要接收适配器进行调整结构。
|
||||||
|
|
||||||
#### 字符串形式
|
#### 字符串形式
|
||||||
|
|
||||||
如果在JSON文件中配置的话,`adaptor`只支持字符串形式,如下:
|
如果在 JSON 文件中配置的话,`adaptor`只支持字符串形式,如下:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "form",
|
"type": "form",
|
||||||
"api": {
|
"api": {
|
||||||
"method": "post",
|
"method": "post",
|
||||||
"url": "https://houtai.baidu.com/api/mock2/form/saveForm",
|
"url": "https://houtai.baidu.com/api/mock2/form/saveForm",
|
||||||
"adaptor": "return {\n ...payload,\n status: payload.code === 200 ? 0 : payload.code\n}"
|
"adaptor": "return {\n ...payload,\n status: payload.code === 200 ? 0 : payload.code\n}"
|
||||||
|
},
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"name": "name",
|
||||||
|
"label": "姓名:"
|
||||||
},
|
},
|
||||||
"controls": [
|
{
|
||||||
{
|
"name": "file",
|
||||||
"type": "text",
|
"type": "file",
|
||||||
"name": "name",
|
"label": "附件:",
|
||||||
"label": "姓名:"
|
"asBlob": true
|
||||||
},
|
}
|
||||||
{
|
]
|
||||||
"name": "file",
|
}
|
||||||
"type": "file",
|
|
||||||
"label": "附件:",
|
|
||||||
"asBlob": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
上例中的适配器实际上是如下代码的字符串形式:
|
上例中的适配器实际上是如下代码的字符串形式:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
return {
|
return {
|
||||||
...payload,
|
...payload,
|
||||||
status: payload.code === 200 ? 0 : payload.code
|
status: payload.code === 200 ? 0 : payload.code
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数形式
|
#### 函数形式
|
||||||
|
|
||||||
如果你的使用环境为js文件,则可以直接传入函数,如下:
|
如果你的使用环境为 js 文件,则可以直接传入函数,如下:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const schema = {
|
const schema = {
|
||||||
|
@ -553,11 +555,11 @@ const schema = {
|
||||||
api: {
|
api: {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: 'https://houtai.baidu.com/api/mock2/form/saveForm',
|
url: 'https://houtai.baidu.com/api/mock2/form/saveForm',
|
||||||
adaptor: function(payload, response) {
|
adaptor: function (payload, response) {
|
||||||
return {
|
return {
|
||||||
...payload,
|
...payload,
|
||||||
status: payload.code === 200 ? 0 : payload.code
|
status: payload.code === 200 ? 0 : payload.code
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
controls: [
|
controls: [
|
||||||
|
@ -587,16 +589,10 @@ const schema = {
|
||||||
| url | 请求地址 | [模板字符串](https://suda.bce.baidu.com/docs/template#%E6%A8%A1%E6%9D%BF%E5%AD%97%E7%AC%A6%E4%B8%B2) | - |
|
| url | 请求地址 | [模板字符串](https://suda.bce.baidu.com/docs/template#%E6%A8%A1%E6%9D%BF%E5%AD%97%E7%AC%A6%E4%B8%B2) | - |
|
||||||
| data | 请求数据 | 对象或字符串 | 支持数据映射 |
|
| data | 请求数据 | 对象或字符串 | 支持数据映射 |
|
||||||
| dataType | 数据体格式 | 字符串 | 默认为 `json` 可以配置成 `form` 或者 `form-data`。当 `data` 中包含文件时,自动会采用 `form-data(multipart/form-data)` 格式。当配置为 `form` 时为 `application/x-www-form-urlencoded` 格式。 |
|
| dataType | 数据体格式 | 字符串 | 默认为 `json` 可以配置成 `form` 或者 `form-data`。当 `data` 中包含文件时,自动会采用 `form-data(multipart/form-data)` 格式。当配置为 `form` 时为 `application/x-www-form-urlencoded` 格式。 |
|
||||||
| qsOptions | -- | 对象或字符串 | 当 dataType 为form或者form-data 的时候有用。具体参数请参考这里,默认设置为: `{ arrayFormat: 'indices', encodeValuesOnly: true }` |
|
| qsOptions | -- | 对象或字符串 | 当 dataType 为 form 或者 form-data 的时候有用。具体参数请参考这里,默认设置为: `{ arrayFormat: 'indices', encodeValuesOnly: true }` |
|
||||||
| headers | 请求头 | 对象 | - |
|
| headers | 请求头 | 对象 | - |
|
||||||
| sendOn | 请求条件 | [表达式](https://suda.bce.baidu.com/docs/expression) | - |
|
| sendOn | 请求条件 | [表达式](https://suda.bce.baidu.com/docs/expression) | - |
|
||||||
| cache | 接口缓存时间 | 整型数字 | - |
|
| cache | 接口缓存时间 | 整型数字 | - |
|
||||||
| requestAdaptor | 发送适配器 | 字符串 | ,支持字符串串格式,或者直接就是函数如: |
|
| requestAdaptor | 发送适配器 | 字符串 | ,支持字符串串格式,或者直接就是函数如: |
|
||||||
| adaptor | 接收适配器 | 字符串 | 如果接口返回不符合要求,可以通过配置一个适配器来处理成 amis 需要的。同样支持 Function 或者 字符串函数体格式 |
|
| adaptor | 接收适配器 | 字符串 | 如果接口返回不符合要求,可以通过配置一个适配器来处理成 amis 需要的。同样支持 Function 或者 字符串函数体格式 |
|
||||||
| replaceData | 替换当前数据 | 布尔 | 返回的数据是否替换掉当前的数据,默认为 `false`,即:`追加`,设置成 `true` 就是完全替换。 |
|
| replaceData | 替换当前数据 | 布尔 | 返回的数据是否替换掉当前的数据,默认为 `false`,即:`追加`,设置成 `true` 就是完全替换。 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,15 @@ export class App extends React.PureComponent {
|
||||||
'is-open': isOpen
|
'is-open': isOpen
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Link to={`${path || (hasChildren && nav.children[0].path)}`}>
|
<Link
|
||||||
|
onClick={e => {
|
||||||
|
browserHistory.push(
|
||||||
|
`${path || (hasChildren && nav.children[0].path)}`
|
||||||
|
);
|
||||||
|
this.toggleOpen(e, nav);
|
||||||
|
}}
|
||||||
|
// to={`${path || (hasChildren && nav.children[0].path)}`}
|
||||||
|
>
|
||||||
{nav.label}
|
{nav.label}
|
||||||
{hasChildren ? (
|
{hasChildren ? (
|
||||||
<i
|
<i
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import makeMarkdownRenderer from './MdRenderer';
|
import makeMarkdownRenderer from './MdRenderer';
|
||||||
|
import {flattenTree, filterTree} from '../../src/utils/helper';
|
||||||
|
|
||||||
export const docs = [
|
export const docs = [
|
||||||
{
|
{
|
||||||
|
@ -7,7 +8,7 @@ export const docs = [
|
||||||
label: '开始',
|
label: '开始',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'AMIS 是什么?',
|
label: '介绍',
|
||||||
path: '/docs/index',
|
path: '/docs/index',
|
||||||
getComponent: (location, cb) =>
|
getComponent: (location, cb) =>
|
||||||
require(['../../docs/index.md'], doc => {
|
require(['../../docs/index.md'], doc => {
|
||||||
|
@ -16,12 +17,21 @@ export const docs = [
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
label: '使用',
|
label: '快速开始',
|
||||||
path: '/docs/start/usage',
|
path: '/docs/start/usage',
|
||||||
getComponent: (location, cb) =>
|
getComponent: (location, cb) =>
|
||||||
require(['../../docs/start/usage.md'], doc => {
|
require(['../../docs/start/usage.md'], doc => {
|
||||||
cb(null, makeMarkdownRenderer(doc));
|
cb(null, makeMarkdownRenderer(doc));
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: '自定义组件',
|
||||||
|
path: '/docs/start/custom',
|
||||||
|
getComponent: (location, cb) =>
|
||||||
|
require(['../../docs/start/custom.md'], doc => {
|
||||||
|
cb(null, makeMarkdownRenderer(doc));
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
|
@ -159,12 +169,21 @@ export const docs = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Form 表单',
|
label: 'Form 表单',
|
||||||
path: '/docs/components/form/index',
|
// path: '/docs/components/form/index',
|
||||||
getComponent: (location, cb) =>
|
// getComponent: (location, cb) =>
|
||||||
require(['../../docs/components/form/index.md'], doc => {
|
// require(['../../docs/components/form/index.md'], doc => {
|
||||||
cb(null, makeMarkdownRenderer(doc));
|
// cb(null, makeMarkdownRenderer(doc));
|
||||||
}),
|
// }),
|
||||||
children: [
|
children: [
|
||||||
|
// @todo 完了想办法把这个放上面,暂时先这样
|
||||||
|
{
|
||||||
|
label: 'Form 表单',
|
||||||
|
path: '/docs/components/form/index',
|
||||||
|
getComponent: (location, cb) =>
|
||||||
|
require(['../../docs/components/form/index.md'], doc => {
|
||||||
|
cb(null, makeMarkdownRenderer(doc));
|
||||||
|
})
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'FormItem 表单项',
|
label: 'FormItem 表单项',
|
||||||
path: '/docs/components/form/formitem',
|
path: '/docs/components/form/formitem',
|
||||||
|
@ -948,12 +967,30 @@ export const docs = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export default class Doc extends React.PureComponent {
|
export default class Doc extends React.PureComponent {
|
||||||
|
state = {
|
||||||
|
prevDoc: null,
|
||||||
|
nextDoc: null
|
||||||
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.setNavigations(docs);
|
this.props.setNavigations(docs);
|
||||||
|
this.setDocFooter();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate(preProps) {
|
||||||
this.props.setNavigations(docs);
|
if (this.props.location.pathname !== preProps.location.pathname) {
|
||||||
|
this.props.setNavigations(docs);
|
||||||
|
this.setDocFooter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setDocFooter() {
|
||||||
|
const flattenDocs = flattenTree(docs).filter(i => !!i.path);
|
||||||
|
const docIndex = flattenDocs.findIndex(d => d.path === location.pathname);
|
||||||
|
this.setState({
|
||||||
|
prevDoc: flattenDocs[docIndex - 1],
|
||||||
|
nextDoc: flattenDocs[docIndex + 1]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -963,7 +1000,9 @@ export default class Doc extends React.PureComponent {
|
||||||
...this.props.children.props,
|
...this.props.children.props,
|
||||||
theme: this.props.theme,
|
theme: this.props.theme,
|
||||||
classPrefix: this.props.classPrefix,
|
classPrefix: this.props.classPrefix,
|
||||||
locale: this.props.locale
|
locale: this.props.locale,
|
||||||
|
prevDoc: this.state.prevDoc,
|
||||||
|
nextDoc: this.state.nextDoc
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -511,20 +511,22 @@ export const examples = [
|
||||||
icon: 'fa fa-cloud',
|
icon: 'fa fa-cloud',
|
||||||
path: '/examples/iframe',
|
path: '/examples/iframe',
|
||||||
component: makeSchemaRenderer(IFrameSchema)
|
component: makeSchemaRenderer(IFrameSchema)
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SDK',
|
|
||||||
icon: 'fa fa-rocket',
|
|
||||||
path: '/examples/sdk',
|
|
||||||
component: SdkTest
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
label: 'Test',
|
|
||||||
icon: 'fa fa-code',
|
|
||||||
path: '/examples/test',
|
|
||||||
component: TestComponent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 放到使用中
|
||||||
|
// {
|
||||||
|
// label: 'SDK',
|
||||||
|
// icon: 'fa fa-rocket',
|
||||||
|
// path: '/examples/sdk',
|
||||||
|
// component: SdkTest
|
||||||
|
// }
|
||||||
|
|
||||||
|
// {
|
||||||
|
// label: 'Test',
|
||||||
|
// icon: 'fa fa-code',
|
||||||
|
// path: '/examples/test',
|
||||||
|
// component: TestComponent
|
||||||
|
// }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -540,14 +542,14 @@ export default class Example extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="Doc-content">
|
<>
|
||||||
{React.cloneElement(this.props.children, {
|
{React.cloneElement(this.props.children, {
|
||||||
...this.props.children.props,
|
...this.props.children.props,
|
||||||
theme: this.props.theme,
|
theme: this.props.theme,
|
||||||
classPrefix: this.props.classPrefix,
|
classPrefix: this.props.classPrefix,
|
||||||
locale: this.props.locale
|
locale: this.props.locale
|
||||||
})}
|
})}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import PopOver from '../../src/components/PopOver';
|
||||||
import NestedLinks from '../../src/components/AsideNav';
|
import NestedLinks from '../../src/components/AsideNav';
|
||||||
import {Portal} from 'react-overlays';
|
import {Portal} from 'react-overlays';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import {Link} from 'react-router';
|
||||||
|
|
||||||
class CodePreview extends React.Component {
|
class CodePreview extends React.Component {
|
||||||
state = {
|
state = {
|
||||||
|
@ -183,6 +184,10 @@ export default function (doc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
console.log('this.props', this.props);
|
||||||
|
|
||||||
|
const {prevDoc, nextDoc} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="Doc-content">
|
<div className="Doc-content">
|
||||||
|
@ -191,7 +196,42 @@ export default function (doc) {
|
||||||
<h1>{doc.title}</h1>
|
<h1>{doc.title}</h1>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Preview {...this.props} doc={doc} />
|
<Preview {...this.props} doc={doc} />
|
||||||
|
|
||||||
|
<div className="Doc-footer">
|
||||||
|
<div className="Doc-navLinks">
|
||||||
|
{prevDoc ? (
|
||||||
|
<Link className="Doc-navLinks--prev" to={prevDoc.path}>
|
||||||
|
<div className="Doc-navLinks-icon">
|
||||||
|
<i className="iconfont icon-arrow-left"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="Doc-navLinks-body text-right">
|
||||||
|
<div className="Doc-navLinks-subtitle">
|
||||||
|
上一篇 - {prevDoc.group || '其他'}
|
||||||
|
</div>
|
||||||
|
<div className="Doc-navLinks-title">{prevDoc.label} </div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{nextDoc ? (
|
||||||
|
<Link className="Doc-navLinks--next" to={nextDoc.path}>
|
||||||
|
<div className="Doc-navLinks-body">
|
||||||
|
<div className="Doc-navLinks-subtitle">
|
||||||
|
下一篇 - {nextDoc.group || '其他'}
|
||||||
|
</div>
|
||||||
|
<div className="Doc-navLinks-title">{nextDoc.label}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="Doc-navLinks-icon">
|
||||||
|
<i className="iconfont icon-arrow-right"></i>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{doc.toc && doc.toc.children && doc.toc.children.length > 1 ? (
|
{doc.toc && doc.toc.children && doc.toc.children.length > 1 ? (
|
||||||
<div className="Doc-toc">
|
<div className="Doc-toc">
|
|
@ -185,8 +185,6 @@ export default class PlayGround extends React.Component {
|
||||||
locale: this.props.locale
|
locale: this.props.locale
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('render', render(schema, props, this.env));
|
|
||||||
|
|
||||||
if (!this.props.useIFrame) {
|
if (!this.props.useIFrame) {
|
||||||
return render(schema, props, this.env);
|
return render(schema, props, this.env);
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,32 +185,16 @@ export default function (schema) {
|
||||||
size="lg"
|
size="lg"
|
||||||
onHide={this.close}
|
onHide={this.close}
|
||||||
show={this.state.open}
|
show={this.state.open}
|
||||||
position="left"
|
position="right"
|
||||||
>
|
>
|
||||||
{this.state.open ? this.renderCode() : null}
|
{this.state.open ? this.renderCode() : null}
|
||||||
</DrawerContainer>
|
</DrawerContainer>
|
||||||
) : null}
|
) : null}
|
||||||
{this.renderSchema()}
|
{this.renderSchema()}
|
||||||
{showCode !== false ? (
|
{showCode !== false ? (
|
||||||
<Portal
|
<span onClick={this.toggleCode} className="view-code-btn">
|
||||||
container={() => document.querySelector('#headerLeftBtns')}
|
查看配置 <i className="fa fa-code p-l-xs"></i>
|
||||||
>
|
</span>
|
||||||
<Button
|
|
||||||
classPrefix={ns}
|
|
||||||
onClick={this.toggleCode}
|
|
||||||
active={this.state.open}
|
|
||||||
iconOnly
|
|
||||||
tooltip="查看源码"
|
|
||||||
level="link"
|
|
||||||
placement="bottom"
|
|
||||||
className="view-code"
|
|
||||||
>
|
|
||||||
<i className="fa fa-code" />
|
|
||||||
</Button>
|
|
||||||
<span className="inline v-middle text-info">
|
|
||||||
←点击这里查看源码
|
|
||||||
</span>
|
|
||||||
</Portal>
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<html lang="zh">
|
<html lang="zh">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>AMis Renderer</title>
|
<title>amis - 低代码前端框架</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<meta
|
<meta
|
||||||
name="viewport"
|
name="viewport"
|
||||||
|
|
|
@ -342,16 +342,9 @@ body {
|
||||||
&-content {
|
&-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
> .schema-wrapper > .a-Page {
|
|
||||||
position: absolute;
|
|
||||||
top: 36px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Doc-title {
|
.Doc-title {
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
padding-left: 45px;
|
padding-left: 40px;
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -444,6 +437,49 @@ body {
|
||||||
.is-flipped {
|
.is-flipped {
|
||||||
transform: rotateX(180deg);
|
transform: rotateX(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .schema-wrapper {
|
||||||
|
.view-code-btn {
|
||||||
|
position: absolute;
|
||||||
|
font-weight: bold;
|
||||||
|
right: -100px;
|
||||||
|
top: 112px;
|
||||||
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -21px;
|
||||||
|
bottom: 0;
|
||||||
|
content: ' ';
|
||||||
|
border-left: 1px solid #e8ebee;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
> i {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .a-Page,
|
||||||
|
> .cxd-Page,
|
||||||
|
> .dark-Page {
|
||||||
|
position: absolute;
|
||||||
|
top: 100px;
|
||||||
|
left: 30px;
|
||||||
|
right: 60px;
|
||||||
|
bottom: 0;
|
||||||
|
height: auto;
|
||||||
|
&--withSidebar {
|
||||||
|
padding-right: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up(lg) {
|
@include media-breakpoint-up(lg) {
|
||||||
|
@ -457,7 +493,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
&-toc {
|
&-toc {
|
||||||
margin-left: 30px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-toc > div {
|
&-toc > div {
|
||||||
|
|
|
@ -636,12 +636,6 @@ class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||||
const {data: defaultData, ...restSchema} = schema;
|
const {data: defaultData, ...restSchema} = schema;
|
||||||
const Component = renderer.component;
|
const Component = renderer.component;
|
||||||
|
|
||||||
if (schema.type === 'page') {
|
|
||||||
console.log(schema);
|
|
||||||
console.log(schema.title);
|
|
||||||
console.log('='.repeat(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Component
|
<Component
|
||||||
{...theme.getRendererConfig(renderer.name)}
|
{...theme.getRendererConfig(renderer.name)}
|
||||||
|
|
Loading…
Reference in New Issue