ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vue3低代码平台自定义物料组件:从注册协议到AI生成全解析

Vue3低代码平台自定义物料组件:从注册协议到AI生成全解析 如果你做过一年以上的低代码平台大概率会碰到同一个坎内置物料不够用。Vue3 搭建平台上表单、表格、图片这些通用组件能覆盖 60% 的需求剩下 40% 全是业务特有形态——审批卡片、进度待办、数据看板、甚至某个项目独家的复杂交互。这个系列写到第十一篇我不打算再泛泛聊物料系统的架构而是把“自定义物料组件”这条链路完整拉出来从物料目录结构、注册协议、Schema 驱动属性面板到 AI 如何辅助生成新物料再到发布和版本治理。目标很简单让一个普通前端能在不改平台主工程的前提下把自研组件变成平台里可拖拽、可配置、可被 AI 识别的一个标准物料。1. 物料系统到底在解什么题从拖拽搭建到自定义物料的边界1.1 物料在搭建平台里的角色很多第一次接触低代码的朋友会把“物料”和“组件”划等号这个理解不准确。普通组件只是渲染层的存在平台拿到组件实例后只能按写死的 props 使用它而物料是“带说明书、带配置面板、带预览态”的一整套可维护单元。你可以把它想象成乐高积木组件是那块塑料物料是积木外包装上印着拼法、适用年龄、兼容系列的那份说明。没有说明搭建者不知道这块积木能拼在哪也不知道有哪些颜色可选。在 Vue3 平台里物料系统承担三件事第一把组件能力通过协议暴露给搭建画布第二把属性配置翻译成表单让非研发人员也能编辑第三把页面 JSON 中的描述还原成真实组件实例。这三件事环环相扣任何一环断裂物料就只是一个“能 import 的.vue 文件”而不是真正的低代码能力。1.2 内置物料与自定义物料的边界内置物料通常由平台团队维护覆盖高频通用场景比如按钮、输入框、下拉选择、日期选择、表格、卡片容器。它们的特点是生命周期跟着平台主版本走升级时平台统一控制接口稳定性要求很高不能随便改动。自定义物料则不同它由业务团队或第三方开发者提供解决的问题是“内置物料表达不了的那部分业务”。两者之间的边界就是平台协议和内部实现的分界线。平台只需要约定物料必须符合注册协议、必须导出一个可渲染的 Vue3 组件、必须提供 schema 描述。至于组件内部是用 Element Plus、Vant、还是纯手写 CSS平台完全不关心。这样平台核心包体积不会随业务物料增多而膨胀业务团队也能按自己的节奏迭代物料版本。这个边界如果在项目初期没画清楚后面八成会出现“为某个业务在平台主工程里硬塞一个组件”的脏代码。1.3 AI 驱动平台对物料提出了新要求当平台引入 AI 之后物料不能只是“机器可渲染”的东西还得是“机器可理解”的东西。AI 要能从一段自然语言描述里判断该用哪个物料或者自动生成一页由多个物料组合的搭建 JSON就必须知道每个物料支持哪些属性、哪些事件、哪些数据源。这意味着自定义物料必须极度结构化组件代码是给人看的物料 schema 是给平台和 AI 看的。我在实际项目中把物料协议拆成了“元信息 属性描述 能力声明”三层。元信息解决物料是谁、在哪一类目下属性描述解决怎么样被配置能力声明解决 AI 能不能正确使用它比如是否支持数据绑定、是否支持事件派发、是否适合移动端。有了这三层AI 在生成页面时就不会逮着一个物料乱填参数物料中心也才能支持“AI 建物料”这类高级功能。2. 先定规矩自定义物料的目录结构与注册协议2.1 一个物料最少需要哪几个文件要做一个自定义物料第一步不是写组件而是定目录结构。我建议平台侧把规则固定下来后续所有物料都按同一套模板生成省去大量沟通成本。一套最简的物料目录通常长这样src/materials/todo-card/ ├── index.ts # 物料注册入口 ├── component.vue # 运行时渲染组件 ├── schema.ts # 属性、事件、插槽描述 ├── preview.vue # 物料市场/面板里的预览缩略图 └── settings.vue # 属性配置面板可选component.vue 是真正跑在画布和最终页面里的组件preview.vue 负责在物料面板中展示静态效果不需要拉真实接口schema.ts 是平台用来生成配置表单的元数据settings.vue 是复杂物料的自定义配置面板如果 schema 覆盖不了就用它兜底。index.ts 负责把所有文件组装成一个完整的物料对象。2.2 manifest 到底要暴露什么信息index.ts 里导出的物料对象我习惯叫它 manifest。一个可供平台和 AI 使用的 manifest 至少要包含下面这些字段import type { MaterialManifest } from platform/material-types import TodoCardSchema from ./schema const manifest: MaterialManifest { type: material.todo-card, name: 待办卡片, category: business, version: 1.0.0, component: () import(./component.vue), preview: () import(./preview.vue), settings: () import(./settings.vue), schema: TodoCardSchema, capabilities: [data-binding, event-emit], keywords: [todo, 待办, 任务, 进度] } export default manifesttype 是全局唯一标识页面 JSON 里存的就是它name 和 keywords 是给搭建用户和 AI 检索用的很多人会忽略 keywords但 AI 匹配物料时它反而比 name 更关键component 用箭头函数动态 import避免物料市场一打开就把所有组件代码加载完capabilities 用来声明物料能不能被数据绑定、能不能对外派发事件。这套信息越完整平台和 AI 就越不会用错物料。2.3 运行时组件、预览组件、配置组件三件套一开始接触物料系统的人常问为什么不能直接拿 component.vue 当预览图原因很简单真实组件需要数据、需要接口、可能还会发请求放在物料列表里会把面板拖垮如果组件内部有定时器还会造成严重的内存泄漏。预览组件应该是一个零请求、零副作用的纯静态表现甚至可以只是一个带样式的 div只要用户能看出这个物料的最终形态就行。配置组件则负责在右侧属性面板中编辑当前选中物料。大部分时候我们可以用 schema 自动生成配置表单不需要单独写 settings.vue但遇到特殊交互——比如“要配置一个包含子选项的联动规则”时schema 表达不了就必须让开发者写一个自定义配置面板。三件套各管一摊运行时负责真实渲染预览负责静态展示配置负责修改属性彼此不混用。这个设计还有一个额外好处AI 生成新物料时可以先用自动生成的 schema 和默认 preview 跑通链路再迭代真实组件。3. Schema 驱动属性面板让非研发也能改组件3.1 属性 Schema 设计的基本原则如果你只把 schema 当成“记录组件有哪些 props”那就太浪费了。属性 schema 是平台配置表单、AI 参数补全、页面 JSON 校验三者的共同基础。我整理过几条原则后面做新物料时都在遵守第一保持扁平不要把一个复杂对象整个塞进一个属性里否则配置表单只能显示一个 JSON 输入框非研发人员根本不会用第二每个属性都要给默认值AI 生成物料配置时需要知道缺省情况下是什么第三尽量用声明式规则表达联动比如“当布局为列表时显示某个字段”不要把这些逻辑写死在 settings.vue 里。除了以上几点属性的 label 要面向业务人员而不是面向开发。比如组件内部变量叫progressVisibleschema 里应该写成“显示进度条”而不是“progressVisible 是否可见”。AI 训练时也更容易从自然语言 label 中学习到这个物料该怎么配置。3.2 常用字段类型和联动规则物料属性最常见的字段类型大概有下表这些类型配置表单控件常见用途text单行输入框标题、文案、接口地址textarea多行输入框描述、富文本模板number数字输入框数量、间隔、阈值select下拉选择器枚举选项、布局模式switch开关是否显示某区域、是否启用某功能color颜色选择器主题色、背景色array可增删列表待办事项、展示列表>export const TodoCardSchema { props: [ { key: title, label: 标题, type: text, default: 待办事项, required: true }, { key: items, label: 事项列表, type: array, itemType: text, default: [需求评审, UI 走查, 联调验收] }, { key: progress, label: 显示进度, type: switch, default: true }, { key: layout, label: 布局方式, type: select, options: [ { label: 列表, value: list }, { label: 平铺, value: grid } ], default: list }, { key: theme, label: 主题色, type: color, default: #4F6AF5 } ], events: [ { key: click, label: 点击卡片 } ] }平台拿到这份 schema 后会为每个属性生成对应的表单控件并把当前物料 props 作为表单初始值。用户改完表单后平台再把新值写回页面 JSON。事件描述也很关键AI 生成页面交互时可以根据 events 自动装配“点击卡片后打开某路由”的联动逻辑。3.4 配置值如何运行时注入页面 JSON 里只会存一段可序列化的配置例如{ type: material.todo-card, id: mat_1290, props: { title: 本周冲刺, items: [需求评审, UI 走查], progress: true, layout: list, theme: #4F6AF5 } }渲染画布时平台动态加载物料 manifest 中的component再通过 Vue3 的动态组件能力把 props 传进去template component :iscurrentComponent v-bindmaterialProps v-onmaterialEvents / /template script setup langts import { computed } from vue import { useMaterialLoader } from platform/use-material-loader const props defineProps{ node: MaterialNode }() const { loadComponent, schemaToProps } useMaterialLoader() const currentComponent computed(() loadComponent(props.node.type)) const materialProps computed(() schemaToProps(props.node.props)) const materialEvents computed(() ({ click: (payload: any) emitNodeEvent(props.node.id, click, payload) })) /scriptschemaToProps这一步很重要它会把表单返回的字符串数字转成 number把选择器的 value 映射成组件真正接收的值并补齐默认值。很多物料在搭建态看起来正常、一到真实渲染就报错原因就是直接把表单原始值塞给了组件。4. 从 0 实现“待办卡片”物料完整走一遍链路4.1 创建组件本体组件本体没什么特殊的就是一个标准 Vue3 SFC。我建议把所有对外属性通过defineProps声明清楚不要把平台注入的一些内部字段混到 props 里。下面是 component.vue 的最小实现script setup langts defineProps{ title?: string items?: string[] progress?: boolean layout?: list | grid theme?: string }() defineEmits{ (e: click, payload: { action: string }): void }() /script template div classmt-todo-card :class[is-${layout}] :style{ --mt-theme: theme } click$emit(click, { action: card }) h4 classmt-todo-card__title{{ title }}/h4 ul v-iflayout list classmt-todo-card__list li v-for(item, index) in items :keyindex{{ item }}/li /ul div v-else classmt-todo-card__grid span v-for(item, index) in items :keyindex{{ item }}/span /div /div /template style scoped .mt-todo-card { border: 1px solid var(--mt-border-color, #e5e5e5); border-radius: 8px; padding: 16px; background: var(--mt-bg-color, #fff); } .mt-todo-card__title { margin: 0 0 12px; color: var(--mt-text-color, #333); } .mt-todo-card.is-grid { display: flex; gap: 8px; flex-wrap: wrap; } /style注意两个细节根节点类名我用mt-前缀降低和页面其他样式冲突的概率颜色值通过 CSS 变量透传而不是直接在模板里写:style{ color: theme }这样后续做主题切换时只需要在平台层覆盖 CSS 变量不用改每个物料。4.2 补充 preview 和 settingspreview.vue 不需要完整实现组件逻辑。我通常用静态结构和 CSS 模仿运行态外观甚至可以直接用一张图片占位。示例template div classmt-todo-card-preview p classp-title待办卡片/p p classp-item需求评审/p p classp-itemUI 走查/p /div /templatesettings.vue 如果物料逻辑简单可以不写平台会根据 schema 自动生成属性面板。只有遇到“需要在配置面板里嵌套数据表格”“需要可视化配置联动条件”这类复杂场景才需要单独实现。如果你选择实现 settings.vue我建议优先复用平台提供的SchemaForm组件它内部已经处理好类型转换和联动显隐了。4.3 在物料中心注册物料写好后有两种注册方式。第一种是平台启动时扫描固定目录比如src/materials/**/index.ts自动把物料收集起来适合内部项目第二种是走物料中心后台把打包后的物料上传或者填一个 Git 仓库地址由物料中心服务拉取并登记到数据库适合跨团队协作或需要权限审核的场景。我在内部平台里同时保留了两种方式开发阶段用扫描目录改了代码立即热更新发布阶段走物料中心后台经过构建、校验、审核后才进正式列表。这么做的好处是开发体验和线上稳定性可以兼顾。物料中心登记成功后列表页会出现“待办卡片”拖到画布就能用。4.4 在搭建画布中验证拖拽验证这步最容易暴露问题一定要按下面几条逐一检查从物料面板拖出“待办卡片”后右侧属性面板是否能自动出现字段。修改“标题”输入框画布中的卡片标题是否实时更新。切换“布局方式”为平铺画布是否从列表变为平铺。关闭“显示进度”开关对应区域是否消失。点击卡片是否能触发事件绑定器的日志输出。切换平台主题色卡片主题色是否跟随变化。如果以上全部通过说明这个物料在搭建态已经闭环。接下来要导出页面 JSON渲染到真实页面确认异步加载的 component 能正常显示。走到这一步一个最小可用的自定义物料就完成了。5. AI 如何参与自定义物料代码生成与 Schema 补全5.1 AI 在物料系统里的三种介入方式AI 驱动不是简单在物料中心挂一个聊天框而是要在合适的环节替代人工重复劳动。目前我见过比较实用的有三种方式。第一种是“物料推荐”AI 根据用户输入的业务描述从已有物料列表里筛出最匹配的几个并给出使用建议。第二种是“实例配置生成”AI 直接生成页面 JSON比如用户说“一个待办卡片标题叫冲刺计划包含三个事项”AI 输出完整的物料节点配置。第三种才是“物料源码生成”AI 根据需求和平台协议直接生成 component.vue、schema.ts、preview.vue 等文件。第二种最容易落地因为它不需要动态编译新代码只要约束好 JSON 结构就行。第三种价值最大但风险也最高不做好校验就放出来会变成事故现场。一个成熟的 AI 驱动物料系统应该同时支持三种方式按用户意图自动选择。5.2 自然语言生成物料的落地链路我们在物料中心做“AI 建物料”功能时走了这样一条链路用户输入“我要一个待办卡片列表展示可以配置三个待办事项点整张卡片能触发跳转。”平台先把这句描述转换成结构化请求附带当前平台所有物料协议示例、可用依赖列表、schema 规范一起发给大模型。大模型返回一个包含 component.vue、schema.ts、preview.vue 的代码包。平台后端对这个代码包做静态检查确认没有黑名单依赖、没有危险调用、import 路径合法。自动执行vue-tsc --noEmit做类型检查再用独立沙箱页面渲染这个组件。渲染通过后物料进入草稿状态等待业务负责人确认。整个链路里最关键的一步不是“生成”而是“校验”。我在草稿态里加了两个状态AI 已生成、人工已验证。只有经过真实页面验证的物料才能被正式使用否则 AI 生成的物料再惊艳也不能直接上架。5.3 降低幻觉的几个工程约束大模型写代码免不了出现幻觉最常见的包括import 一个不存在的依赖、使用平台协议里没有的字段、直接把演示数据写死在组件里。我的应对方式是给 AI 划出边界而不是让它自由发挥。第一固定模板。AI 只需要填充模板中的业务逻辑区域、样式区域和 schema 的 props 列表不允许修改 import 头和 export 结构。模板里已经把所有平台相关 API 引入好AI 没有机会自行发明。第二依赖白名单。平台校验器会检查代码里所有from xxx语句只允许vue、platform/material-types以及预设的 UI 库。第三schema 白名单。所有属性类型只能是平台已有的 type出现function、eval、v-html这类高风险写法时直接拦截。这样约束之后AI 生成的物料质量稳定不少至少不会出现“代码跑不起来”的情况。当然样式不好看、交互不符合业务预期这些问题仍然存在所以人工复核的行为不能省。6. 发布、版本与主题适配物料上线的最后一公里6.1 独立构建与按需加载自定义物料不应该随着平台主工程一起发版否则一次物料更新就要全量重新部署风险太大。我们的做法是把每个物料打包成一个独立的 ESM 模块放在静态资源服务或者对象存储上manifest 里记录这个模块的 URL。平台运行时动态加载const module await import(/* vite-ignore */ url)Vite 默认会解析动态 import 中的变量所以必须加上vite-ignore注释。如果团队用了 webpack 的 Module Federation也可以把物料注册为远程组件效果类似。不管哪种方案目标是同一个物料代码和平台代码运行时解耦物料出错不阻塞页面主流程。6.2 版本管理与页面兼容物料一旦被大量页面使用版本管理就变得很重要。manifest 里的version不能只是摆设。页面 JSON 里除了记录type还要记录materialVersion。当物料发布新版本时旧页面可以继续加载旧版本只有新拖入或主动升级的页面才使用新版本。Schema 变化要有一套兼容策略。新增字段可以用 default 填充删除字段时老页面 JSON 里多出来的字段要能忽略如果只是字段重命名schema 里可以加一个deprecatedFrom平台读取旧配置时自动映射。没有这套逻辑版本升级基本靠全网搜索哪个页面报错非常痛苦。6.3 样式隔离与主题变量样式隔离是自定义物料最容易被忽略的坑。如果你的平台把物料代码直接注入页面而物料内部又用了全局类名很可能覆盖平台自身样式。我的建议是三层防护第一层组件根类名加mt-前缀第二层CSS 使用scoped或在 style 块里加一层根节点作用域第三层不要直接依赖第三方 UI 库的全局主题类名所有颜色、圆角、间距尽量用平台提供的 CSS 变量。平台可以定义一组全局主题变量比如--mt-primary、--mt-success、--mt-border-color、--mt-bg-color。主题切换时只换变量值所有物料同步变化。如果物料把颜色写死换肤效果就会漏掉一块。6.4 灰度与回滚的实操顺序我踩过“物料新版本上线即白屏”的坑后来把发布流程固化成先灰度再全量。具体顺序是物料中心提交新版本后选择 1% 流量试运行观察运行时错误率和“物料加载成功率”是否异常如果稳定升到 10% 再观察确认没问题后全量开放。回滚时不需要重新发布页面只需要在物料中心把版本号回退到旧版已经加载的页面下一次进入就能自动切回。灰度期间如果发现错误平台要把错误信息记录到物料维度的监控看板上包括加载报错、渲染报错、事件派发报错。没有监控就贸然全量等于把一个未验证的组件塞进了所有业务页面。7. 踩坑实录渲染方案、响应式丢失和 AI 生成的边界7.1 运行时渲染为什么不建议所有物料都走 render 函数很多低代码框架喜欢在渲染器内部写一堆h(component, props)这是为了性能可控。但我在自定义物料这条线上吃过亏用 render 函数写业务组件代码可读性很差组件一复杂就没人愿意维护。后来我们把自定义物料的组件形式统一成 SFC渲染器只做component动态加载内部细节全部交给开发者。这样既保留了动态渲染能力又让业务代码回归正常 Vue3 开发习惯。还要注意异步组件的加载体验。动态import()在弱网环境下会产生白屏我一般会给异步组件配置loading和delay或者在物料加载失败时展示一个“物料加载失败”的占位块而不是直接抛异常。物料出问题不能拖垮整个页面这是底线。7.2 响应式丢失和 props 被污染Vue3 下很多人以为用reactive包一下 props 就安全了其实还有两个隐藏坑。第一子组件内部用const { title } props解构后再在模板里使用title一旦父级更新解构出来的值不会自动变。官方推荐直接用props.title或者用toRefs解构。第二物料组件内部如果反向修改了 props 对象上的属性因为 props 来自平台 store 的响应式对象很可能把平台状态改脏导致其他物料联动异常。平台端的思路是把页面 JSON 里的物料配置做一次深拷贝再传给组件并且用只读方式注入组件任何修改只能通过 emit 事件上报。这样能最大限度避免“一个物料的 bug 污染整个页面状态”。7.3 AI 生成物料的安全边界与人工确认AI 生成物料最终还是要落到平台上运行所以安全边界必须前置。我们的校验器会从源码中搜索黑名单模式eval、new Function、document.write、动态拼接 URL 请求、未知协议的网络地址。凡是命中的直接拦截不让进入草稿态。这不是不信任 AI而是环境里可能有人故意构造恶意提示词AI 会无意中生成危险代码。另外AI 生成的物料在卡片上要打上“AI 生成待人工确认”的标签。只有人工在真实页面验证过功能、看过样式、检查过接口数据后才能转正。我自己的体会是生成物料这件事AI 能把“写代码”的周期从一天压到十分钟但最后的把关责任仍然在开发者身上。协议足够稳定、校验足够严格、人工确认足够认真自定义物料才能真正成为 Vue3 搭建平台的长期生产力。
返回列表