Files
wukuang/docs/widget-steps/03-helper-config.html
T

318 lines
14 KiB
HTML
Raw Normal View History

2026-05-23 14:05:22 +08:00
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>步骤详解 - 创建 Helper 配置文件</title>
<style>
:root {
--bg-primary: #0a0e1a;
--bg-secondary: #111827;
--bg-card: #1a2035;
--bg-card-hover: #1f2a45;
--border-color: #2d3a5c;
--text-primary: #e2e8f0;
--text-secondary: #94a3b8;
--text-muted: #64748b;
--accent-green: #10b981;
--accent-green-light: #34d399;
--accent-cyan: #06b6d4;
--accent-purple: #8b5cf6;
--accent-orange: #f59e0b;
--shadow-lg: 0 10px 40px rgba(0, 0, 0, 0.4);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.7;
padding: 2rem;
}
.container { max-width: 1000px; margin: 0 auto; }
.back-link {
display: inline-flex; align-items: center; gap: 0.5rem;
color: var(--accent-green-light); text-decoration: none;
margin-bottom: 2rem; padding: 0.5rem 1rem;
background: var(--bg-card); border-radius: 8px;
border: 1px solid var(--border-color); transition: all 0.2s ease;
}
.back-link:hover { background: var(--bg-card-hover); transform: translateX(-4px); }
.header {
background: var(--bg-card); border-radius: 16px; padding: 2rem;
margin-bottom: 2rem; border: 1px solid var(--border-color);
box-shadow: var(--shadow-lg); border-left: 4px solid var(--accent-green);
}
.step-badge {
display: inline-block; background: linear-gradient(135deg, #10b981 0%, #059669 100%);
color: white; padding: 0.3rem 1rem; border-radius: 20px;
font-size: 0.85rem; font-weight: 600; margin-bottom: 1rem;
}
.header h1 { font-size: 2rem; margin-bottom: 0.5rem; }
.header .desc { color: var(--text-secondary); font-size: 1rem; }
.section {
background: var(--bg-card); border-radius: 12px; padding: 1.5rem;
margin-bottom: 1.5rem; border: 1px solid var(--border-color);
}
.section h2 {
font-size: 1.3rem; margin-bottom: 1rem; color: var(--accent-green-light);
display: flex; align-items: center; gap: 0.5rem;
}
.section p { color: var(--text-secondary); margin-bottom: 1rem; }
.code-block {
background: var(--bg-secondary); padding: 1.25rem; border-radius: 8px;
font-family: 'Fira Code', 'Cascadia Code', monospace; font-size: 0.85rem;
color: var(--accent-cyan); overflow-x: auto; line-height: 1.6; margin-bottom: 1rem;
}
.code-block .comment { color: var(--text-muted); }
.code-block .keyword { color: var(--accent-purple); }
.code-block .string { color: var(--accent-green); }
.method-table { width: 100%; border-collapse: separate; border-spacing: 0; margin-top: 1rem; }
.method-table th {
background: var(--bg-secondary); padding: 0.75rem 1rem; text-align: left;
font-size: 0.85rem; color: var(--accent-orange); border-bottom: 1px solid var(--border-color);
}
.method-table td {
padding: 0.75rem 1rem; border-bottom: 1px solid var(--border-color);
font-size: 0.85rem; color: var(--text-secondary);
}
.method-table code {
background: rgba(6, 182, 212, 0.1); color: var(--accent-cyan);
padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.8rem;
}
.info-grid {
display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem; margin-top: 1rem;
}
.info-card {
background: var(--bg-secondary); padding: 1rem; border-radius: 8px;
border: 1px solid var(--border-color);
}
.info-card h4 { font-size: 0.9rem; margin-bottom: 0.5rem; color: var(--accent-green-light); }
.info-card p { font-size: 0.85rem; color: var(--text-secondary); margin: 0; }
.file-path {
font-family: 'Fira Code', monospace; font-size: 0.8rem;
color: var(--accent-cyan); background: rgba(6, 182, 212, 0.1);
padding: 0.25rem 0.5rem; border-radius: 4px;
}
ul { list-style: none; padding: 0; }
ul li { padding: 0.4rem 0; color: var(--text-secondary); display: flex; align-items: flex-start; gap: 0.5rem; }
ul li::before { content: "▸"; color: var(--accent-green); flex-shrink: 0; }
</style>
</head>
<body>
<div class="container">
<a href="../../物料组件添加流程.html" class="back-link">← 返回主文档</a>
<div class="header">
<div class="step-badge">步骤 3</div>
<h1>创建 Helper 配置文件</h1>
<p class="desc">定义物料组件的配置中心:物料面板、属性面板、拖拽行为等</p>
</div>
<div class="section">
<h2>📋 功能描述</h2>
<p>Helper 是物料组件的<strong>配置中枢</strong>,定义了组件在物料面板的显示信息、右侧属性面板的表单 schema、拖入画布时的默认数据、拖拽行为规则等。它是连接设计器 UI 和组件实例的桥梁。</p>
</div>
<div class="section">
<h2>🧩 模块描述</h2>
<p>Helper 对象被 <code>RegisterWidgetHelper.ts</code> 导入并注册到系统,主要提供以下能力:</p>
<ul>
<li><strong>物料面板配置</strong> - 控制组件在左侧面板的图标、名称、分类</li>
<li><strong>属性面板 Schema</strong> - 定义右侧属性面板的表单控件(输入框、选择器等)</li>
<li><strong>默认 Widget 数据</strong> - 拖入画布时生成的初始 schema</li>
<li><strong>拖拽行为</strong> - 控制组件拖入时的栅格占位</li>
<li><strong>选择框配置</strong> - 控制组件是否可选中、复制、删除、隐藏</li>
<li><strong>国际化路径</strong> - 指定需要国际化的属性路径</li>
</ul>
</div>
<div class="section">
<h2>📁 文件信息</h2>
<div class="info-grid">
<div class="info-card">
<h4>文件路径</h4>
<p><span class="file-path">packages/form-designer/src/config/widget-helper/&lt;组件名&gt;Helper.ts</span></p>
</div>
<div class="info-card">
<h4>操作类型</h4>
<p><strong style="color: #34d399;">新建</strong> - 创建 Helper 配置对象</p>
</div>
<div class="info-card">
<h4>导出方式</h4>
<p>默认导出 (export default) Helper 对象</p>
</div>
<div class="info-card">
<h4>所属层级</h4>
<p>页面设计器层 (packages/form-designer)</p>
</div>
</div>
</div>
<div class="section">
<h2>📊 Helper 接口方法</h2>
<table class="method-table">
<thead>
<tr>
<th>方法名</th>
<th>返回值</th>
<th>作用说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>type</code></td>
<td>WidgetType</td>
<td>组件唯一类型标识,与 WidgetType 枚举值对应</td>
</tr>
<tr>
<td><code>buildMaterialConfig()</code></td>
<td>MaterialConfig</td>
<td>物料面板显示配置:图标、名称、分类</td>
</tr>
<tr>
<td><code>buildSettings(params)</code></td>
<td>WidgetSettingsConfig[]</td>
<td>右侧属性面板的表单 schema(属性/样式/事件 tab</td>
</tr>
<tr>
<td><code>buildWidget(params)</code></td>
<td>WidgetSchema</td>
<td>拖入画布时生成的默认 schema(默认值、初始 props</td>
</tr>
<tr>
<td><code>dragInfo()</code></td>
<td>{ col: number }</td>
<td>拖拽时的栅格跨度(1-24</td>
</tr>
<tr>
<td><code>hasSelectBox()</code></td>
<td>SelectBoxConfig</td>
<td>是否可选中、可否复制/删除/隐藏等</td>
</tr>
<tr>
<td><code>collectLanguagePath()</code></td>
<td>{ paths: string[][] }</td>
<td>需要国际化的属性路径</td>
</tr>
</tbody>
</table>
</div>
<div class="section">
<h2>💻 完整代码示例</h2>
<div class="code-block">
<span class="comment">// packages/form-designer/src/config/widget-helper/MyNewComponentHelper.ts</span>
import { WidgetType } from '~@/types/WidgetType'
<span class="keyword">export default</span> {
<span class="comment">// 1. 组件类型标识</span>
type: WidgetType.MyNewComponent,
<span class="comment">// 2. 物料面板配置</span>
buildMaterialConfig() {
<span class="keyword">return</span> {
icon: <span class="string">'icon-text'</span>, <span class="comment">// 图标类名</span>
name: <span class="string">'MyNewComponent'</span>, <span class="comment">// 组件类型名</span>
title: <span class="string">'新组件'</span>, <span class="comment">// 显示名称(在物料面板中显示)</span>
category: <span class="string">'common'</span>, <span class="comment">// 分类:common/container/navigation 等</span>
}
},
<span class="comment">// 3. 右侧属性面板配置</span>
buildSettings(params) {
<span class="keyword">return</span> [
{
key: <span class="string">'property'</span>,
label: <span class="string">'属性设置'</span>,
type: <span class="string">'tab'</span>,
children: [
{
key: <span class="string">'content'</span>,
label: <span class="string">'文本内容'</span>,
type: <span class="string">'input'</span>, <span class="comment">// form-create 内置控件类型</span>
placeholder: <span class="string">'请输入内容'</span>,
},
{
key: <span class="string">'fontSize'</span>,
label: <span class="string">'字体大小'</span>,
type: <span class="string">'inputNumber'</span>,
min: 12,
max: 72,
},
{
key: <span class="string">'color'</span>,
label: <span class="string">'字体颜色'</span>,
type: <span class="string">'colorPicker'</span>,
},
],
},
]
},
<span class="comment">// 4. 拖入画布时生成的默认数据</span>
buildWidget(params) {
<span class="keyword">return</span> {
type: <span class="keyword">this</span>.type,
props: {
content: <span class="string">'默认文本'</span>,
fontSize: <span class="string">'14px'</span>,
color: <span class="string">'#333333'</span>,
},
}
},
<span class="comment">// 5. 拖拽行为配置</span>
dragInfo() {
<span class="keyword">return</span> {
col: 12, <span class="comment">// 占 12/24 栅格</span>
}
},
<span class="comment">// 6. 选择框配置</span>
hasSelectBox() {
<span class="keyword">return</span> {
selectable: <span class="keyword">true</span>, <span class="comment">// 是否可选中</span>
deletable: <span class="keyword">true</span>, <span class="comment">// 是否可删除</span>
copyable: <span class="keyword">true</span>, <span class="comment">// 是否可复制</span>
hideable: <span class="keyword">false</span>, <span class="comment">// 是否可隐藏</span>
}
},
<span class="comment">// 7. 国际化路径</span>
collectLanguagePath() {
<span class="keyword">return</span> {
paths: [
[<span class="string">'widget'</span>, <span class="string">'MyNewComponent'</span>, <span class="string">'content'</span>],
],
}
},
}
</div>
</div>
<div class="section">
<h2>⚠️ 注意事项</h2>
<ul>
<li><code>type</code> 必须与 WidgetType 枚举值完全一致</li>
<li><code>buildSettings</code> 中的 type 使用 form-create 内置控件类型</li>
<li><code>buildWidget</code> 返回的 props 结构需与 Vue 组件的 props 定义匹配</li>
<li>复杂组件可实现 <code>transformSchemaProperties</code><code>buildSchemaController</code> 方法</li>
</ul>
</div>
<div class="section" style="border-left: 4px solid var(--accent-green);">
<h2>➡️ 下一步</h2>
<p>完成 Helper 配置后,继续执行:</p>
<ul>
<li><strong>步骤 4</strong>:在 RegisterWidget.ts 中注册组件实例</li>
<li><strong>步骤 5</strong>:在 RegisterWidgetHelper.ts 中注册 Helper</li>
<li><strong>步骤 6</strong>:在 Material.ts 中注册物料面板分组</li>
</ul>
</div>
</div>
</body>
</html>