docs: 新增高级分类,增加国际化和扩展现有组件的文档 (#1269)

* 完善扩展相关文档初步

* 文档完善

* 文档文字完善
This commit is contained in:
吴多益 2020-12-29 12:21:10 +08:00 committed by GitHub
parent eaa58a81d3
commit 6706445183
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 672 additions and 327 deletions

View File

@ -29,7 +29,7 @@ order: 1
}
```
- `name`: **必填属性**,标识表单数据域中,当前表单项值的`key`
- `name`: **必填属性**,标识表单数据域中,当前表单项值的`key`,这个 name 可以是深层结构,比如 `aa.bb`
- `type`: **必填属性**,标识表单项类型
- `label`: 标识表单项的标签

View File

@ -46,7 +46,7 @@ order: 10
渲染后页面如下:
```schema:height="200"
```schema:height="50"
{
"type": "page",
"initApi": "https://houtai.baidu.com/api/mock2/page/initData",
@ -81,7 +81,7 @@ order: 10
毫无疑问,`${text}`将会解析为空白文本,最终渲染的文本是 `Hello`
```schema:height="200"
```schema:height="50"
{
"type": "page",
"body": "Hello ${text}"
@ -92,7 +92,7 @@ order: 10
再观察下面这段配置:
```schema:height="200"
```schema:height="50"
{
"data": {
"text": "World!"
@ -106,7 +106,7 @@ order: 10
相信你可能已经猜到,**组件的`data`属性值是数据域的一种形式**,实际上当我们没有显式的配置数据域时,可以假想成这样:
```schema:height="200"
```schema:height="50"
{
"data": {}, // 空的数据域
"type": "page",
@ -114,8 +114,6 @@ order: 10
}
```
> amis 中大部分组件都具有数据域。
>
> 而前面我们知道 amis 的特性之一是基于组件树,因此自然数据域也会形成类似于树型结构,如何来处理这些数据域之间的联系呢,这就是我们马上要介绍到的 **[数据链](./datascope-and-datachain#%E6%95%B0%E6%8D%AE%E9%93%BE)**
## 数据链
@ -132,7 +130,7 @@ order: 10
继续来看这个例子:
```schema:height="200"
```schema:height="70"
{
"type": "page",
"data": {
@ -193,6 +191,67 @@ page
> **注意:** 当前例子中,对数据域中数据的获取使用的是 **\${xxx}** 模板语法,但是在不同的组件配置项中,获取数据的语法会有差异,我们会在后续的[模板](./template)和[表达式章节](./expression)中一一介绍。
### 常见误解
需要注意,只有少数几个容器组件会创建新的数据域,除了最顶层的 Page还有 CRUD、Dialog、IFrame、Form、Serice 等。
常见的错误写法是给容器组件加 data 属性,比如:
```schema:height="70"
{
"type": "page",
"data": {
"name": "zhangsan"
},
"body": [
{
"type": "tpl",
"tpl": "my name is ${name}"
},
{
"type": "container",
"data": {
"name": "lisi"
},
"body": {
"type": "tpl",
"tpl": "my name is ${name}"
}
}
]
}
```
这样是不会生效的,正确的做法是使用 Service 包裹一层,如下所示
```schema:height="70"
{
"type": "page",
"data": {
"name": "zhangsan"
},
"body": [
{
"type": "tpl",
"tpl": "my name is ${name}"
},
{
"type": "service",
"data": {
"name": "lisi"
},
"body": {
"type": "container",
"body": {
"type": "tpl",
"tpl": "my name is ${name}"
}
}
}
]
}
```
## 初始化数据域
通过上面的介绍你可能发现,初始化数据域有两种方式:

147
docs/extend/addon.md Normal file
View File

@ -0,0 +1,147 @@
---
title: 扩展现有组件
---
除了新增组件,在 amis 中还能扩展和修改现有组件。
## 事件扩展
amis 默认会将配置项剩余参数都作为 React 的 props 传入对应标签,使得可以添加自己的自定义事件,比如 下面的例子
```javascript
let amis = amisRequire('amis/embed');
let amisLib = amisRequire('amis');
let amisScoped = amis.embed('#root', {
type: 'page',
title: '表单页面',
body: {
type: 'form',
mode: 'horizontal',
api: '/saveForm',
controls: [
{
type: 'button',
label: '按钮',
onClick: () => {
amisLib.toast.info('消息通知');
}
}
]
}
});
```
这样就能在点击按钮的时候执行自定义代码了。
## 同时支持多种类型编辑
在表单编辑中,每个 name 一般对应一种类型,如果这个 name 有多种类型,比如下面的例子中 id 的值有可能是字符串,也有可能是数字,但 type 只能设置为一种类型,这种情况如何处理?
```schema:height="200" scope="body"
{
"type": "form",
"mode": "horizontal",
"controls": [
{
"name": "id",
"type": "text",
"label": "id"
}
]
}
```
有两种方式:
### 使用另一个名称作为状态
```schema:height="250" scope="body"
{
"type": "form",
"mode": "horizontal",
"controls": [
{
"name": "idIsNumber",
"type": "switch",
"label": "id 是数字类型"
},
{
"name": "id",
"type": "text",
"label": "id",
"hiddenOn": "data.idIsNumber"
},
{
"name": "id",
"type": "number",
"label": "id",
"visibleOn": "data.idIsNumber"
}
]
}
```
可以看到在一个 form 中可以有两个 name 相同的组件,通过 hiddenOn 或 visibleOn 来控制同时只显示一个。
### 使用 PipeIn/PipeOut 方法
如果不想增加一个新的 name在 JS SDK 或 React 还有更高级的处理方法,可以增加一个 name 同样为 id 的 switch实现 PipeIn/PipeOut 函数来进行自动识别,下面是个示例:
```javascript
let amis = amisRequire('amis/embed');
let amisScoped = amis.embed('#root', {
type: 'page',
title: '表单页面',
// 可以通过去掉下面的注释来测试
// data: {
// id: 1
// },
body: {
type: 'form',
mode: 'horizontal',
api: '/saveForm',
controls: [
{
type: 'switch',
label: 'id 是数字',
name: 'id',
// pipeIn 返回的应该是这个组件所需的值,比如 switch 的返回值就应该是 true 或 false
// 这里的 value 就是初始值,如果不设置将会是 undefined
pipeIn: (value, data) => {
if (typeof value === 'undefined') {
return false;
}
return typeof value !== 'string';
},
// 这里的 value 是点击 switch 之后的值,比如打开就是 true关闭就是 false
pipeOut: (value, oldValue, data) => {
if (value) {
return 1; // 切换到数字之后的默认值
} else {
return 'id1'; // 关闭之后的默认值
}
}
},
{
name: 'id',
type: 'text',
label: 'id',
visibleOn:
'typeof data.id === "undefined" || typeof data.id === "string"'
},
{
name: 'id',
type: 'number',
label: 'id',
visibleOn: 'typeof data.id === "number"'
}
]
}
});
```
不过这种写法的复杂度较高
## 修改组件标签
有些组件可以设置 `wrapperComponent`,比如 Form 下默认使用 form 标签,在浏览器中会自带回车提交功能,如果想去掉这个功能,可以将 `wrapperComponent` 设置为 `div`

View File

@ -1,123 +1,7 @@
---
title: 自定义
title: 自定义组件 - React
---
如果默认的组件不能满足需求,可以通过自定义组件来进行扩展,根据不同使用方式,一共有四种方法:
1. JS SDK
1. 使用 custom 组件临时扩展,但不支持组件复用。
2. JS SDK 注册组件,支持组件复用。
2. React
1. React 临时扩展,适合无需复用的组件。
2. React 注册自定义类型,支持组件复用。
## 使用 custom 组件临时扩展
基于 custom 组件可以直接在 amis 配置实现自定义功能,它的支持面最广,是唯一支持在可视化编辑器中使用的方法。
使用 custom 组件类似如下写法:
```javascript
{
label: '使用 custom 组件',
name: 'username', // 如果要放在 form 中,需要设置 nameonChange 将会设置这个值
type: 'custom',
// onMount 将会在组件创建时执行,默认会创建一个空 div 标签,也可以设置 inline: true 来创建 span 标签
// dom 是 dom 节点value 是初始数据,比如表单 name 初始拿到的数据onChange 只有在表单下才会有
onMount: (dom, value, onChange) => {
const button = document.createElement('button');
button.innerText = '点击修改姓名';
button.onclick = event => {
onChange('new name');
event.preventDefault();
};
dom.appendChild(button);
},
// onUpdate 将会在数据更新时被调用
// dom 是 dom 节点、data 将包含表单所有数据prevData 是之前表单的所有数据
onUpdate: (dom, data, prevData) => {
console.log('数据有变化', data);
},
// onUnmount 将会在组件被销毁的时候调用,用于清理资源
onUnmount:() => {
console.log('组件被销毁');
}
}
```
注意上面的代码用到了 JavaScript 函数,无法转成 json 格式,但这三个函数还支持字符串形式,上面的代码可以改成如下形式,这样就能在可视化编辑器里支持自定义组件了:
```schema:height="330" scope="body"
{
"type": "form",
"title": "custom 组件",
"controls": [
{
"type": "text",
"name": "username",
"label": "姓名"
},
{
"name": "username",
"type": "custom",
"label": "自定义组件",
"onMount": "const button = document.createElement('button'); button.innerText = '点击修改姓名'; button.onclick = event => { onChange('new name'); event.preventDefault(); }; dom.appendChild(button);"
}
]
}
```
注意上面的例子中两个组件的 name 是一样的,这是为了方便示例,因为 amis 中的数据是双向绑定的,因此 onChange 修改自身的时候,另一个「姓名」输入框由于 name 一样,也会同步更新。
关于 custom 组件的更多属性请参考「[Custom 组件](../components/custom)」。
## JS SDK 注册组件
amis 组件都是基于 React 的,所以需要使用一个简单的 React 组件来注册,可以是函数组件也可以是类组件,下面以函数组件为例,将[快速开始](getting-started)中的代码替换成如下示例:
```javascript
(function () {
let amis = amisRequire('amis/embed');
let amisLib = amisRequire('amis');
let React = amisRequire('react');
// 自定义组件
function CustomComponent() {
let dom = React.useRef(null);
React.useEffect(function () {
// 从这里开始写自定义代码dom.current 就是新创建的 dom 节点
// 可以基于这个 dom 节点对接任意 JavaScript 框架,比如 jQuery/Vue 等
dom.current.innerHTML = 'custom';
});
return React.createElement('div', {
ref: dom
});
}
//注册自定义组件,请参考后续对工作原理的介绍
amisLib.Renderer({
test: /(^|\/)my-custom/
})(CustomComponent);
let amisScoped = amis.embed('#root', {
type: 'page',
title: '表单页面',
body: {
type: 'form',
mode: 'horizontal',
api: '/saveForm',
controls: [
{
label: 'Name',
type: 'my-custom', // 注意这个的 type 对应之前注册的 test
name: 'custom'
}
]
}
});
})();
```
## React 临时扩展
amis 的配置最终会转成 React 组件来执行,所以如果只是想在某个配置中加入定制功能,可以直接在这个 JSON 配置里写 React 代码,比如下面这个例子:
@ -163,157 +47,7 @@ amis 的配置最终会转成 React 组件来执行,所以如果只是想在
## React 注册自定义类型
注册自定义类型需要了解 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
import * as React from 'react';
import {Renderer} from 'amis';
@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>
);
}
}
// 如果不支持 Decorators 语法也可以使用如下写法
export Renderer({
test: /^page$/
})(class PageRenderer extends React.Component {
render() {
// ...同上
}
})
```
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 信息去组件池里面找到对应的渲染器,然后交给对应组件去完成渲染。
### 编写自定义组件
了解了基本原理后,来看个简单的例子:
首先需要了解「[基本原理](internal)」,了解了基本原理后,来看个简单的例子:
```jsx
import * as React from 'react';
@ -330,6 +64,14 @@ class CustomRenderer extends React.Component {
}
```
> 上面这个语法需要开启 Decorator 功能,如果不支持,可以改成如下写法
```javascript
Renderer({
test: /(^|\/)my\-renderer$/
})(CustomRenderer);
```
有了以上这段代码后,就可以这样使用了。
```json

