项目模型系统
引言
本技术文档围绕 VTJ 低代码平台的"项目模型系统",系统性阐述 ProjectModel、BlockModel 与 NodeModel 的设计架构、数据结构、操作流程与 API 使用方式。文档旨在帮助开发者快速理解并高效使用模型系统进行页面与区块的创建、更新、删除与组织,掌握事件驱动的数据流转机制,并提供最佳实践与常见问题解决方案。
项目结构
项目模型系统位于核心包中,采用"分层数据结构"组织项目与区块,配合事件总线实现状态变更通知。核心文件如下:
- ProjectModel:项目级状态与文件管理(页面/区块/依赖/API/Meta 等)
- BlockModel:区块级状态与节点树管理(含节点增删改、移动、克隆、锁定等)
- NodeModel:DOM 节点抽象(属性、事件、指令、插槽、可见性、层级关系等)
graph TB
subgraph "核心模型"
PM["ProjectModel
项目模型"] BM["BlockModel
区块模型"] NM["NodeModel
节点模型"] end subgraph "协议与类型" PS["ProjectSchema
项目协议"] BS["BlockSchema
区块协议"] NS["NodeSchema
节点协议"] SH["Shared Types
共享类型(JSONValue/JSFunction/JSExpression)"] end PM --> BM BM --> NM PM --> PS BM --> BS NM --> NS BS --> NS PS --> SH BS --> SH NS --> SH
项目模型"] BM["BlockModel
区块模型"] NM["NodeModel
节点模型"] end subgraph "协议与类型" PS["ProjectSchema
项目协议"] BS["BlockSchema
区块协议"] NS["NodeSchema
节点协议"] SH["Shared Types
共享类型(JSONValue/JSFunction/JSExpression)"] end PM --> BM BM --> NM PM --> PS BM --> BS NM --> NS BS --> NS PS --> SH BS --> SH NS --> SH
核心组件
- ProjectModel
- 职责:项目级 CRUD、文件管理(页面/区块)、依赖/API/Meta 管理、活动文件切换、序列化导出
- 关键能力:创建/更新/移动/复制/删除页面;创建/更新/克隆/删除区块;设置/移除依赖;设置/移除 API;打开/关闭文件
- 事件:项目变更、活动文件变更、页面变更、区块变更、依赖变更、发布、出码等
- BlockModel
- 职责:区块级状态管理(注入、状态、方法、计算属性、watch、CSS、props/emits/expose/slots、数据源)、节点树管理
- 关键能力:节点添加/删除/移动/克隆;锁定/解锁;设置/移除函数、状态、CSS、watch、props、emits、slots、inject、数据源
- NodeModel
- 职责:节点抽象(组件/HTML 标签)、属性、事件、指令、插槽、可见性、层级关系
- 关键能力:设置/移除属性、事件、指令;设置插槽;追加/插入/删除子节点;前后移动;锁定/解锁;可见性传播;销毁与层级校验
架构总览
项目模型系统采用"事件驱动 + DSL 序列化"的架构:
- 事件驱动:各模型在状态变更时通过统一事件总线发出事件,便于上层设计器与渲染器响应
- DSL 序列化:toDsl 输出标准化结构,便于持久化、版本控制、模板发布与代码生成
- 分层组织:ProjectModel 管理页面/区块集合,BlockModel 管理节点树,NodeModel 表示具体 DOM 节点
sequenceDiagram
participant UI as "设计器/UI"
participant PM as "ProjectModel"
participant BM as "BlockModel"
participant NM as "NodeModel"
UI->>PM : "创建页面/区块"
PM-->>UI : "触发页面/区块变更事件"
UI->>BM : "添加/移动/删除节点"
BM->>NM : "构造/更新子节点"
BM-->>UI : "触发区块变更事件"
UI->>PM : "打开/关闭文件"
PM-->>UI : "触发活动文件变更事件"
UI->>PM : "导出项目DSL"
PM->>PM : "清理页面DSL字段"
PM-->>UI : "返回DSL结构"
详细组件分析
ProjectModel 详解
- 数据结构
- 核心属性:id、name、platform、pages、blocks、currentFile、dependencies、apis、meta、config、uniConfig、globals、i18n、env、BASE_PATH 、UID
- 静态属性列表:用于统一更新与序列化
- 文件管理
- 页面:创建、更新、移动到目录、复制、保存为区块、删除
- 区块:创建、更新、克隆、删除
- 活动文件:active/deactivate 切换
- 依赖与 API
- setDeps/removeDeps、setApi/setApis/removeApi
- 序列化
- toDsl:清理页面 DSL 字段,输出标准化项目结构
flowchart TD
Start(["开始"]) --> CreatePage["创建页面"]
CreatePage --> BuildDSL["生成默认DSL"]
BuildDSL --> AddToTree["加入页面树"]
AddToTree --> AutoOpen{"是否自动打开?"}
AutoOpen --> |是| Active["激活页面"]
AutoOpen --> |否| End(["结束"])
Active --> End
BlockModel 详解
- 数据结构
- 核心属性:id、name、inject、state、lifeCycles/methods/computed/watch、css、props/emits/expose/slots、dataSources、nodes、locked、disposed
- 正常属性列表:用于批量更新
- 节点管理
- 添加节点:addNode(支持 left/right/top/bottom/inner 五种位置)
- 删除节点:removeNode(区分根节点与子节点)
- 移动节点:move(先从原父节点移除,再添加到目标位置)
- 克隆节点:cloneNode(基于 DSL 深拷贝)
- 前后移动:movePrev/moveNext
- 状态与元信息
- setFunction/removeFunction、setState/removeState、setCss、setWatch/removeWatch、setProp/removeProp、setEmit/removeEmit、setExpose、setSlot/removeSlot、setInject/removeInject、setDataSource/removeDataSource
- 锁定与层级传播
- lock/unlock 会递归作用于子节点
- 序列化
- toDsl:输出区块 DSL,包含节点树
classDiagram
class BlockModel {
+string id
+string name
+BlockInject[] inject
+Record~string, any~ state
+Record~string, JSFunction~ lifeCycles
+Record~string, JSFunction~ methods
+Record~string, JSFunction~ computed
+BlockWatch[] watch
+string css
+any[] props
+any[] emits
+string[] expose
+any[] slots
+Record~string, DataSourceSchema~ dataSources
+NodeModel[] nodes
+boolean locked
+boolean disposed
+update(schema, silent)
+toDsl(version?)
+addNode(node, target?, position, silent)
+removeNode(node, silent)
+move(node, target?, position, silent)
+cloneNode(target, silent)
+movePrev(node, silent)
+moveNext(node, silent)
+lock(silent)
+unlock(silent)
+isChild(node)
}
BlockModel --> NodeModel : "包含"
NodeModel 详解
- 数据结构
- 标识与来源:id、name、from
- 可见性与锁定:invisible、locked
- 层级与插槽:children(数组/表达式/字符串)、slot
- 属性/事件/指令:props(PropModel)、events(EventModel)、directives(DirectiveModel[])
- 销毁状态:disposed
- 操作能力
- 更新:update(批量设置属性/事件/指令/子节点/插槽)
- 子节点:appendChild/insertAfter/insertBefore/removeChild
- 前后移动:movePrev/moveNext
- 属性/事件/指令:setProp/removeProp、setEvent/removeEvent、setDirective/removeDirective
- 可见性传播:setVisible
- 锁定传播:lock/unlock
- 销毁:dispose(递归销毁子节点并从父节点移除)
- 层级校验:isChild/findChildIndex
- 序列化
- toDsl:输出节点 DSL,包含子树、属性、事件、指令
classDiagram
class NodeModel {
+string id
+string name
+string from
+boolean invisible
+boolean locked
+slot NodeSlot
+boolean disposed
+update(schema, silent)
+setChildren(children, silent)
+setSlot(slot, silent)
+setProp(name, value, default?, silent)
+removeProp(name, silent)
+getPropValue(name)
+setEvent(event, silent)
+removeEvent(name, silent)
+setDirective(dir, silent)
+removeDirective(dir, silent)
+appendChild(node, silent)
+insertAfter(node, silent)
+insertBefore(node, silent)
+removeChild(node, silent)
+movePrev(silent)
+moveNext(silent)
+setVisible(visible, silent)
+lock(silent)
+unlock(silent)
+dispose(silent)
+isChild(node)
+findChildIndex(child)
}
NodeModel --> PropModel : "使用"
NodeModel --> EventModel : "使用"
NodeModel --> DirectiveModel : "使用"
协议与类型体系
- ProjectSchema:项目结构协议,包含平台、页面、区块、依赖、API、Meta、配置等
- BlockSchema:区块结构协议,包含注入、状态、方法、计算属性、watch、CSS、props/emits/expose/slots、数据源、节点树等
- NodeSchema:节点结构协议,包含属性、事件、指令、插槽、子节点等
- Shared Types:JSONValue、JSExpression、JSFunction、DataType、平台类型等
依赖关系分析
- 模型间依赖
- ProjectModel 依赖 BlockModel(页面 DSL 默认由 BlockModel 生成)
- BlockModel 依赖 NodeModel(节点树)
- NodeModel 依赖 PropModel、EventModel、DirectiveModel(属性/事件/指令抽象)
- 事件总线
- 通过统一事件发射器对外广播变更事件,便于上层订阅与响应
- 类型与协议
- 所有模型均遵循对应 Schema 协议,保证序列化与反序列化的稳定性
graph LR
PM["ProjectModel"] --> BM["BlockModel"]
BM --> NM["NodeModel"]
NM --> PMD["PropModel/EventModel/DirectiveModel"]
PM -.-> EVT["事件总线"]
BM -.-> EVT
NM -.-> EVT
性能考量
- 节点树遍历与层级传播
- lock/unlock、setVisible、isChild 等操作涉及递归遍历,建议在批量操作时使用静默模式减少事件风暴
- 事件风暴控制
- 大量节点更新时,优先使用静默更新并在最后一次性触发事件
- 序列化优化
- toDsl 会清理页面 DSL 字段,避免冗余数据传输与存储
- 内存释放
- dispose 会递归销毁子节点并从父节点移除,防止内存泄漏
故障排查指南
- 页面/区块未生效
- 检查是否调用了 create/update/saveToBlock 等方法并正确触发事件
- 确认 currentFile 已被 active
- 节点无法移动/删除
- 确认节点存在且未被锁定(locked)
- 使用 isChild 校验父子关系
- 事件未触发
- 确认未使用静默模式(silent=true)
- 检查事件常量与监听器是否一致
- 序列化结果异常
- 确认调用 toDsl 且未手动保留 DSL 字段
结论
项目模型系统以清晰的分层结构与事件驱动机制,提供了从项目到区块再到节点的全链路数据抽象与操作能力。通过标准化的 DSL 序列化与完善的 API,开发者可以高效地构建、维护与扩展低代码页面与区块,同时借助事件总线实现与设计器、渲染器的无缝集成。
附录
API 参考(概览)
- ProjectModel
- 创建/更新/移动/复制/删除页面:createPage/updatePage/movePageTo/clonePage/removePage
- 创建/更新/克隆/删除区块:createBlock/updateBlock/cloneBlock/removeBlock
- 活动文件:active/deactivate
- 依赖与 API:setDeps/removeDeps、setApi/setApis/removeApi
- 序列化:toDsl
- BlockModel
- 节点管理:addNode/removeNode/move/cloneNode/movePrev/moveNext
- 状态与元信息:setFunction/removeFunction、setState/removeState、setCss、setWatch/removeWatch、setProp/removeProp、setEmit/removeEmit、setExpose、setSlot/removeSlot、setInject/removeInject、setDataSource/removeDataSource
- 锁定与层级:lock/unlock/isChild
- 序列化:toDsl
- NodeModel
- 更新:update
- 子节点:appendChild/insertAfter/insertBefore/removeChild
- 前后移动:movePrev/moveNext
- 属性/事件/指令:setProp/removeProp、setEvent/removeEvent、setDirective/removeDirective
- 可见性与锁定:setVisible/lock/unlock
- 销毁与层级:dispose/isChild/findChildIndex
- 序列化:toDsl
使用示例(路径指引)
- 创建页面并自动打开
- 将页面保存为区块
- 在区块中添加节点
- 克隆节点
- 设置节点属性/事件/指令
- 锁定/解锁节点树
参考资料
VTJ.PRO 是一个开源的、AI 驱动的 Vue 3 企业级应用开发平台。它通过 AI 智能体与可视化编排实现高效开发,并支持导出标准 Vue 代码以避免平台锁定。更多信息请访问:
- 📘 官方文档:vtj.pro/
- 🌐 在线平台:app.vtj.pro/
- 📦 开源仓库:gitee.com/newgateway/...