mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-09-14 07:59:46 +00:00
197 lines
79 KiB
JavaScript
197 lines
79 KiB
JavaScript
import{H as e,Mt as t,dt as n,lt as r}from"./chunks/framework.BTDV-FQ9.js";var i=JSON.parse(`{"title":"submitForm 函数","description":"","frontmatter":{},"headers":[],"relativePath":"api/form/submit-form.md","filePath":"api/form/submit-form.md"}`),a={name:`api/form/submit-form.md`};function o(e,i,a,o,s,c){return t(),r(`div`,null,[...i[0]||=[n(`<h1 id="submitform-函数" tabindex="-1">submitForm 函数 <a class="header-anchor" href="#submitform-函数" aria-label="Permalink to “submitForm 函数”"></a></h1><p>以命令式方式对一份「表单配置 + 表单值」执行一次校验并取回表单值,类似 <code>ElMessage</code> 的用法。</p><p>走<strong>无渲染</strong>实现:不创建任何 DOM 容器、不实例化任何组件,而是直接遍历 <code>config</code> 树收集带规则的字段,交给 <a href="https://github.com/yiminghe/async-validator" target="_blank" rel="noreferrer"><code>async-validator</code></a>(<code>element-plus</code> 内部用的也是它)执行。因此它可以在 Node / CI 等没有 DOM 的环境中使用,也省去了挂载整棵表单的开销。校验通过则 <code>resolve</code> 表单值,失败则 <code>reject</code> 错误信息。纯 Node 请从 <code>@tmagic/form/headless</code> 引入,避免加载 Vue 组件和样式。</p><p>适用于一些没有合适的容器、但又需要复用 <code>MForm</code> 校验逻辑的场景,例如:</p><ul><li>通过快捷菜单/命令面板触发一次性表单</li><li>在脚本/服务层完成一次表单值校验后再发请求</li><li>把 <code>config</code> 配置当作"可执行的校验规则"使用</li><li>在 Node 脚本 / CI 中批量校验组件配置</li></ul><h2 id="无渲染校验与自定义字段登记" tabindex="-1">无渲染校验与自定义字段登记 <a class="header-anchor" href="#无渲染校验与自定义字段登记" aria-label="Permalink to “无渲染校验与自定义字段登记”"></a></h2><p>无渲染实现按 <code>Container.vue</code> 及各容器组件的模板规则遍历配置树,产出的字段 <code>prop</code> 与规则与「挂载 <code>MForm</code> 后调用 <code>validate()</code>」等价。需要 UI 时传入 <code>dialog: true</code>,会把表单以弹层渲染出来供填写/确认。</p><p>字段只要带了 <code>rules</code>(会包 FormItem),就会校验自身,不必先登记为叶子。配置里有 <code>items</code> 会下钻子项。内部再渲染 <code>MContainer</code> 的复合字段需要 <code>registerField(type, { innerConfig })</code>,把内部会挂到父表单上的配置交出来。innerConfig 回调自身抛错时,会以 <code>FieldInnerConfigError</code>(<code>code: 'FIELD_INNER_CONFIG'</code>)reject。</p><p>innerConfig 回调在校验和表单值初始化两条链路上都会被调用(后者用于走到复合字段内部、找出需要执行 <code>effect</code> 的子字段),所以它应当只做配置派生、可重复调用、不要做重活。在表单值初始化链路上,回调抛错只会记录到 console 并跳过该子树,不会让表单渲染不出来。</p><p>自定义字段的渲染组件和无渲染校验都通过 <code>registerField</code> / <code>registerFields</code> 一次登记。<code>component</code> 会写入字段注册表(<code>getFormField</code>);传入 <code>app</code> 时同时 <code>app.component('m-fields-*')</code>。容器组件用 <code>container</code>,对应 <code>m-form-*</code>。</p><p>字段对表单值的初始化写入统一登记为 <code>effect</code>,渲染与无渲染共用同一份登记表,执行点也只有一个:表单值初始化完成后(<code>MForm</code> 内部、<code>validateValues</code>、以及 tab / table 新增行时)各执行一次 <code>applyMountValueEffects</code>,字段组件自身不要在 <code>setup</code> 里改写 <code>model</code>。因此 effect 有两个约束:一是必须幂等,同一份值可能被执行多次(如 <code>initValues</code> 变化后重新初始化);二是不看 <code>display</code>(<code>display: false</code> 或函数返回假的字段也会被规整,避免字段由隐藏转为显示时漏掉)。<code>type: 'hidden'</code> 不同:遍历在该节点停止、不往下分派,内部字段不会执行 effect。需要按路径跨层级写值时用上下文里的 <code>values</code>(本次处理的值根对象,<code>prop</code> 即以它为根),不要用 <code>mForm.values</code>——对比模式处理的是 <code>lastValues</code> 那一份,新增行处理的则是还没挂到表单上的一行值。单个 effect 抛错只会记录到 console,不影响其余字段与表单渲染。复合字段可以同时登记 <code>effect</code> 与 <code>innerConfig</code>:前者改本字段的值,后者只派生内部配置、不要在回调里改 <code>model</code>。</p><table tabindex="0"><thead><tr><th>字段形态</th><th>登记方式</th></tr></thead><tbody><tr><td>自身带 <code>rules</code>,内部没有嵌套的父表单 FormItem</td><td>无需登记,直接校验</td></tr><tr><td>内部只渲染叶子 UI,或把子表单渲染在独立的 <code>MForm</code> / <code>MFormBox</code> 实例里</td><td><code>registerField('my-field')</code>(配置里有 <code>items</code> 但不属于父表单时,避免被当下钻)</td></tr><tr><td>同时需要渲染组件</td><td><code>registerField('my-field', { component })</code></td></tr><tr><td>容器组件(<code>m-form-*</code>)</td><td><code>registerField('my-box', { container, walk })</code></td></tr><tr><td>叶子字段,但需要改写表单值(类似 <code>display</code> 的 <code>initValue</code>)</td><td><code>registerField('my-field', { effect })</code></td></tr><tr><td>内部再渲染 <code>MContainer</code> / <code>MPanel</code> / <code>MGroupList</code>,向父表单注册字段</td><td><code>registerField('my-field', { innerConfig })</code>(需要改本字段的值时再加 <code>effect</code>)</td></tr><tr><td>自定义 <code>typeMatch</code> 类型校验</td><td><code>registerField('my-field', { typeMatch })</code></td></tr></tbody></table><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { registerField, registerFields } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/form'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MyColorPicker </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> './MyColorPicker.vue'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// 叶子字段:内部没有嵌套的表单项;带 component 时即可渲染</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerFields</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-color-picker'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: { component: MyColorPicker } });</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// 需要挂到当前 app 时传入第二个参数</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerFields</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-color-picker'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: { component: MyColorPicker } }, app);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// 叶子字段,但需要改写表单值:写成 effect,不要在组件 setup 里改 model</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-status'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> effect</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: ({ </span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">config</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">model</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ((config </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">as</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">).initValue </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">&&</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> model) {</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> model[(config </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">as</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">).name] </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (config </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">as</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">).initValue;</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// 复合字段:把组件内部渲染的 MContainer 配置交出来</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-composite'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> innerConfig</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: ({ </span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">config</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">model</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">prop</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ({</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> // 对应组件内部 <MContainer :config="childConfig" :model="model[name]" :prop="prop"></span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> config: childConfig,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> model: model[config.name],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> prop,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// typeMatch:覆盖或扩展该 type 的类型匹配校验,可与 innerConfig / effect 同时登记</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-status'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> typeMatch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: (</span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">value</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { </span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">message</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">typeof</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> value </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'string'</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> undefined</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> :</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> message </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '应为字符串'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">),</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>返回的 <code>config</code> 的 <code>name</code> 会被追加到返回的 <code>prop</code> 上。因此当内部配置复用了字段自身的 <code>name</code>(例如内部渲染 <code><MGroupList :config="{ name, items }" :model="model" :prop="prop"></code>)时,要返回 <code>parentProp</code> 而非 <code>prop</code>,否则 <code>name</code> 会被拼两次:</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-list'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> innerConfig</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: ({ </span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">config</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">parentProp</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> config: { type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'group-list'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, name: config.name, items: innerItems },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> prop: parentProp,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>编辑器侧四个复合字段(<code>code-select</code> / <code>display-conds</code> / <code>event-select</code> / <code>style-setter</code>)的登记可参考 <code>packages/editor/src/fields/headless-validation.ts</code>:innerConfig 与组件共用同一份配置工厂(<code>packages/editor/src/fields/configs/</code>),避免两条链路各写一份而逐渐跑偏。</p><p><code>type: 'component'</code> 会把 <code>config.component</code> 当任意 Vue 组件渲染。无渲染校验把它视为叶子,<strong>不会</strong>遍历内部结构。因此该组件不得再向父表单注册 FormItem;需要嵌套表单项时,应对该具体组件 <code>registerField(type, { innerConfig })</code>。</p><h3 id="重复登记与撤销" tabindex="-1">重复登记与撤销 <a class="header-anchor" href="#重复登记与撤销" aria-label="Permalink to “重复登记与撤销”"></a></h3><p>同一个 type 多次登记按字段浅合并,后一次只覆盖自己传入的 key:</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-composite'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { innerConfig });</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-composite'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { component: MyComposite }); </span><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// innerConfig 仍在</span></span></code></pre></div><p>登记分「内置」与「业务」两层。<code>app.use(MagicForm)</code> / <code>registerBuiltInFields</code> 写内置层,<code>registerField</code> / <code>registerFields</code> 写业务层;读取时业务层优先,<code>unregisterField</code> / <code>clearFields</code> 只清业务层,内置字段不受影响(单测里 <code>clearFields</code> 之后仍能校验 <code>text</code>、<code>tab</code> 等内置 type)。</p><p>因为是合并语义,把一个已登记 <code>innerConfig</code> 的 type 改成普通叶子,不能靠再传一次空对象,要先撤销:</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-composite'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {}); </span><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// ✗ 合并后 innerConfig 还在,仍会下钻</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">unregisterField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-composite'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">); </span><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// ✓ 先清掉业务层登记</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerField</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'my-composite'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { component: MyComposite });</span></span></code></pre></div><p>一次登记里同时传多个形态时的优先级:<code>walk</code> > <code>innerConfig</code> > <code>effect</code>(叶子),命中低优先级的那份会被忽略并在控制台给出告警。</p><h2 id="签名" tabindex="-1">签名 <a class="header-anchor" href="#签名" aria-label="Permalink to “签名”"></a></h2><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> submitForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">options</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SubmitFormOptions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Promise</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>;</span></span></code></pre></div><h2 id="参数" tabindex="-1">参数 <a class="header-anchor" href="#参数" aria-label="Permalink to “参数”"></a></h2><p><code>options</code> 与 <code>MForm</code> 组件的 props 基本对齐,额外提供了 <code>native</code>、<code>returnChangeRecords</code>、<code>dialog</code>、<code>signal</code> 等参数。<code>appContext</code> 仅 <code>dialog: true</code> 时生效。</p><table tabindex="0"><thead><tr><th>名称</th><th>类型</th><th>默认值</th><th>说明</th></tr></thead><tbody><tr><td><code>config</code></td><td><code>FormConfig</code></td><td>—</td><td>必填,表单配置</td></tr><tr><td><code>initValues</code></td><td><code>Record<string, any></code></td><td><code>{}</code></td><td>表单初始值</td></tr><tr><td><code>lastValues</code></td><td><code>Record<string, any></code></td><td><code>{}</code></td><td>需对比的值(开启对比模式时传入)</td></tr><tr><td><code>isCompare</code></td><td><code>boolean</code></td><td><code>false</code></td><td>是否开启对比模式</td></tr><tr><td><code>parentValues</code></td><td><code>Record<string, any></code></td><td><code>{}</code></td><td>父级 values,透传给字段的回调</td></tr><tr><td><code>labelWidth</code></td><td><code>string</code></td><td><code>'200px'</code></td><td>label 宽度</td></tr><tr><td><code>disabled</code></td><td><code>boolean</code></td><td><code>false</code></td><td>是否禁用</td></tr><tr><td><code>height</code></td><td><code>string</code></td><td><code>'auto'</code></td><td>表单高度</td></tr><tr><td><code>stepActive</code></td><td><code>string | number</code></td><td><code>1</code></td><td>步骤表单当前激活步骤</td></tr><tr><td><code>size</code></td><td><code>'small' | 'default' | 'large'</code></td><td>—</td><td>组件尺寸</td></tr><tr><td><code>inline</code></td><td><code>boolean</code></td><td><code>false</code></td><td>是否行内表单</td></tr><tr><td><code>labelPosition</code></td><td><code>string</code></td><td><code>'right'</code></td><td>label 对齐方式</td></tr><tr><td><code>keyProp</code></td><td><code>string</code></td><td><code>'__key'</code></td><td>配置项的唯一 key</td></tr><tr><td><code>popperClass</code></td><td><code>string</code></td><td>—</td><td>弹层 className</td></tr><tr><td><code>preventSubmitDefault</code></td><td><code>boolean</code></td><td>—</td><td>是否阻止表单原生 submit</td></tr><tr><td><code>useFieldTextInError</code></td><td><code>boolean</code></td><td><code>true</code></td><td>校验失败时错误提示前缀是否使用字段的 <code>text</code> 文案;<code>false</code> 时直接使用字段 <code>name</code></td></tr><tr><td><code>context</code></td><td><code>FormContext</code></td><td>—</td><td>宿主业务上下文,与 MForm 的 <code>context</code> 语义一致;配置回调通过 <code>mForm.xxx</code> 读穿取用</td></tr><tr><td><code>native</code></td><td><code>boolean</code></td><td><code>false</code></td><td>透传给 <code>Form.submitForm</code>。<code>true</code> 时返回内部响应式 <code>values</code>,否则返回 <code>cloneDeep(toRaw(values))</code></td></tr><tr><td><code>returnChangeRecords</code></td><td><code>boolean</code></td><td><code>false</code></td><td><code>true</code> 时 resolve 结果为 <code>{ values, changeRecords }</code>,携带表单变更记录;否则仅 resolve <code>values</code></td></tr><tr><td><code>appContext</code></td><td><code>AppContext | null</code></td><td><code>null</code></td><td>父级 Vue 应用上下文。仅 <code>dialog: true</code> 时生效,用于继承全局组件、指令、provide 等,常通过 <code>app._context</code> 或 <code>getCurrentInstance()?.appContext</code> 获取</td></tr><tr><td><code>dialog</code></td><td><code>boolean</code></td><td><code>false</code></td><td><code>true</code> 时把表单以弹层形式渲染出来,点击「确定」才提交,「取消」则以 reject 中断;校验失败会保留弹层并展示错误,便于修正后重试。等待人工操作,可用 <code>signal</code> 中断</td></tr><tr><td><code>title</code></td><td><code>string</code></td><td><code>'submitForm'</code> / <code>'validateForm'</code></td><td>弹层标题,仅 <code>dialog: true</code> 时生效</td></tr><tr><td><code>signal</code></td><td><code>AbortSignal</code></td><td>—</td><td>外部中断信号。abort 时立即以 <code>signal.reason</code> reject,并卸载 <code>dialog</code> 模式下已挂载的临时表单实例</td></tr></tbody></table><h2 id="返回值" tabindex="-1">返回值 <a class="header-anchor" href="#返回值" aria-label="Permalink to “返回值”"></a></h2><ul><li><code>校验通过</code> — <code>Promise<any></code> resolve 当前表单值(<code>native</code> 决定是否克隆);当 <code>returnChangeRecords</code> 为 <code>true</code> 时,resolve <code>{ values, changeRecords }</code></li><li><code>校验失败</code> — <code>Promise<any></code> reject 一个 <code>Error</code>,<code>message</code> 中包含逐条字段错误信息(格式 <code>\${text} -> \${message}</code>,多条用 <code><br></code> 分隔)</li></ul><p><code>dialog: true</code> 时无论成功或失败,函数都会在最后自动 <code>unmount</code> 内部 app 并移除挂载用的 DOM 容器,无需调用方手动清理。</p><div class="tip custom-block"><p class="custom-block-title">关于 changeRecords</p><p><code>changeRecords</code> 记录的是表单挂载后发生的字段变更(由各字段的 <code>change</code> 事件累积而来)。无渲染校验没有用户交互,因此固定返回空数组;只有 <code>dialog: true</code> 时才可能有内容(<code>MForm</code> 内部的 <code>submitForm</code> 在校验通过后会清空变更记录,因此本函数会在调用前先做快照)。</p></div><h2 id="基础用法" tabindex="-1">基础用法 <a class="header-anchor" href="#基础用法" aria-label="Permalink to “基础用法”"></a></h2><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { submitForm } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/form'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> values</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> submitForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> config: [</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'text'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> name: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'username'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> text: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'用户名'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> rules: [</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { required: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, message: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'请输入用户名'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { typeMatch: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, message: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'用户名类型不合法'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> initValues: { username: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">''</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'提交成功'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, values);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">} </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">catch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (e) {</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'校验失败'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, e);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h2 id="同时获取变更记录-changerecords" tabindex="-1">同时获取变更记录(changeRecords) <a class="header-anchor" href="#同时获取变更记录-changerecords" aria-label="Permalink to “同时获取变更记录(changeRecords)”"></a></h2><p>设置 <code>returnChangeRecords: true</code> 后,resolve 的结果会从单纯的 <code>values</code> 变为 <code>{ values, changeRecords }</code>:</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { submitForm } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/form'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">values</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">changeRecords</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> submitForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> config: [{ type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'text'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, name: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'username'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, text: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'用户名'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> initValues: { username: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'foo'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> returnChangeRecords: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(values); </span><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// { username: 'foo' }</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(changeRecords); </span><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// ChangeRecord[]</span></span></code></pre></div><h2 id="弹层模式-dialog-true-下继承父级应用上下文" tabindex="-1">弹层模式(<code>dialog: true</code>)下继承父级应用上下文 <a class="header-anchor" href="#弹层模式-dialog-true-下继承父级应用上下文" aria-label="Permalink to “弹层模式(dialog: true)下继承父级应用上下文”"></a></h2><p>默认路径不挂载组件,不需要 <code>appContext</code>。只有 <code>dialog: true</code> 会渲染弹层,此时 <code>MForm</code> 要用到 <code>@tmagic/design</code> 的组件(背后可能是 <code>element-plus</code> 或 <code>tdesign</code>),需要把宿主应用的上下文带过去:</p><div class="language-vue"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">vue</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#11782a;--shiki-dark:#85E89D;">script</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setup</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> lang</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"ts"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">></span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { getCurrentInstance } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'vue'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { submitForm } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/form'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">appContext</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getCurrentInstance</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onClick</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> values</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> submitForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> config: [{ type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'text'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, name: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'text'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, text: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'文本'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> initValues: { text: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'hello'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> dialog: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> title: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'编辑配置'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> appContext,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(values);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">};</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"></</span><span style="--shiki-light:#11782a;--shiki-dark:#85E89D;">script</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">></span></span></code></pre></div><p>也可以在初始化 app 时把上下文缓存下来,再在任意位置复用:</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { createApp } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'vue'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ElementPlus </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'element-plus'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MagicForm, { </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">type</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SubmitFormOptions, submitForm </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">as</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> rawSubmitForm } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/form'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> App </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> './App.vue'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> app</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> createApp</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(App);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">app.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">use</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(ElementPlus);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">app.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">use</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(MagicForm);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">app.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">mount</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'#app'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> submitForm</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">options</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Omit</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">SubmitFormOptions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'appContext'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>) </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">=></span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> rawSubmitForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">options, appContext: app._context });</span></span></code></pre></div><h2 id="处理校验错误" tabindex="-1">处理校验错误 <a class="header-anchor" href="#处理校验错误" aria-label="Permalink to “处理校验错误”"></a></h2><p>校验失败时 reject 的 <code>Error.message</code> 已经把出错字段拼好,可以直接展示到用户:</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { tMagicMessage } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/design'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> values</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> submitForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ config, initValues });</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> save</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(values);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">} </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">catch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">e</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> tMagicMessage.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> dangerouslyUseHTMLString: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> message: e.message,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h2 id="validateform-函数" tabindex="-1">validateForm 函数 <a class="header-anchor" href="#validateform-函数" aria-label="Permalink to “validateForm 函数”"></a></h2><p><code>validateForm</code> 与 <code>submitForm</code> 共用同一套无渲染校验实现,区别在于它是<strong>静默</strong>的:校验失败不抛异常、不返回表单值,而是以返回值形式给出错误文案。适合「只想探测这份配置是否合法」的场景,例如源码编辑器保存后校验、批量校验组件配置。</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> validateForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">options</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ValidateFormOptions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Promise</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>;</span></span></code></pre></div><p><code>options</code> 取 <code>SubmitFormOptions</code> 中与校验相关的子集(<code>config</code>、<code>initValues</code>、<code>parentValues</code>、<code>labelWidth</code>、<code>keyProp</code>、<code>useFieldTextInError</code>、<code>extendState</code>、<code>typeMatchValid</code>、<code>appContext</code>、<code>dialog</code>、<code>title</code>、<code>signal</code>)。</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { validateForm } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/form'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> error</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> validateForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> config: [{ type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'text'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, name: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'username'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, text: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'用户名'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, rules: [{ required: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, message: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'请输入用户名'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }] }],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> initValues: { username: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">''</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (error) {</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> // '用户名 -> 请输入用户名'</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>校验通过返回空字符串 <code>''</code>,否则返回以 <code><br></code> 拼接的错误文案。无法完成校验时才会 reject(例如 innerConfig 回调失败抛出 <code>FieldInnerConfigError</code>)。</p><h2 id="运行环境" tabindex="-1">运行环境 <a class="header-anchor" href="#运行环境" aria-label="Permalink to “运行环境”"></a></h2><p>无渲染实现不接触 <code>document</code> / <code>window</code>,因此在任何 JS 运行时中都可用:</p><table tabindex="0"><thead><tr><th>环境</th><th>是否可用</th><th>说明</th></tr></thead><tbody><tr><td>浏览器 / Electron 渲染进程 / 浏览器扩展</td><td>✅</td><td>直接可用</td></tr><tr><td>Vitest / Jest + <code>happy-dom</code> / <code>jsdom</code></td><td>✅</td><td>项目自身的单测就跑在这种环境下</td></tr><tr><td>纯 Node.js / Bun / Deno(无 DOM polyfill)</td><td>✅</td><td>从 <code>@tmagic/form/headless</code> 引入,不要用 <code>@tmagic/form</code> 主入口</td></tr></tbody></table><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// scripts/check-form.ts —— 纯 Node 环境,无需任何 DOM polyfill</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { builtInFields, registerBuiltInFields, registerFields, validateForm } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/form/headless'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { editorFields } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@tmagic/editor/headless'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// \`builtInFields\` 只是数据;未 \`app.use(MagicForm)\` 时要自己登记</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerBuiltInFields</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(builtInFields);</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerFields</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(editorFields);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> error</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> validateForm</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> config: [{ type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'text'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, name: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'username'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, text: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'用户名'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, rules: [{ required: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }] }],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> initValues: { username: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">''</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (error) {</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(error);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> process.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">exit</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><div class="warning custom-block"><p class="custom-block-title">注意</p><p><code>dialog: true</code> 依赖 DOM 与已安装的 UI 库(<code>element-plus</code> / <code>tdesign</code>),在纯 Node 环境中不可用。</p></div><div class="warning custom-block"><p class="custom-block-title">ESM 与 CJS 不要混用</p><p><code>@tmagic/form/headless</code> 的 ESM 产物与 <code>@tmagic/form</code> 共用同一批模块文件,字段注册表是同一份,两个入口可以混着 <code>import</code>。</p><p>CJS 产物是两个各自独立的 bundle,注册表不共享。所以同一进程里不要同时 <code>require('@tmagic/form')</code> 和 <code>require('@tmagic/form/headless')</code>——在一边 <code>registerField</code> 另一边读不到,校验会因为「没登记过这个 type」而静默放过。<code>@tmagic/editor</code> 与 <code>@tmagic/design</code> 的 headless 子路径同理。</p></div><h2 id="类型定义" tabindex="-1">类型定义 <a class="header-anchor" href="#类型定义" aria-label="Permalink to “类型定义”"></a></h2><details class="details custom-block"><summary>查看 <code>SubmitFormOptions</code> 类型定义</summary><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">/**</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * submitForm 函数参数(与 Form.vue 组件 props 对齐)</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SubmitFormOptions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 表单配置 */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> config</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> FormConfig</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 表单初始值 */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> initValues</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Record</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 需对比的值(开启对比模式时传入) */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> lastValues</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Record</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 是否开启对比模式 */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> isCompare</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> parentValues</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Record</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> labelWidth</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> disabled</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> height</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> stepActive</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> number</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> size</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'small'</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'default'</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'large'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> inline</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> labelPosition</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'top'</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'left'</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'right'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> keyProp</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> popperClass</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> preventSubmitDefault</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /**</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 表单校验失败时,错误提示前缀是否使用字段的 text 文案(通过 \`getTextByName\` 从 config 中查找)。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 默认 \`true\`,置为 \`false\` 时直接使用字段 name。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> useFieldTextInError</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 宿主业务上下文,与 MForm 的同名 prop 语义一致 */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> context</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> FormContext</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 透传给 Form.submitForm 的参数:是否直接返回原始响应式 values */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> native</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /**</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 是否在 resolve 结果中携带 changeRecords(变更记录)。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 开启后 resolve 的结果为 \`{ values, changeRecords }\`,否则仅 resolve values。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> returnChangeRecords</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /**</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 父级应用上下文,用于继承全局组件、指令、provide 等。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 仅 \`dialog: true\` 时生效。\`@tmagic/form/headless\` 不支持弹层。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> appContext</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> AppContext</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /**</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 是否以弹层展示表单。默认 \`false\`。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> *</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * \`@tmagic/form/headless\` 不支持 \`dialog: true\`,请从 \`@tmagic/form\` 引入。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> dialog</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /**</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 弹层标题,仅 \`dialog: true\` 时生效。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> title</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> typeMatchValid</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /**</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 外部中断信号。abort 时会立即以 \`signal.reason\` reject。</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> signal</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> AbortSignal</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div></details><details class="details custom-block"><summary>查看 <code>SubmitFormResult</code> 类型定义</summary><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">/**</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> * 开启 \`returnChangeRecords\` 时 submitForm 的返回结果</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SubmitFormResult</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 校验通过后的表单值 */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> values</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 表单变更记录 */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> changeRecords</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ChangeRecord</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[];</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div></details>`,61)]])}var s=e(a,[[`render`,o]]);export{i as __pageData,s as default}; |