141
docs/extend/custom-sdk.md Normal file
View File

@ -0,0 +1,141 @@
---
title: 自定义组件 - SDK
---
## 使用 custom 组件临时扩展
基于 custom 组件可以直接在 amis 配置实现自定义功能,它的支持面最广,是唯一支持在可视化编辑器中使用的方法。
使用 custom 组件类似如下写法:
```javascript
{
label: '使用 custom 组件',
name: 'username', // 如果要放在 form 中,需要设置 nameonChange 将会设置这个值
type: 'custom',
// onMount 将会在组件创建时执行,默认会创建一个空 div 标签,也可以设置 inline: true 来创建 span 标签
// dom 是 dom 节点value 是初始数据,比如表单 name 初始拿到的数据onChange 只有在表单下才会有
onMount: (dom, value, onChange) => {
const button = document.createElement('button');
button.innerText = '点击修改姓名';
button.onclick = event => {
onChange('new name');
event.preventDefault();
};
dom.appendChild(button);
},
// onUpdate 将会在数据更新时被调用
// dom 是 dom 节点、data 将包含表单所有数据prevData 是之前表单的所有数据
onUpdate: (dom, data, prevData) => {
console.log('数据有变化', data);
},
// onUnmount 将会在组件被销毁的时候调用,用于清理资源
onUnmount:() => {
console.log('组件被销毁');
}
}
```
注意上面的代码用到了 JavaScript 函数,无法转成 json 格式,但这三个函数还支持字符串形式,上面的代码可以改成如下形式,这样就能在可视化编辑器里支持自定义组件了:
```schema:height="330" scope="body"
{
"type": "form",
"title": "custom 组件",
"controls": [
{
"type": "text",
"name": "username",
"label": "姓名"
},
{
"name": "username",
"type": "custom",
"label": "自定义组件",
"onMount": "const button = document.createElement('button'); button.innerText = '点击修改姓名'; button.onclick = event => { onChange('new name'); event.preventDefault(); }; dom.appendChild(button);"
}
]
}
```
注意上面的例子中两个组件的 name 是一样的,这是为了方便示例,因为 amis 中的数据是双向绑定的,因此 onChange 修改自身的时候,另一个「姓名」输入框由于 name 一样,也会同步更新。
关于 custom 组件的更多属性请参考「[Custom 组件](../components/custom)」。
## JS SDK 注册组件
amis 组件都是基于 React 的,所以需要使用一个简单的 React 组件来注册,可以是函数组件也可以是类组件,下面以函数组件为例,将[快速开始](../start/getting-started)中的代码替换成如下示例:
```javascript
let amis = amisRequire('amis/embed');
let amisLib = amisRequire('amis');
let React = amisRequire('react');
// 自定义组件props 中可以拿到配置中的所有参数,比如 props.label 是 'Name'
function CustomComponent(props) {
let dom = React.useRef(null);
React.useEffect(function () {
// 从这里开始写自定义代码dom.current 就是新创建的 dom 节点
// 可以基于这个 dom 节点对接任意 JavaScript 框架,比如 jQuery/Vue 等
dom.current.innerHTML = 'custom';
// 而 props 中能拿到这个
});
return React.createElement('div', {
ref: dom
});
}
//注册自定义组件,请参考后续对工作原理的介绍
amisLib.Renderer({
test: /(^|\/)my-custom/
})(CustomComponent);
let amisScoped = amis.embed('#root', {
type: 'page',
title: '表单页面',
body: {
type: 'form',
mode: 'horizontal',
api: '/saveForm',
controls: [
{
label: 'Name',
type: 'my-custom', // 注意这个的 type 对应之前注册的 test
name: 'custom'
}
]
}
});
```
### 示例:引入 Element UI
首先在页面中加入 Element UI 所需的依赖
```html
<link
rel="stylesheet"
href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
/>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
```
然后将前面的 `React.useEffect` 改成如下即可:
```javascript
React.useEffect(function () {
dom.current.innerHTML = `
<el-button @click="visible = true">Button</el-button>
<el-dialog :visible.sync="visible" title="Hello world">
<p>Try Element</p>
</el-dialog>
`;
new Vue({
el: dom.current,
data: function () {
return {visible: false};
}
});
});
```

