<!DOCTYPE html><html><head>
<title>README</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- <link rel="stylesheet" href="file:////Users/chengkaiquan/.vscode/extensions/shd101wyy.markdown-preview-enhanced-0.6.0/node_modules/@shd101wyy/mume/dependencies/katex/katex.min.css"> -->
<style>
/**
* prism.js Github theme based on GitHub's theme.
* @author Sam Clarke
*/
code[class*="language-"],
pre[class*="language-"] {
color: #333;
background: none;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.4;
-moz-tab-size: 8;
-o-tab-size: 8;
tab-size: 8;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: .8em;
overflow: auto;
/* border: 1px solid #ddd; */
border-radius: 3px;
/* background: #fff; */
background: #f5f5f5;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
background: #f5f5f5;
}
.token.comment,
.token.blockquote {
color: #969896;
}
.token.cdata {
color: #183691;
}
.token.doctype,
.token.punctuation,
.token.variable,
.token.macro.property {
color: #333;
}
.token.operator,
.token.important,
.token.keyword,
.token.rule,
.token.builtin {
color: #a71d5d;
}
.token.string,
.token.url,
.token.regex,
.token.attr-value {
color: #183691;
}
.token.property,
.token.number,
.token.boolean,
.token.entity,
.token.atrule,
.token.constant,
.token.symbol,
.token.command,
.token.code {
color: #0086b3;
}
.token.tag,
.token.selector,
.token.prolog {
color: #63a35c;
}
.token.function,
.token.namespace,
.token.pseudo-element,
.token.class,
.token.class-name,
.token.pseudo-class,
.token.id,
.token.url-reference .token.variable,
.token.attr-name {
color: #795da3;
}
.token.entity {
cursor: help;
}
.token.title,
.token.title .token.punctuation {
font-weight: bold;
color: #1d3e81;
}
.token.list {
color: #ed6a43;
}
.token.inserted {
background-color: #eaffea;
color: #55a532;
}
.token.deleted {
background-color: #ffecec;
color: #bd2c00;
}
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
/* JSON */
.language-json .token.property {
color: #183691;
}
.language-markup .token.tag .token.punctuation {
color: #333;
}
/* CSS */
code.language-css,
.language-css .token.function {
color: #0086b3;
}
/* YAML */
.language-yaml .token.atrule {
color: #63a35c;
}
code.language-yaml {
color: #183691;
}
/* Ruby */
.language-ruby .token.function {
color: #333;
}
/* Markdown */
.language-markdown .token.url {
color: #795da3;
}
/* Makefile */
.language-makefile .token.symbol {
color: #795da3;
}
.language-makefile .token.variable {
color: #183691;
}
.language-makefile .token.builtin {
color: #0086b3;
}
/* Bash */
.language-bash .token.keyword {
color: #0086b3;
}
/* highlight */
pre[data-line] {
position: relative;
padding: 1em 0 1em 3em;
}
pre[data-line] .line-highlight-wrapper {
position: absolute;
top: 0;
left: 0;
background-color: transparent;
display: block;
width: 100%;
}
pre[data-line] .line-highlight {
position: absolute;
left: 0;
right: 0;
padding: inherit 0;
margin-top: 1em;
background: hsla(24, 20%, 50%,.08);
background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
pointer-events: none;
line-height: inherit;
white-space: pre;
}
pre[data-line] .line-highlight:before,
pre[data-line] .line-highlight[data-end]:after {
content: attr(data-start);
position: absolute;
top: .4em;
left: .6em;
min-width: 1em;
padding: 0 .5em;
background-color: hsla(24, 20%, 50%,.4);
color: hsl(24, 20%, 95%);
font: bold 65%/1.5 sans-serif;
text-align: center;
vertical-align: .3em;
border-radius: 999px;
text-shadow: none;
box-shadow: 0 1px white;
}
pre[data-line] .line-highlight[data-end]:after {
content: attr(data-end);
top: auto;
bottom: .4em;
}html body{font-family:"Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif;font-size:16px;line-height:1.6;color:#333;background-color:#fff;overflow:initial;box-sizing:border-box;word-wrap:break-word}html body>:first-child{margin-top:0}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{line-height:1.2;margin-top:1em;margin-bottom:16px;color:#000}html body h1{font-size:2.25em;font-weight:300;padding-bottom:.3em}html body h2{font-size:1.75em;font-weight:400;padding-bottom:.3em}html body h3{font-size:1.5em;font-weight:500}html body h4{font-size:1.25em;font-weight:600}html body h5{font-size:1.1em;font-weight:600}html body h6{font-size:1em;font-weight:600}html body h1,html body h2,html body h3,html body h4,html body h5{font-weight:600}html body h5{font-size:1em}html body h6{color:#5c5c5c}html body strong{color:#000}html body del{color:#5c5c5c}html body a:not([href]){color:inherit;text-decoration:none}html body a{color:#08c;text-decoration:none}html body a:hover{color:#00a3f5;text-decoration:none}html body img{max-width:100%}html body>p{margin-top:0;margin-bottom:16px;word-wrap:break-word}html body>ul,html body>ol{margin-bottom:16px}html body ul,html body ol{padding-left:2em}html body ul.no-list,html body ol.no-list{padding:0;list-style-type:none}html body ul ul,html body ul ol,html body ol ol,html body ol ul{margin-top:0;margin-bottom:0}html body li{margin-bottom:0}html body li.task-list-item{list-style:none}html body li>p{margin-top:0;margin-bottom:0}html body .task-list-item-checkbox{margin:0 .2em .25em -1.8em;vertical-align:middle}html body .task-list-item-checkbox:hover{cursor:pointer}html body blockquote{margin:16px 0;font-size:inherit;padding:0 15px;color:#5c5c5c;background-color:#f0f0f0;border-left:4px solid #d6d6d6}html body blockquote>:first-child{margin-top:0}html body blockquote>:last-child{margin-bottom:0}html body hr{height:4px;margin:32px 0;background-color:#d6d6d6;border:0 none}html body table{margin:10px 0 15px 0;border-collapse:collapse;border-spacing:0;display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}html body table th{font-weight:bold;color:#000}html body table td,html body table th{border:1px solid #d6d6d6;padding:6px 13px}html body dl{padding:0}html body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:bold}html body dl dd{padding:0 16px;margin-bottom:16px}html body code{font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:.85em !important;color:#000;background-color:#f0f0f0;border-radius:3px;padding:.2em 0}html body code::before,html body code::after{letter-spacing:-0.2em;content:"00円a0"}html body pre>code{padding:0;margin:0;font-size:.85em !important;word-break:normal;white-space:pre;background:transparent;border:0}html body .highlight{margin-bottom:16px}html body .highlight pre,html body pre{padding:1em;overflow:auto;font-size:.85em !important;line-height:1.45;border:#d6d6d6;border-radius:3px}html body .highlight pre{margin-bottom:0;word-break:normal}html body pre code,html body pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}html body pre code:before,html body pre tt:before,html body pre code:after,html body pre tt:after{content:normal}html body p,html body blockquote,html body ul,html body ol,html body dl,html body pre{margin-top:0;margin-bottom:16px}html body kbd{color:#000;border:1px solid #d6d6d6;border-bottom:2px solid #c7c7c7;padding:2px 4px;background-color:#f0f0f0;border-radius:3px}@media print{html body{background-color:#fff}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{color:#000;page-break-after:avoid}html body blockquote{color:#5c5c5c}html body pre{page-break-inside:avoid}html body table{display:table}html body img{display:block;max-width:100%;max-height:100%}html body pre,html body code{word-wrap:break-word;white-space:pre}}.markdown-preview{width:100%;height:100%;box-sizing:border-box}.markdown-preview .pagebreak,.markdown-preview .newpage{page-break-before:always}.markdown-preview pre.line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}.markdown-preview pre.line-numbers>code{position:relative}.markdown-preview pre.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:1em;font-size:100%;left:0;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.markdown-preview pre.line-numbers .line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.markdown-preview pre.line-numbers .line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.markdown-preview .mathjax-exps .MathJax_Display{text-align:center !important}.markdown-preview:not([for="preview"]) .code-chunk .btn-group{display:none}.markdown-preview:not([for="preview"]) .code-chunk .status{display:none}.markdown-preview:not([for="preview"]) .code-chunk .output-div{margin-bottom:16px}.scrollbar-style::-webkit-scrollbar{width:8px}.scrollbar-style::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}.scrollbar-style::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,0.66);border:4px solid rgba(150,150,150,0.66);background-clip:content-box}html body[for="html-export"]:not([data-presentation-mode]){position:relative;width:100%;height:100%;top:0;left:0;margin:0;padding:0;overflow:auto}html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{position:relative;top:0}@media screen and (min-width:914px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{padding:2em calc(50% - 457px + 2em)}}@media screen and (max-width:914px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{font-size:14px !important;padding:1em}}@media print{html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn{display:none}}html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn{position:fixed;bottom:8px;left:8px;font-size:28px;cursor:pointer;color:inherit;z-index:99;width:32px;text-align:center;opacity:.4}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] #sidebar-toc-btn{opacity:1}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc{position:fixed;top:0;left:0;width:300px;height:100%;padding:32px 0 48px 0;font-size:14px;box-shadow:0 0 4px rgba(150,150,150,0.33);box-sizing:border-box;overflow:auto;background-color:inherit}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar{width:8px}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,0.66);border:4px solid rgba(150,150,150,0.66);background-clip:content-box}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc a{text-decoration:none}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc ul{padding:0 1.6em;margin-top:.8em}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc li{margin-bottom:.8em}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc ul{list-style-type:none}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{left:300px;width:calc(100% - 300px);padding:2em calc(50% - 457px - 150px);margin:0;box-sizing:border-box}@media screen and (max-width:1274px){html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{width:100%}}html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .markdown-preview{left:50%;transform:translateX(-50%)}html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .md-sidebar-toc{display:none}
/* Please visit the URL below for more information: */
/* https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */
</style>
</head>
<body for="html-export">
<div class="mume markdown-preview ">
<h1 class="mume-header" id="leggo">leggo</h1>
<p>拖拽式前端表单生成低代码工具~</p>
<blockquote>
<ul>
<li>演示地址:<a href="https://kerrycodes.github.io/">https://kerrycodes.github.io/</a></li>
<li>Github:<a href="https://github.com/KerryCodes/leggo">https://github.com/KerryCodes/leggo</a></li>
<li>安装:<code>npm i leggo</code></li>
</ul>
</blockquote>
<h2 class="mume-header" id="story">story</h2>
<p>因为老员工的离职,我接手了一个完全由表单组成的发布模块,之前我并没有看过业务源码。后续因为接入新的需求而冲进去维护这坨代码。注意我用了“坨”这个量词,你应该明白我在说什么。因为整个模块缺少顶层设计,导致维护成本极高,频频报bug。于是开始思考为什么不能通过拖拽直接生成和维护这些表单呢?于是leggo就此诞生,名字来源于乐高Lego,寓意像搭积木一样完成表单的设计。</p>
<h2 class="mume-header" id="leggo%E5%93%B2%E5%AD%A6">leggo哲学</h2>
<ul>
<li>
<p>虽然利用了“拖拽”这一最直观简单的交互方式。但<strong>leggo并非面向非前端人员,Leggo是一个为专业前端开发者提升效率的工具</strong></p>
</li>
<li>
<p><strong>leggo从一开始就没有想要做成一个大而全的表单配置解决方案。</strong> 第一版甚至只是花了一个下午便告完成。所以leggo并不会为了能够实现复杂逻辑的表单组件而放弃易用性。leggo真正要做的是帮助前端开发快速搭建和维护表单结构,轻松完成那些无脑重复搬砖的表单组件。这使得前端开发能够更专注于开发拥有特定复杂逻辑交互的表单组件。</p>
</li>
<li>
<p><strong>leggo保持了几乎完全开放的自由拓展空间。</strong> 不但可拖拽的表单组件库能够被自由注册。所有通过leggo模板渲染的组件也可以轻松的被整体覆盖、组装或重写属性。你甚至可以暴露各种公共状态和函数给leggo消费。所以leggo并非只能应用于简单的表单设计场景,这完全取决于开发者的大胆拓展。</p>
</li>
<li>
<p><strong>上手成本极低。</strong> 如果你熟悉React和Antd,则你只需要学习1-2个leggo的Api就可以开始在项目中部署。Antd库中<code>Form</code>、<code>Form.Item</code>以及相关input组件的所有属性和事件仍旧可以正常定义和使用。</p>
</li>
</ul>
<h2 class="mume-header" id="%E5%9F%BA%E7%A1%80%E5%BA%94%E7%94%A8">基础应用</h2>
<p>假设你已经通过<a href="https://kerrycodes.github.io/">leggo表单设计器</a>生成了一个表单模板(获得一个JSON对象,即下列代码中<code>schemaModel</code>),则仅通过以下2行代码你就得到了实际需要的表单:</p>
<pre data-role="codeBlock" data-info="typeScript" class="language-typescript"><span class="token keyword">export</span> <span class="token keyword">const</span> schemaModel<span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token comment">//JSON</span>
<span class="token punctuation">}</span>
</pre><pre data-role="codeBlock" data-info="typeScript" class="language-typescript"><span class="token keyword">export</span> <span class="token punctuation">{</span> LeggoForm <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'leggo'</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> schemaModel <span class="token punctuation">}</span> form <span class="token string">'./schemaModel'</span>
<span class="token keyword">function</span> <span class="token function">MyForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">const</span> leggo<span class="token operator">=</span> LeggoForm<span class="token punctuation">.</span><span class="token function">useLeggo</span><span class="token punctuation">(</span>schemaModel<span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token operator"><</span>LeggoForm leggo<span class="token operator">=</span><span class="token punctuation">{</span>leggo<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span>
<span class="token punctuation">}</span>
</pre><p>我们从<code>leggo</code>导出了<code>LeggoForm</code>,而<code>schemaModel</code>是通过Leggo表单设计器生成的JSON,<code>LeggoForm</code>这个高阶组件会将模版JSON解析并渲染成实际的表单组件。</p>
<p>从使用的角度来说<code>LeggoForm</code>和Antd中的<code>Form</code>几乎没有任何差别(除了必须要挂载<code>leggo</code>这个属性)。你可以在<code>LeggoForm</code>上定义任何<code>Form</code>组件允许的属性并正常运行,比如像以下这样:</p>
<pre data-role="codeBlock" data-info="typeScript" class="language-typescript"><span class="token keyword">function</span> <span class="token function">MyForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">const</span> leggo<span class="token operator">=</span> LeggoForm<span class="token punctuation">.</span><span class="token function">useLeggo</span><span class="token punctuation">(</span>schemaModel<span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token punctuation">[</span>form<span class="token punctuation">]</span><span class="token operator">=</span> Form<span class="token punctuation">.</span><span class="token function">useForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
<span class="token operator"><</span>LeggoForm leggo<span class="token operator">=</span><span class="token punctuation">{</span>leggo<span class="token punctuation">}</span>
form<span class="token operator">=</span><span class="token punctuation">{</span>form<span class="token punctuation">}</span>
labelCol<span class="token operator">=</span><span class="token punctuation">{</span> span<span class="token operator">:</span> <span class="token number">6</span> <span class="token punctuation">}</span>
wrapperCol<span class="token operator">=</span><span class="token punctuation">{</span> span<span class="token operator">:</span> <span class="token number">14</span> <span class="token punctuation">}</span>
onValuesChange<span class="token operator">=</span><span class="token punctuation">{</span>handleValuesChange<span class="token punctuation">}</span>
onFinish<span class="token operator">=</span><span class="token punctuation">{</span>hanldeFinish<span class="token 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 operator">></span>
<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</pre><p>考虑到你的表单模板<code>schemaModel</code>可能不是存在本地,而需要从服务器异步远程拉取,则你可以这样部署:</p>
<pre data-role="codeBlock" data-info="typeScript" class="language-typescript"><span class="token keyword">function</span> <span class="token function">MyForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">const</span> leggo<span class="token operator">=</span> LeggoForm<span class="token punctuation">.</span><span class="token function">useLeggo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token punctuation">[</span>form<span class="token punctuation">]</span><span class="token operator">=</span> Form<span class="token punctuation">.</span><span class="token function">useForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
leggo<span class="token punctuation">.</span><span class="token function">resetSchemaModel</span><span class="token punctuation">(</span>schemaModel<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>schemaModel<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
<span class="token operator"><</span>LeggoForm leggo<span class="token operator">=</span><span class="token punctuation">{</span>leggo<span class="token punctuation">}</span>
form<span class="token operator">=</span><span class="token punctuation">{</span>form<span class="token punctuation">}</span>
labelCol<span class="token operator">=</span><span class="token punctuation">{</span> span<span class="token operator">:</span> <span class="token number">6</span> <span class="token punctuation">}</span>
wrapperCol<span class="token operator">=</span><span class="token punctuation">{</span> span<span class="token operator">:</span> <span class="token number">14</span> <span class="token punctuation">}</span>
onValuesChange<span class="token operator">=</span><span class="token punctuation">{</span>handleValuesChange<span class="token punctuation">}</span>
onFinish<span class="token operator">=</span><span class="token punctuation">{</span>hanldeFinish<span class="token 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 operator">></span>
<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</pre><p>简单的表单通过以上代码已经足够部署应用了。下面我们逐步引入更复杂的场景。以下是我们需要的一个表单组件,可以注意到在组件到右侧有一个“同步”按钮。这种个性化的组件并没有办法通过拖拽完成全部设计。</p>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d67b3b3c16754116afb9a96528ddb61a~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p>
<p>不要着急,我们先通过拖拽完成左侧经典表单组件部分的设计。右侧的按钮我们只需要在渲染表单前通过中间件函数注入即可,中间件函数在leggo中是作为表单渲染前灵活拓展的手段之一。代码如下:</p>
<pre data-role="codeBlock" data-info="typeScript" class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> TConfigs <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'leggo/lib/interface'</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">MyForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">const</span> leggo<span class="token operator">=</span> LeggoForm<span class="token punctuation">.</span><span class="token function">useLeggo</span><span class="token punctuation">(</span>schemaModel<span class="token punctuation">,</span> middleware<span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token punctuation">[</span>form<span class="token punctuation">]</span><span class="token operator">=</span> Form<span class="token punctuation">.</span><span class="token function">useForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment">// 异步的情况</span>
<span class="token comment">// useEffect(() => {</span>
<span class="token comment">// leggo.resetSchemaModel(schemaModel, middleware)</span>
<span class="token comment">// }, [schemaModel])</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
<span class="token operator"><</span>LeggoForm leggo<span class="token operator">=</span><span class="token punctuation">{</span>leggo<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span>
<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// 定义一个中间件函数</span>
<span class="token keyword">function</span> <span class="token function">middleware</span><span class="token punctuation">(</span>configs<span class="token operator">:</span> TConfigs<span class="token punctuation">)</span> <span class="token punctuation">{</span>
configs<span class="token punctuation">.</span><span class="token function-variable function">Successor</span><span class="token operator">=</span> <span class="token punctuation">(</span>props<span class="token operator">:</span> React<span class="token punctuation">.</span>PropsWithChildren<span class="token operator"><</span><span class="token builtin">any</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
<span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>display<span class="token operator">:</span> <span class="token string">'flex'</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span>
<span class="token punctuation">{</span> props<span class="token punctuation">.</span>children <span class="token punctuation">}</span>
<span class="token operator"><</span>Button<span class="token operator">></span>同步<span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span>
<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</pre><blockquote>
<p>值得注意的是,中间件函数只会在整个<code>schemaModel</code>注入时执行。无论表单后续如何更新和渲染,中间函数都不会运行(除非你又通过<code>leggo.resetSchemaModel</code>重新注入一个新的<code>schemaModel</code>)。所以你不需要担心由中间件函数可能导致的性能问题。</p>
</blockquote>
<p>你会注意到leggo引擎在运行中间件函数时为其注入一个参数<code>configs</code>。这个对象非常重要,它来自<code>schemaModel</code>,你通过表单设计器拖拽和设置的几乎所有参数都存在这个对象中。实际上,我们正是通过中间件函数在改造由表单设计器生成的<code>schemaModel</code>。<code>configs</code>中有2个关键的属性<code>itemProps</code>和<code>inputProps</code>。</p>
<blockquote>
<p><strong>itemProps</strong></p>
<p>itemProps包含的参数有name、label、rules等。没错,这个对象会被直接注入进Form.Item组件:</p>
<p><code><Form.Item {...itemProps} ></Form.Item></code></p>
</blockquote>
<blockquote>
<p><strong>inputProps</strong></p>
<p>inputProps包含的参数有disabled、style、placeholder、htmlType等。这个对象会被直接注入进input相关组件:</p>
<p><code><Input {...inputProps} /></code></p>
<p><code><Checkbox.Group {...inputProps} /></code></p>
<p><code><DatePicker {...inputProps} /></code></p>
</blockquote>
<p>然后你发现在表单渲染前,通过中间件函数你有足够的机会去拓展整个表单的设计,比如:</p>
<pre data-role="codeBlock" data-info="typeScript" class="language-typescript"><span class="token keyword">function</span> <span class="token function">middleware</span><span class="token punctuation">(</span>configs<span class="token operator">:</span> TConfigs<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> itemProps<span class="token punctuation">,</span> inputprops <span class="token punctuation">}</span><span class="token operator">=</span> configs
<span class="token keyword">if</span><span class="token punctuation">(</span>itemProps<span class="token punctuation">.</span>name <span class="token operator">!==</span> <span class="token string">'test'</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span> <span class="token comment">//筛选我们需要改造的表单</span>
itemProps<span class="token punctuation">.</span>label<span class="token operator">=</span> <span class="token string">'test2'</span> <span class="token comment">//我们更换了label</span>
itemProps<span class="token punctuation">.</span>options<span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token comment">//我们更换了选项类组件所需要的options数据</span>
<span class="token punctuation">{</span>label<span class="token operator">:</span> <span class="token string">'浙江'</span><span class="token punctuation">,</span> value<span class="token operator">:</span> <span class="token string">'zj'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>label<span class="token operator">:</span> <span class="token string">'福建'</span><span class="token punctuation">,</span> value<span class="token operator">:</span> <span class="token string">'fj'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span>
configs<span class="token punctuation">.</span><span class="token function-variable function">Successor</span><span class="token operator">=</span> <span class="token punctuation">(</span>props<span class="token operator">:</span> React<span class="token punctuation">.</span>PropsWithChildren<span class="token operator"><</span><span class="token builtin">any</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
<span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>display<span class="token operator">:</span> <span class="token string">'flex'</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span>
<span class="token punctuation">{</span> props<span class="token punctuation">.</span>children <span class="token punctuation">}</span>
<span class="token operator"><</span>Button<span class="token operator">></span>同步<span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span>
<span class="token punctuation">)</span> <span class="token comment">//我们在表单右侧增加了一个按钮</span>
configs<span class="token punctuation">.</span><span class="token function-variable function">SuperSuccessor</span><span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
<span class="token operator"><</span>Form<span class="token punctuation">.</span>Item label<span class="token operator">=</span><span class="token string">"newOne"</span> name<span class="token operator">=</span><span class="token string">"newOne"</span><span class="token operator">></span>
<span class="token operator"><</span>Input <span class="token operator">/</span><span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Item<span class="token operator">></span>
<span class="token punctuation">)</span> <span class="token comment">//我们甚至用一个全新的表单组件完全覆盖和丢弃了原有的表单组件</span>
<span class="token punctuation">}</span>
</pre><blockquote>
<p><strong>Successor 和 SuperSuccessor</strong></p>
<p>对于复杂的表单来说,<code>Successor</code> 和 <code>SuperSuccessor</code>非常有用,它是开发者利用leggo专注于复杂逻辑表单组件的关键。leggo表单设计器中所谓的<strong>占位表单</strong>组件即是为<code>Successor</code> 和 <code>SuperSuccessor</code>的替换操作预留了结构空间。</p>
<p>区别在于,<code>Successor</code>只是对原有的表单组件进行改造(原有的表单组件通过children的方式传给它,<code>itemProps</code>和<code>inputprops</code>仍旧会注入)。而<code>SuperSuccessor</code>则非常激进的覆盖和丢弃了原有的表单组件(<code>itemProps</code>和<code>inputprops</code>也被丢弃)。</p>
</blockquote>
<pre data-role="codeBlock" data-info="js" class="language-javascript"><span class="token operator"><</span><span class="token maybe-class-name">Form</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Item</span></span> <span class="token punctuation">{</span><span class="token spread operator">...</span>itemProps<span class="token punctuation">}</span><span class="token operator">></span>
<span class="token operator"><</span><span class="token maybe-class-name">Successor</span><span class="token operator">></span>
<span class="token operator"><</span><span class="token maybe-class-name">Input</span> <span class="token punctuation">{</span><span class="token spread operator">...</span>inputprops<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span><span class="token maybe-class-name">Successor</span><span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span><span class="token maybe-class-name">Form</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Item</span></span><span class="token operator">></span>
</pre><pre data-role="codeBlock" data-info="js" class="language-javascript"><span class="token operator"><</span><span class="token maybe-class-name">SuperSuccessor</span> <span class="token operator">/</span><span class="token operator">></span>
</pre><p>以上是通过中间件函数一次性的改造<code>schemaModel</code>。而如果你需要随时改变表单的渲染方式,比如<code>disabled</code>属性,则你可以在任意时机通过调用<code>leggo.updateSchema</code>来实现。每个表单组件是单独重渲染的,所以你也不需要考虑性能的问题。如下:</p>
<pre data-role="codeBlock" data-info="typeScript" class="language-typescript"><span class="token comment">// 可以随时调用</span>
leggo<span class="token punctuation">.</span><span class="token function">updateSchema</span><span class="token punctuation">(</span><span class="token string">'select'</span><span class="token punctuation">,</span> configs <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> inputprops <span class="token punctuation">}</span><span class="token operator">=</span> configs
inputprops<span class="token punctuation">.</span>disabled<span class="token operator">=</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 中间件函数实现方式(注意这个函数只会运行一次!):</span>
<span class="token keyword">function</span> <span class="token function">middleware</span><span class="token punctuation">(</span>configs<span class="token operator">:</span> TConfigs<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> itemProps<span class="token punctuation">,</span> inputprops <span class="token punctuation">}</span><span class="token operator">=</span> configs
<span class="token keyword">if</span><span class="token punctuation">(</span>itemProps<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'select'</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
inputprops<span class="token punctuation">.</span>disabled<span class="token operator">=</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</pre><h2 class="mume-header" id="%E9%AB%98%E7%BA%A7%E5%BA%94%E7%94%A8">高级应用</h2>
<p>好的,让我们进一步引入更复杂的设计场景。假设我们需要设计一个允许数据联动的表单,日期组件是否必选由“单选”这个组件的值决定。</p>
<p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/13ce9a7bd22946e2aff84be87c3909a6~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p>
<p>则我们只需要通过leggo表单设计器设置数据关联和简单的逻辑运算操作即可。</p>
<p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0de7822943314e43bc5f5176aa546b5d~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p>
<blockquote>
<p><code>[{label: '必选日期', value: 1}, {label: '非必选日期', value: 2}]</code></p>
</blockquote>
<p>如果我们的关联值是在程序运行时才能拿到的,则我们可以通过在表单实际渲染前传入一个公共状态即可。公共状态既可以是值,也可以是函数,leggo引擎会自动识别。</p>
<p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6a0f5be3652b45a3971430050853e04f~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p>
<p>还有一种常见的场景就是关于Select或Radio等组件需要远程拉取options数据,通过leggo也同样可以很方便实现这样的需求。</p>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c317085f28c74c0da31306ce0f0adb04~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p>
<p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/eeeb114a75d84fec990b4d3d63792e00~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p>
<blockquote>
<p>带有关联按钮的数据都可以设置关联数据</p>
</blockquote>
<h2 class="mume-header" id="leggo%E8%A1%A8%E5%8D%95%E8%AE%BE%E8%AE%A1%E5%99%A8">leggo表单设计器</h2>
<blockquote>
<p>演示地址:<a href="https://kerrycodes.github.io/">https://kerrycodes.github.io/</a></p>
</blockquote>
<p>如果你需要在项目中直接部署这个表单设计器,则可以直接引入<code>LeggoConfigs</code>组件,<code>onGetSchemaModel</code>属性会在<code>schemaModel</code>生成后自动注入和执行,样式需要手动引入。如下:</p>
<pre data-role="codeBlock" data-info="typeScript" class="language-typescript"><span class="token keyword">import</span> <span class="token string">'leggo/lib/styles/configs.less'</span>
<span class="token keyword">function</span> <span class="token function-variable function">postSchemaModelData</span><span class="token operator">=</span> <span class="token punctuation">(</span>schemaModel<span class="token operator">:</span> TSchemaModel<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'发送schema~~~~~~'</span><span class="token punctuation">,</span> schemaModel<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</pre><blockquote>
<p><strong>重要!</strong></p>
<p>项目地址:<a href="https://github.com/KerryCodes/leggo">https://github.com/KerryCodes/leggo</a></p>
<p>入行快一年了,编乎上没发过回答都攒了20个粉丝了,Github的star仍旧挂0!!!各位大佬能不能动动金手指,让我体验一下star的快感~</p>
</blockquote>
</div>
</body></html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。