80 lines
63 KiB
JavaScript
80 lines
63 KiB
JavaScript
define('docs/custom.md', function(require, exports, module) {
|
||
|
||
module.exports = {
|
||
"title": "定制功能",
|
||
"html": "<p>如果默认的组件不能满足需求,可以通过定制组件来进行扩展,在 amis 中有两种方法:</p>\n<ol>\n<li>临时扩展,适合无需复用的组件。</li>\n<li>注册自定义类型,适合需要在很多地方复用的组件。</li>\n</ol>\n<blockquote>\n<p>注意,扩展只支持使用 React 组件方式引入的 amis,使用 JSSDK 无法支持</p>\n</blockquote>\n<h2><a class=\"anchor\" name=\"%E4%B8%B4%E6%97%B6%E6%89%A9%E5%B1%95\" href=\"#%E4%B8%B4%E6%97%B6%E6%89%A9%E5%B1%95\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>临时扩展</h2><p>amis 的 JSON 配置最终会转成 React 组件来执行,所以如果只是想在某个配置中加入定制功能,可以直接在这个 JSON 配置里写 React 代码,比如下面这个例子:</p>\n<pre><code class=\"lang-jsx\"><span class=\"token punctuation\">{</span>\n <span class=\"token string\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"page\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"自定义组件示例\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">\"body\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token string\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"form\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">\"controls\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n <span class=\"token punctuation\">{</span>\n <span class=\"token string\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"text\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">\"label\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"用户名\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"usename\"</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n <span class=\"token punctuation\">{</span>\n <span class=\"token string\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"mycustom\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">\"children\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>\n value<span class=\"token punctuation\">,</span>\n onChange\n <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">这个是个自定义组件</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">当前值:</span><span class=\"token punctuation\">{</span>value<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>a</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>btn btn-default<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">onClick</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>\n <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">onChange</span><span class=\"token punctuation\">(</span>Math<span class=\"token punctuation\">.</span><span class=\"token function\">round</span><span class=\"token punctuation\">(</span>Math<span class=\"token punctuation\">.</span><span class=\"token function\">random</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">10000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">随机修改</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>a</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span>\n <span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">]</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>其中的 <code>mycustom</code> 就是一个临时扩展,它的 <code>children</code> 属性是一个函数,它的返回内容和 React 的 Render 方法一样,即 jsx,在这个方法里你可以写任意 JavaScript 来实现自己的定制需求,这个函数有两个参数 <code>value</code> 和 <code>onChange</code>,<code>value</code> 就是组件的值,<code>onChange</code> 方法用来改变这个值,比如上面的例子中,点击链接后就会修改 <code>mycustom</code> 为一个随机数,在提交表单的时候就变成了这个随机数。</p>\n<p>与之类似的还有个 <code>component</code> 属性,这个属性可以传入 React Component,如果想用 React Hooks,请通过 <code>component</code> 传递,而不是 <code>children</code>。</p>\n<p>这种扩展方式既简单又灵活,但它是写在配置中的,如果需要在很多地方,可以使用下面的「注册自定义类型」方式:</p>\n<h2><a class=\"anchor\" name=\"%E6%B3%A8%E5%86%8C%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B\" href=\"#%E6%B3%A8%E5%86%8C%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>注册自定义类型</h2><p>注册自定义类型需要了解 amis 的工作原理。</p>\n<h3><a class=\"anchor\" name=\"%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86\" href=\"#%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>工作原理</h3><p>amis 的渲染过程是将 <code>json</code> 转成对应的 React 组件。先通过 <code>json</code> 的 type 找到对应的 <code>Component</code> 然后,然后把其他属性作为 <code>props</code> 传递过去完成渲染。</p>\n<p>拿一个表单页面来说,如果用 React 组件开发一般长这样。</p>\n<pre><code class=\"lang-jsx\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span><span class=\"token class-name\">Page</span></span> <span class=\"token attr-name\">title</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>页面标题<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">subTitle</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>副标题<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span><span class=\"token class-name\">Form</span></span>\n <span class=\"token attr-name\">title</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>用户登录<span class=\"token punctuation\">\"</span></span>\n <span class=\"token attr-name\">controls</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">[</span>\n <span class=\"token punctuation\">{</span>\n type<span class=\"token operator\">:</span> <span class=\"token string\">'text'</span><span class=\"token punctuation\">,</span>\n name<span class=\"token operator\">:</span> <span class=\"token string\">'username'</span><span class=\"token punctuation\">,</span>\n label<span class=\"token operator\">:</span> <span class=\"token string\">'用户名'</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span></span>\n <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span><span class=\"token class-name\">Page</span></span><span class=\"token punctuation\">></span></span>\n</code></pre>\n<p>把以上配置方式换成 amis JSON, 则是:</p>\n<pre><code class=\"lang-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"page\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"页面标题\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"subTitle\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"副标题\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"body\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"form\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"用户登录\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"controls\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"text\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"username\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"label\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"用户名\"</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">]</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>那么,amis 是如何将 JSON 转成组件的呢?直接根据节点的 type 去跟组件一一对应?这样会重名,比如在表格里面展示的类型 <code>text</code> 跟表单里面的 <code>text</code> 是完全不一样的,一个负责展示,一个却负责输入。所以说一个节点要被什么组件渲染,还需要携带上下文(context)信息。</p>\n<p>如何携带上下文(context)信息?amis 中是用节点的路径(path)来作为上下文信息。从上面的例子来看,一共有三个节点,path 信息分别是。</p>\n<ul>\n<li><code>page</code> 页面节点</li>\n<li><code>page/body/form</code> 表单节点</li>\n<li><code>page/body/form/controls/0/text</code> 文本框节点。</li>\n</ul>\n<p>根据 path 的信息就能很容易注册组件跟节点对应了。</p>\n<p>Page 组件的示例代码</p>\n<pre><code class=\"lang-jsx\">@<span class=\"token function\">Renderer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n test<span class=\"token operator\">:</span> <span class=\"token regex\">/^page$/</span>\n <span class=\"token comment\">// ... 其他信息隐藏了</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">PageRenderer</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// ... 其他信息隐藏了</span>\n <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>\n title<span class=\"token punctuation\">,</span>\n body<span class=\"token punctuation\">,</span>\n render <span class=\"token comment\">// 用来渲染孩子节点,如果当前是叶子节点则可以忽略。</span>\n <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">;</span>\n <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>page<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>body-container<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token punctuation\">{</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token string\">'body'</span><span class=\"token punctuation\">,</span> body<span class=\"token punctuation\">)</span> <span class=\"token comment\">/*渲染孩子节点*/</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span>\n <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>Form 组件的示例代码</p>\n<pre><code class=\"lang-jsx\">@<span class=\"token function\">Renderer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n test<span class=\"token operator\">:</span> <span class=\"token regex\">/(^|\\/)form$/</span>\n <span class=\"token comment\">// ... 其他信息隐藏了</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">FormRenderer</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// ... 其他信息隐藏了</span>\n <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>\n title<span class=\"token punctuation\">,</span>\n controls<span class=\"token punctuation\">,</span>\n render <span class=\"token comment\">// 用来渲染孩子节点,如果当前是叶子节点则可以忽略。</span>\n <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">;</span>\n <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>form</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>form<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token punctuation\">{</span>controls<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">control<span class=\"token punctuation\">,</span> index</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>form-item<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">key</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>index<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token punctuation\">{</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>index<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/control</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> control<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span>\n <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>form</span><span class=\"token punctuation\">></span></span>\n <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>Text 组件的示例代码</p>\n<pre><code class=\"lang-jsx\">@<span class=\"token function\">Renderer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n test<span class=\"token operator\">:</span> <span class=\"token regex\">/(^|\\/)form(?:\\/\\d+)?\\/control(?\\/\\d+)?\\/text$/</span>\n <span class=\"token comment\">// ... 其他信息隐藏了</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">FormItemTextRenderer</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// ... 其他信息隐藏了</span>\n <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>\n label<span class=\"token punctuation\">,</span>\n name<span class=\"token punctuation\">,</span>\n onChange\n <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">;</span>\n <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>form-group<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>label</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>label<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>label</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>input</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>text<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">onChange</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">onChange</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>currentTarget<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n );\n }\n}</span>\n</code></pre>\n<p>那么渲染过程就是根据节点 path 信息,跟组件池中的组件 <code>test</code> (检测) 信息做匹配,如果命中,则把当前节点转给对应组件渲染,节点中其他属性将作为目标组件的 props。需要注意的是,如果是容器组件,比如以上例子中的 <code>page</code> 组件,从 props 中拿到的 <code>body</code> 是一个子节点,由于节点类型是不固定,由使用者决定,所以不能直接完成渲染,所以交给属性中下发的 <code>render</code> 方法去完成渲染,<code>{render('body', body)}</code>,他的工作就是拿子节点的 path 信息去组件池里面找到对应的渲染器,然后交给对应组件去完成渲染。</p>\n<h3><a class=\"anchor\" name=\"%E7%BC%96%E5%86%99%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6\" href=\"#%E7%BC%96%E5%86%99%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>编写自定义组件</h3><p>了解了基本原理后,来看个简单的例子:</p>\n<pre><code class=\"lang-jsx\"><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span>Renderer<span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'amis'</span><span class=\"token punctuation\">;</span>\n\n@<span class=\"token function\">Renderer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n test<span class=\"token operator\">:</span> <span class=\"token regex\">/(^|\\/)my\\-renderer$/</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">CustomRenderer</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>tip<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">;</span>\n <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">这是自定义组件:</span><span class=\"token punctuation\">{</span>tip<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>有了以上这段代码后,就可以这样使用了。</p>\n<pre><code class=\"lang-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"page\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"自定义组件示例\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"body\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"my-renderer\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"tip\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"简单示例\"</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>看了前面<a href=\"#%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86\">amis 工作原理</a>应该不难理解,这里注册一个 React 组件,当节点的 path 信息是 <code>my-renderer</code> 结尾时,交给当前组件来完成渲染。</p>\n<p>如果这个组件还能通过 <code>children</code> 属性添加子节点,则需要使用下面这种写法:</p>\n<pre><code class=\"lang-jsx\"><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span>Renderer<span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'amis'</span><span class=\"token punctuation\">;</span>\n\n@<span class=\"token function\">Renderer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n test<span class=\"token operator\">:</span> <span class=\"token regex\">/(^|\\/)my\\-renderer2$/</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">CustomRenderer</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>tip<span class=\"token punctuation\">,</span> body<span class=\"token punctuation\">,</span> render<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">;</span>\n <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">这是自定义组件:</span><span class=\"token punctuation\">{</span>tip<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token punctuation\">{</span>body <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>container<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token punctuation\">{</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token string\">'body'</span><span class=\"token punctuation\">,</span> body<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// 这里的信息会作为 props 传递给子组件,一般情况下都不需要这个</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span>\n <span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span>\n <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>有了以上这段代码后,就可以这样使用了。</p>\n<pre><code class=\"lang-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"page\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"自定义组件示例\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"body\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"my-renderer2\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"tip\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"简单示例\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"body\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"form\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"controls\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"text\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"label\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"用户名\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"usename\"</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">]</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>跟第一个列子不同的地方是,这里多了个 <code>render</code> 方法,这个方法就是专门用来渲染子节点的。来看下参数说明:</p>\n<ul>\n<li><code>region</code> 区域名称,你有可能有多个区域可以作为容器,请不要重复。</li>\n<li><code>node</code> 子节点。</li>\n<li><code>props</code> 可选,可以通过此对象跟子节点通信等。</li>\n</ul>\n<h3><a class=\"anchor\" name=\"%E8%A1%A8%E5%8D%95%E9%A1%B9%E7%9A%84%E6%89%A9%E5%B1%95\" href=\"#%E8%A1%A8%E5%8D%95%E9%A1%B9%E7%9A%84%E6%89%A9%E5%B1%95\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>表单项的扩展</h3><p>以上是普通渲染器的注册方式,如果是表单项,为了更简单的扩充,请使用 <code>FormItem</code> 注解,而不是 <code>Renderer</code>。 原因是如果用 <code>FormItem</code> 是不用关心:label 怎么摆,表单验证器怎么实现,如何适配表单的 3 中展现方式(水平、上下和内联模式),而只用关心:有了值后如何回显,响应用户交互设置新值。</p>\n<pre><code class=\"lang-jsx\"><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span>FormItem<span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'amis'</span><span class=\"token punctuation\">;</span>\n\n@<span class=\"token function\">FormItem</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n type<span class=\"token operator\">:</span> <span class=\"token string\">'custom'</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">MyFormItem</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>value<span class=\"token punctuation\">,</span> onChange<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">;</span>\n\n <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">这个是个自定义组件</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">当前值:</span><span class=\"token punctuation\">{</span>value<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>a</span>\n <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>btn btn-default<span class=\"token punctuation\">\"</span></span>\n <span class=\"token attr-name\">onClick</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">onChange</span><span class=\"token punctuation\">(</span>Math<span class=\"token punctuation\">.</span><span class=\"token function\">round</span><span class=\"token punctuation\">(</span>Math<span class=\"token punctuation\">.</span><span class=\"token function\">random</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">10000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span>\n <span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n 随机修改\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>a</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span>\n <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>有了以上这段代码后,就可以这样使用了。</p>\n<pre><code class=\"lang-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"page\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"自定义组件示例\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"body\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"form\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"controls\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"text\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"label\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"用户名\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"usename\"</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"custom\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"label\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"随机值\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"random\"</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">]</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<blockquote>\n<p>注意: 使用 FormItem 默认是严格模式,即只有必要的属性变化才会重新渲染,有可能满足不了你的需求,如果忽略性能问题,可以传入 <code>strictMode</code>: <code>false</code> 来关闭。</p>\n</blockquote>\n<p>表单项开发主要关心两件事。</p>\n<ol>\n<li>呈现当前值。如以上例子,通过 <code>this.props.value</code> 判定如果勾选了则显示<code>已勾选</code>,否则显示<code>请勾选</code>。</li>\n<li>接收用户交互,通过 <code>this.props.onChange</code> 修改表单项值。如以上例子,当用户点击按钮时,切换当前选中的值。</li>\n</ol>\n<p>至于其他功能如:label/description 的展示、表单验证功能、表单布局(常规、左右或者内联)等等,只要是通过 FormItem 注册进去的都无需自己实现。</p>\n<p>需要注意,获取或者修改的是什么值跟配置中 <code>type</code> 并列的 <code>name</code> 属性有关,也就是说直接关联某个变量,自定义中直接通过 props 下发了某个指定变量的值和修改的方法。如果你想获取其他数据,或者设置其他数据可以看下以下说明:</p>\n<ul>\n<li><code>获取其他数据</code> 可以通过 <code>this.props.data</code> 查看,作用域中所有的数据都在这了。</li>\n<li><code>设置其他数据</code> 可以通过 <code>this.props.onBulkChange</code>, 比如: <code>this.props.onBulkChange({a: 1, b: 2})</code> 等于同时设置了两个值。当做数据填充的时候,这个方法很有用。</li>\n</ul>\n<h3><a class=\"anchor\" name=\"%E5%85%B6%E5%AE%83%E9%AB%98%E7%BA%A7%E5%AE%9A%E5%88%B6\" href=\"#%E5%85%B6%E5%AE%83%E9%AB%98%E7%BA%A7%E5%AE%9A%E5%88%B6\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>其它高级定制</h3><p>下面是一些不太常用的 amis 扩展方式及技巧。</p>\n<h4><a class=\"anchor\" name=\"%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AA%8C%E8%AF%81%E5%99%A8\" href=\"#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AA%8C%E8%AF%81%E5%99%A8\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>自定义验证器</h4><p>如果 amis <a href=\"/amis/docs/renderers/Form/FormItem#\">自带的验证</a>能满足需求了,则不需要关心。组件可以有自己的验证逻辑。</p>\n<pre><code class=\"lang-jsx\"><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span>FormItem<span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'amis'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> cx <span class=\"token keyword\">from</span> <span class=\"token string\">'classnames'</span><span class=\"token punctuation\">;</span>\n\n@<span class=\"token function\">FormItem</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n type<span class=\"token operator\">:</span> <span class=\"token string\">'custom-checkbox'</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">CustomCheckbox</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n <span class=\"token function\">validate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// 通过 this.props.value 可以知道当前值。</span>\n\n <span class=\"token keyword\">return</span> isValid <span class=\"token operator\">?</span> <span class=\"token string\">''</span> <span class=\"token operator\">:</span> <span class=\"token string\">'不合法,说明不合法原因。'</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token comment\">// ... 其他省略了</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>上面的栗子只是简单说明,另外可以做<code>异步验证</code>,validate 方法可以返回一个 promise。</p>\n<h4><a class=\"anchor\" name=\"optionscontrol\" href=\"#optionscontrol\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>OptionsControl</h4><p>如果你的表单组件性质和 amis 的 Select、Checkboxes、List 差不多,用户配置配置 source 可通过 API 拉取选项,你可以用 OptionsControl 取代 FormItem 这个注解。</p>\n<p>用法是一样,功能方面主要多了以下功能。</p>\n<ul>\n<li>可以配置 options,options 支持配置 visibleOn hiddenOn 等表达式</li>\n<li>可以配置 <code>source</code> 换成动态拉取 options 的功能,source 中有变量依赖会自动重新拉取。</li>\n<li>下发了这些 props,可以更方便选项。<ul>\n<li><code>options</code> 不管是用户配置的静态 options 还是配置 source 拉取的,下发到组件已经是最终的选项了。</li>\n<li><code>selectedOptions</code> 数组类型,当前用户选中的选项。</li>\n<li><code>loading</code> 当前选项是否在加载</li>\n<li><code>onToggle</code> 切换一个选项的值</li>\n<li><code>onToggleAll</code> 切换所有选项的值,类似于全选。</li>\n</ul>\n</li>\n</ul>\n<h4><a class=\"anchor\" name=\"%E7%BB%84%E4%BB%B6%E9%97%B4%E9%80%9A%E4%BF%A1\" href=\"#%E7%BB%84%E4%BB%B6%E9%97%B4%E9%80%9A%E4%BF%A1\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>组件间通信</h4><p>关于组件间通信,amis 中有个机制就是,把需要被引用的组件设置一个 name 值,然后其他组件就可以通过这个 name 与其通信,比如这个<a href=\"/amis/docs/advanced#组件间通信\">栗子</a>。其实内部是依赖于内部的一个 Scoped Context。你的组件希望可以被别的组件引用,你需要把自己注册进去,默认自定义的非表单类组件并没有把自己注册进去,可以参考以下代码做添加。</p>\n<pre><code class=\"lang-js\"><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span>Renderer<span class=\"token punctuation\">,</span> ScopedContext<span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'amis'</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">Renderer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n test<span class=\"token operator\">:</span> <span class=\"token regex\">/(?:^|\\/)my\\-renderer$/</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">CustomRenderer</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">static</span> contextType <span class=\"token operator\">=</span> ScopedContext<span class=\"token punctuation\">;</span>\n\n <span class=\"token function\">componentWillMount</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">const</span> scoped <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>context<span class=\"token punctuation\">;</span>\n scoped<span class=\"token punctuation\">.</span><span class=\"token function\">registerComponent</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n\n <span class=\"token function\">componentWillUnmount</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">const</span> scoped <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>context<span class=\"token punctuation\">;</span>\n scoped<span class=\"token punctuation\">.</span><span class=\"token function\">unRegisterComponent</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n\n <span class=\"token comment\">// 其他部分省略了。</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>把自己注册进去了,其他组件就能引用到了。同时,如果你想找别的组件,也同样是通过 scoped 这个 context,如: <code>scoped.getComponentByName("xxxName")</code> 这样就能拿到目标组件的实例了(前提是目标组件已经配置了 name 为 <code>xxxName</code>)。</p>\n<h4><a class=\"anchor\" name=\"%E5%85%B6%E4%BB%96%E5%8A%9F%E8%83%BD%E6%96%B9%E6%B3%95\" href=\"#%E5%85%B6%E4%BB%96%E5%8A%9F%E8%83%BD%E6%96%B9%E6%B3%95\" aria-hidden=\"true\"><svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>其他功能方法</h4><p>自定义的渲染器 props 会下发一个非常有用的 env 对象。这个 env 有以下功能方法。</p>\n<ul>\n<li><code>env.fetcher</code> 可以用来做 ajax 请求如: <code>this.props.env.fetcher('xxxAPi', this.props.data).then((result) => console.log(result))</code></li>\n<li><code>env.confirm</code> 确认框,返回一个 promise 等待用户确认如: <code>this.props.env.confirm('你确定要这么做?').then((confirmed) => console.log(confirmed))</code></li>\n<li><code>env.alert</code> 用 Modal 实现的弹框,个人觉得更美观。</li>\n<li><code>env.notify</code> toast 某个消息 如: <code>this.props.env.notify("error", "出错了")</code></li>\n<li><code>env.jumpTo</code> 页面跳转。</li>\n</ul>\n\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/docs/custom.md\">/docs/custom.md</a>。</div>",
|
||
"toc": {
|
||
"label": "目录",
|
||
"type": "toc",
|
||
"children": [
|
||
{
|
||
"label": "临时扩展",
|
||
"fragment": "%E4%B8%B4%E6%97%B6%E6%89%A9%E5%B1%95",
|
||
"fullPath": "#%E4%B8%B4%E6%97%B6%E6%89%A9%E5%B1%95",
|
||
"level": 2
|
||
},
|
||
{
|
||
"label": "注册自定义类型",
|
||
"fragment": "%E6%B3%A8%E5%86%8C%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B",
|
||
"fullPath": "#%E6%B3%A8%E5%86%8C%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B",
|
||
"level": 2,
|
||
"children": [
|
||
{
|
||
"label": "工作原理",
|
||
"fragment": "%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86",
|
||
"fullPath": "#%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86",
|
||
"level": 3
|
||
},
|
||
{
|
||
"label": "编写自定义组件",
|
||
"fragment": "%E7%BC%96%E5%86%99%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6",
|
||
"fullPath": "#%E7%BC%96%E5%86%99%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6",
|
||
"level": 3
|
||
},
|
||
{
|
||
"label": "表单项的扩展",
|
||
"fragment": "%E8%A1%A8%E5%8D%95%E9%A1%B9%E7%9A%84%E6%89%A9%E5%B1%95",
|
||
"fullPath": "#%E8%A1%A8%E5%8D%95%E9%A1%B9%E7%9A%84%E6%89%A9%E5%B1%95",
|
||
"level": 3
|
||
},
|
||
{
|
||
"label": "其它高级定制",
|
||
"fragment": "%E5%85%B6%E5%AE%83%E9%AB%98%E7%BA%A7%E5%AE%9A%E5%88%B6",
|
||
"fullPath": "#%E5%85%B6%E5%AE%83%E9%AB%98%E7%BA%A7%E5%AE%9A%E5%88%B6",
|
||
"level": 3,
|
||
"children": [
|
||
{
|
||
"label": "自定义验证器",
|
||
"fragment": "%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AA%8C%E8%AF%81%E5%99%A8",
|
||
"fullPath": "#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AA%8C%E8%AF%81%E5%99%A8",
|
||
"level": 4
|
||
},
|
||
{
|
||
"label": "OptionsControl",
|
||
"fragment": "optionscontrol",
|
||
"fullPath": "#optionscontrol",
|
||
"level": 4
|
||
},
|
||
{
|
||
"label": "组件间通信",
|
||
"fragment": "%E7%BB%84%E4%BB%B6%E9%97%B4%E9%80%9A%E4%BF%A1",
|
||
"fullPath": "#%E7%BB%84%E4%BB%B6%E9%97%B4%E9%80%9A%E4%BF%A1",
|
||
"level": 4
|
||
},
|
||
{
|
||
"label": "其他功能方法",
|
||
"fragment": "%E5%85%B6%E4%BB%96%E5%8A%9F%E8%83%BD%E6%96%B9%E6%B3%95",
|
||
"fullPath": "#%E5%85%B6%E4%BB%96%E5%8A%9F%E8%83%BD%E6%96%B9%E6%B3%95",
|
||
"level": 4
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"level": 0
|
||
}
|
||
};
|
||
|
||
});
|