83
docs/extend/i18n.md Normal file
View File

@ -0,0 +1,83 @@
---
title: 多语言
---
amis 内置对英文的支持,同时你也可以扩展其他语言。
## JS SDK
从 1.1.0 版本开始已经自带英文翻译,所以只需要在 props 里设置 locale 即可。
```javascript
let amisScoped = amis.embed(
'#root',
{
type: 'page',
title: '表单页面',
body: {
type: 'form',
mode: 'horizontal',
api: '/saveForm',
controls: [
{
label: 'Name',
type: 'text',
name: 'name'
}
]
}
},
{
locale: 'en'
}
);
```
## React
React 中没有内置英文版本,需要自己 import使用如下方法
```javascript
import 'amis/lib/locale/en';
```
在渲染 amis 组件的时候设置 locale 为 en
```javascript
{
renderAmis(
{
type: 'page',
title: '简单页面',
body: '内容'
},
{
locale: 'en'
}
);
}
```
## 扩展其它语言
如果想扩展其他语言,首先参考 `https://github.com/baidu/amis/blob/master/src/locale/en.ts` 文件,了解需要翻译哪些文字,以中文为 key然后参考后面的示例注册新语言未翻译的文字都将使用默认语言即中文。
> 目前这种方式将会在未来修改,为了支持更多语言而不再使用中文为 key
### JS SDK 扩展方法
```javascript
let amisLib = amisRequire('amis');
amisLib.registerLocale('jp', {
提交: '送信'
});
```
### React 扩展方法
```javascript
import {registerLocale} from 'amis';
registerLocale('jp', {
提交: '送信'
});
```

