mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-07-27 08:27:44 +00:00
41 lines
22 KiB
JavaScript
41 lines
22 KiB
JavaScript
import{At as e,E as t,Ot as n,Xt as r}from"./chunks/framework.ECw2lWOt.js";var i=JSON.parse(`{"title":"属性配置表单校验联动","description":"","frontmatter":{},"headers":[],"relativePath":"guide/advanced/prop-form-validate.md","filePath":"guide/advanced/prop-form-validate.md"}`),a={name:`guide/advanced/prop-form-validate.md`};function o(t,i,a,o,s,c){return r(),n(`div`,null,[...i[0]||=[e(`<h1 id="属性配置表单校验联动" tabindex="-1">属性配置表单校验联动 <a class="header-anchor" href="#属性配置表单校验联动" aria-label="Permalink to “属性配置表单校验联动”"></a></h1><p>编辑器在属性面板(属性表单 / 样式表单)中已支持 <a href="./../../form-config/rules.html">表单校验</a>。默认情况下,表单校验失败时本次改动会被丢弃,不会写入节点。</p><p>「属性配置表单校验联动」能力(<code>enablePropsFormValidate</code>)允许在<strong>校验失败时仍按当前表单值更新节点</strong>,并把错误信息集中记录到 <code>editorService</code>,从而实现:</p><ul><li>组件树(图层)中对出错节点<strong>标红并显示错误图标</strong>,悬停可查看错误文案;</li><li>业务在<strong>保存前拦截</strong>存在校验错误的组件(见 <a href="#保存拦截">保存拦截</a>);</li><li>校验错误随 DSL 操作写入历史快照,<strong>撤销 / 重做能正确还原</strong>错误状态。</li></ul><blockquote><p>该能力默认关闭,需通过 <code><m-editor :enable-props-form-validate="true"></code> 显式开启。</p></blockquote><h2 id="工作原理" tabindex="-1">工作原理 <a class="header-anchor" href="#工作原理" aria-label="Permalink to “工作原理”"></a></h2><h3 id="错误来源维度" tabindex="-1">错误来源维度 <a class="header-anchor" href="#错误来源维度" aria-label="Permalink to “错误来源维度”"></a></h3><p>属性面板分「属性」与「样式」两个独立的 <code>FormPanel</code>,它们指向同一节点。为避免某个面板校验通过时误清另一个面板记录的错误,错误信息<strong>以来源(<code>source</code>)为键分别保存</strong>:</p><ul><li><code>'props'</code>:属性表单校验错误</li><li><code>'style'</code>:样式表单校验错误</li></ul><p>节点只要<strong>任一来源存在非空错误文案</strong>即视为出错。</p><p>内部类型定义见 <code>NodeInvalidInfo</code>:</p><div class="language-ts"><button title="Copy Code" 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;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> NodeInvalidInfo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99;"> /** 属性表单校验错误文案(可能为包含 <br> 的 HTML) */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> props</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:#62687b;--shiki-dark:#818e99;"> /** 样式表单校验错误文案(可能为包含 <br> 的 HTML) */</span></span>
|
||
<span class="line"><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;"> style</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:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h3 id="数据流" tabindex="-1">数据流 <a class="header-anchor" href="#数据流" aria-label="Permalink to “数据流”"></a></h3><ol><li>表单校验失败时(开启了 <code>enablePropsFormValidate</code>),<code>FormPanel</code> 仍以当前表单值提交,并把错误随提交事件一并抛出;</li><li><code>PropsPanel</code> 在调用 <code>editorService.update()</code> 时,把 <code>invalidInfo: { id, source, error }</code> 一并传入;</li><li><code>editorService</code> 在<strong>写入历史记录之前</strong>落库错误标记(<code>applyInvalidInfo</code>),使历史快照与本次变更对齐;</li><li>错误被记录到 <code>invalidNodeIds</code> 状态,并触发 <code>invalid-node-change</code> 事件;</li><li>组件树节点通过读取 <code>invalidNodeIds</code> 响应式地展示标红与错误图标。</li></ol><p>校验成功时(或源码编辑器保存时)不携带 <code>invalidInfo</code>,保持已有错误状态不变(即不会清除错误)——只有对应来源的表单再次校验通过才会清除该来源的错误。</p><h2 id="快速开始" tabindex="-1">快速开始 <a class="header-anchor" href="#快速开始" aria-label="Permalink to “快速开始”"></a></h2><div class="language-html"><button title="Copy Code" class="copy"></button><span class="lang">html</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;">template</span><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;">m-editor</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> :enable-props-form-validate</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"true"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">></</span><span style="--shiki-light:#11782a;--shiki-dark:#85E89D;">m-editor</span><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;">template</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">></span></span></code></pre></div><p>开启后无需其它配置,属性 / 样式表单校验失败即会自动记录错误并标红组件树节点。</p><h2 id="读取与清除错误" tabindex="-1">读取与清除错误 <a class="header-anchor" href="#读取与清除错误" aria-label="Permalink to “读取与清除错误”"></a></h2><p>业务侧可通过 <code>editorService</code> 读取或清除错误标记:</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</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;"> { editorService } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@tmagic/editor"</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;">// 读取全部错误节点(Map<Id, NodeInvalidInfo>)</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> invalidNodeIds</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> editorService.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getInvalidNodeIds</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;">// 读取单个节点的错误</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> info</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> editorService.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getInvalidNodeInfo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"text_123"</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;">// 手动记录 / 清除错误(一般无需手动调用,属性面板已自动维护)</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">editorService.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setInvalidNode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"text_123"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"props"</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;">);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">editorService.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">deleteInvalidNode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"text_123"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"props"</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:#24292E;--shiki-dark:#E1E4E8;">editorService.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">resetInvalidNodeId</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(); </span><span style="--shiki-light:#62687b;--shiki-dark:#818e99;">// 清空全部错误</span></span></code></pre></div><p>订阅错误状态变化(非响应式消费方,如自定义工具栏):</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</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;">editorService.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">on</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"invalid-node-change"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, (</span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">invalidNodeIds</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;"> 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;">, invalidNodeIds.size);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><blockquote><p>响应式读取(如自定义组件树节点内容)请直接读取 <code>editorService.get('invalidNodeIds')</code>,其变化会触发 Vue 响应式更新。</p></blockquote><h2 id="保存拦截" tabindex="-1">保存拦截 <a class="header-anchor" href="#保存拦截" aria-label="Permalink to “保存拦截”"></a></h2><p>开启校验联动后,业务可读取 <code>invalidNodeIds</code>,在存在校验错误时阻止保存并提示:</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</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;"> { editorService } </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@tmagic/editor"</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;"> { 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;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> checkInvalidNodes</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;">services</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;"> invalidNodeIds</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> services?.editorService.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getInvalidNodeIds</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;"> (</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">invalidNodeIds </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> invalidNodeIds.size </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> return</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:#c62739;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> names</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;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">invalidNodeIds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">keys</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()].</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#c13617;--shiki-dark:#FFAB70;">id</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;"> node</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> services?.editorService.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getNodeById</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(id);</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> node?.name </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;">node</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">name</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}(\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">id</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">})\`</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;">id</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:#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 style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`以下组件存在配置校验错误,请修复后再保存:\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">names</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">join</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"、"</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">)</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:#c62739;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> false</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:#62687b;--shiki-dark:#818e99;">// 在菜单保存按钮 / 预览保存的 handler 中:</span></span>
|
||
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">if</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;">checkInvalidNodes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(services)) </span><span style="--shiki-light:#c62739;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">save</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">();</span></span></code></pre></div><p>playground 已内置该拦截逻辑,参见 <code>playground/src/pages/composables/use-editor-menu.ts</code>。</p><h2 id="与历史记录的关系" tabindex="-1">与历史记录的关系 <a class="header-anchor" href="#与历史记录的关系" aria-label="Permalink to “与历史记录的关系”"></a></h2><p>错误标记会随 DSL 操作(<code>add</code> / <code>update</code> 等)一并写入历史快照。编辑器内部在「操作前」与「操作后」分别留存错误状态快照:</p><ul><li><strong>撤销(undo)</strong>:还原到操作前的错误状态(撤销一个「校验失败」的改动后错误消失);</li><li><strong>重做(redo)</strong>:还原到操作后的错误状态(重做后错误恢复)。</li></ul><p>整体替换 <code>root</code>(如加载新 DSL)后会自动清理不存在于新 DSL 中的失效节点错误记录,避免残留误报;删除节点时也会同步清理其子树相关的错误记录。</p>`,32)]])}var s=t(a,[[`render`,o]]);export{i as __pageData,s as default}; |