151
docs/extend/internal.md Normal file
View File

@ -0,0 +1,151 @@
---
title: 工作原理
---
实现自定义类型需要了解 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
import * as React from 'react';
import {Renderer} from 'amis';
@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>
);
}
}
// 如果不支持 Decorators 语法也可以使用如下写法
export Renderer({
test: /^page$/
})(class PageRenderer extends React.Component {
render() {
// ...同上
}
})
```
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 信息去组件池里面找到对应的渲染器,然后交给对应组件去完成渲染。

View File

@ -2,7 +2,7 @@
title: 常见问题
---
### 如何实现左侧导航栏页面跳转?
## 如何实现左侧导航栏页面跳转?
为了能更容易嵌入其它平台amis 只负责单页面渲染,不接管前端路由,因此无法只靠 amis 配置实现多页面切换功能,推荐使用以下几种方法:
@ -10,6 +10,13 @@ title: 常见问题
2. 使用传统的页面跳转,这样就能使用 amis 的 aside其中通过 link 类型来跳转到另一个页面。
3. 使用「[爱速搭](http://suda.baidu.com/)」,它可以配置左侧导航,还自带了权限管理等功能。
### 集成到 React 项目中报错
## 集成到 React 项目中报错
一般都是因为 React、Mobx、mobx-react 版本有关,参考 amis 项目的 [package.json](https://github.com/baidu/amis/blob/master/package.json),将版本保持一致,尤其是 Mobx目前 amis 中使用的版本是 4因为兼容性的考虑短期内不会升级到 5使用 MobX 5 肯定会报错。
## 有的功能在官网示例中能用,但在 React/SDK 中无法使用
amis 大概每个月发布一个正式版本,但官网是 master 分支的版本,因此很可能是正式版本未更新。
- React 可以使用最新 beta 版本。
- SDK 可以手动编译一个,下载开源项目源码后运行 `fis3 release publish-sdk -c`,然后在 sdk 目录就能找到。

View File

@ -5,10 +5,8 @@ description:
amis 有两种使用方法:
- [JS SDK](#SDK)
- [React](#react)
React 版本可以完整使用 amis 的所有功能。
- [JS SDK](#SDK),可以用在任意项目中
- [React](#react),可以用在 React 项目中
SDK 版本适合对前端或 React 不了解的开发者,它不依赖 npm 及 webpack可以像 Vue/jQuery 那样外链代码就能使用。
@ -33,9 +31,9 @@ JSSDK 版本可以在 github 的 [releases](https://github.com/baidu/amis/releas
/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<link rel="stylesheet" href="sdk.css" />
<!-- 从 1.0.20 开始默认不支持 IE 11如果要支持 IE11 请引用这个 css -->
<!-- 不过 amis 开发团队几乎没测试过 IE 11 下的效果,所以可能有不少功能用不了 -->
<!-- 从 1.1.0 开始 sdk.css 将不支持 IE 11如果要支持 IE11 请引用这个 css -->
<!-- <link rel="stylesheet" href="sdk-ie11.css" /> -->
<!-- 不过 amis 开发团队几乎没测试过 IE 11 下的效果,所以可能有不少功能用不了 -->
<style>
html,
body,
@ -84,7 +82,7 @@ JSSDK 版本可以在 github 的 [releases](https://github.com/baidu/amis/releas
### 控制 amis 的行为
`amis.embed` 函数还支持以下配置项来控制 amis 的行为,比如在 fetcher 的时候加入自己的处理逻辑,这些函数参数的说明在前面也有介绍。
`amis.embed` 函数还支持以下配置项来控制 amis 的行为,比如在 fetcher 的时候加入自己的处理逻辑,这些函数参数的说明在后面 React 中也有介绍。
```js
let amisScoped = amis.embed(
@ -96,38 +94,37 @@ let amisScoped = amis.embed(
},
{
// props 一般不用传。
// locale: 'en' // 语言
},
{
fetcher: (url, method, data, config) => {
// 可以不传,用来实现 ajax 请求
},
// 可以不传,用来实现 ajax 请求
fetcher: (url, method, data, config) => {},
// 全局 api 适配器。
// 可以不传,全局 api 适配器。
// api 自己也可以配置适配器,这里最好只处理通用逻辑。
responseAdpater(api, response, query, request) {
debugger;
return response;
}
// // 可以不传,用来实现页面跳转
// 可以不传,用来实现页面跳转
// jumpTo: location => {},
// // 可以不传,用来实现地址栏更新
// 可以不传,用来实现地址栏更新
// updateLocation: (location, replace) => {},
// // 可以不传,用来判断是否目标地址当前地址。
// 可以不传,用来判断是否目标地址当前地址。
// isCurrentUrl: url => {},
// // 可以不传,用来实现复制到剪切板
// 可以不传,用来实现复制到剪切板
// copy: content => {},
// // 可以不传,用来实现通知
// 可以不传,用来实现通知
// notify: (type, msg) => {},
// // 可以不传,用来实现提示
// 可以不传,用来实现提示
// alert: content => {},
// // 可以不传,用来实现确认框。
// 可以不传,用来实现确认框。
// confirm: content => {}
}
);
@ -232,7 +229,7 @@ import * as React from 'react';
import axios from 'axios';
import copy from 'copy-to-clipboard';
import {render as renderAmis} from 'amis';
import {render as renderAmis, ToastComponent, AlertComponent} from 'amis';
import {alert, confirm} from 'amis/lib/components/Alert';
import {toast} from 'amis/lib/components/Toast';
@ -241,6 +238,8 @@ class MyComponent extends React.Component<any, any> {
return (
<div>
<p>通过 amis 渲染页面</p>
<ToastComponent key="toast" position={'top-right'} />
<AlertComponent key="alert" />
{renderAmis(
{
// 这里是 amis 的 Json 配置。
@ -250,6 +249,7 @@ class MyComponent extends React.Component<any, any> {
},
{
// props...
// locale: 'en' // 请参考「多语言」的文档
},
{
// 下面三个接口必须实现

View File

@ -2,7 +2,7 @@
title: 快速开始
---
> 这是 1.0.20 版本中新增的功能
> 这是 1.1.0 版本中新增的功能
在 amis 中自定义样式有三种方式:

View File

@ -26,14 +26,6 @@ export const docs = [
)
},
{
label: '自定义',
path: '/docs/start/custom',
getComponent: () =>
// @ts-ignore
import('../../docs/start/custom.md').then(makeMarkdownRenderer)
},
{
label: '常见问题',
path: '/docs/start/faq',
@ -41,26 +33,6 @@ export const docs = [
// @ts-ignore
import('../../docs/start/faq.md').then(makeMarkdownRenderer)
}
// {
// label: '基本用法',
// icon: 'fa fa-file',
// path: '/docs/basic',
// getComponent: (location, cb) =>
// (require as any)(['../../docs/basic.md'], doc => {
// cb(null, makeMarkdownRenderer(doc));
// })
// },
// {
// label: '高级用法',
// icon: 'fa fa-rocket',
// path: '/docs/advanced',
// getComponent: (location, cb) =>
// (require as any)(['../../docs/advanced.md'], doc => {
// cb(null, makeMarkdownRenderer(doc));
// })
// }
]
},
@ -130,6 +102,47 @@ export const docs = [
]
},
{
label: '💎 高级',
children: [
{
label: '工作原理',
path: '/docs/extend/internal',
getComponent: () =>
// @ts-ignore
import('../../docs/extend/internal.md').then(makeMarkdownRenderer)
},
{
label: '自定义组件 - SDK',
path: '/docs/extend/custom-sdk',
getComponent: () =>
// @ts-ignore
import('../../docs/extend/custom-sdk.md').then(makeMarkdownRenderer)
},
{
label: '自定义组件 - React',
path: '/docs/extend/custom-react',
getComponent: () =>
// @ts-ignore
import('../../docs/extend/custom-react.md').then(makeMarkdownRenderer)
},
{
label: '扩展现有组件',
path: '/docs/extend/addon',
getComponent: () =>
// @ts-ignore
import('../../docs/extend/addon.md').then(makeMarkdownRenderer)
},
{
label: '多语言',
path: '/docs/extend/i18n',
getComponent: () =>
// @ts-ignore
import('../../docs/extend/i18n.md').then(makeMarkdownRenderer)
}
]
},
{
label: '🎼 类型',
children: [

View File

@ -15,6 +15,8 @@ import {
render as renderAmis
} from '../src/index';
import '../src/locale/en';
export function embed(
container: string | HTMLElement,
schema: any,