核心引擎
简介
本文件面向核心引擎模块,系统化阐述 ProjectModel 的设计架构、BlockModel 的实现细节、NodeModel 的抽象机制;并从项目数据模型的完整生命周期、状态管理机制、事件系统设计出发,给出协议定义、工具函数库、API 参考与集成方式,帮助开发者快速上手并进行深度扩展。
项目结构
核心引擎位于 packages/core,采用"协议 + 模型 + 工具"的分层组织:
- 协议层:定义跨模块共享的数据结构与服务接口
- 模型层:以 ProjectModel、BlockModel、NodeModel 为核心,承载业务数据与行为
- 工具层:事件总线、克隆 DSL、通用工具等
graph TB
subgraph "核心引擎"
P["ProjectModel
项目模型"] B["BlockModel
区块模型"] N["NodeModel
节点模型"] PR["PropModel
属性模型"] ER["EventModel
事件模型"] DR["DirectiveModel
指令模型"] EM["事件总线
emitter"] end subgraph "协议层" PI["协议入口
protocols/index.ts"] end P --> B B --> N N --> PR N --> ER N --> DR B --> EM N --> EM P --> EM PI --> P PI --> B PI --> N
项目模型"] B["BlockModel
区块模型"] N["NodeModel
节点模型"] PR["PropModel
属性模型"] ER["EventModel
事件模型"] DR["DirectiveModel
指令模型"] EM["事件总线
emitter"] end subgraph "协议层" PI["协议入口
protocols/index.ts"] end P --> B B --> N N --> PR N --> ER N --> DR B --> EM N --> EM P --> EM PI --> P PI --> B PI --> N
核心组件
- Base:提供 ready/triggerReady 机制,用于延迟回调直到就绪
- ProjectModel:项目级数据容器与操作入口,负责页面/区块/依赖/API/Meta 等资源的增删改查与事件广播
- BlockModel:区块级数据容器,管理节点树、状态、函数、属性、事件、插槽、数据源等,并提供节点增删移动与克隆能力
- NodeModel:节点级数据容器,管理属性、事件、指令、子节点、可见性、锁定等,支持层级移动与销毁
- PropModel/EventModel/DirectiveModel:对属性、事件、指令的抽象与序列化
架构总览
核心引擎通过协议定义统一的数据契约,模型之间以组合与父子关系协作,事件总线贯穿各层,形成松耦合、可扩展的体系。
classDiagram
class ProjectModel {
+id : string
+platform : PlatformType
+name : string
+pages : PageFile[]
+blocks : BlockFile[]
+apis : ApiSchema[]
+meta : MetaSchema[]
+currentFile : PageFile|BlockFile|null
+update(schema, silent)
+active(file, silent)
+deactivate(silent)
+createPage(page, parentId?, silent)
+updatePage(page, silent)
+movePageTo(pageId, parentId?, silent)
+clonePage(page, parentId?, silent)
+saveToBlock(page, silent)
+removePage(id, silent)
+createBlock(block, silent)
+updateBlock(block, silent)
+cloneBlock(block, silent)
+removeBlock(id, silent)
+setDeps(item, silent)
+removeDeps(item, silent)
+setApi(item, silent)
+setApis(items, silent)
+removeApi(name, silent)
+toDsl(version?)
}
class BlockModel {
+id : string
+name : string
+state : BlockState
+props : BlockProp[]
+emits : BlockEmit[]
+slots : BlockSlot[]
+dataSources : Record
+nodes : NodeModel[]
+update(schema, silent)
+toDsl(version?)
+addNode(node, target?, position, silent)
+removeNode(node, silent)
+move(node, target?, position, silent)
+movePrev(node, silent)
+moveNext(node, silent)
+cloneNode(target, silent)
+setState(name, value, silent)
+setFunction(type, name, value, silent)
+setProp(prop, silent)
+setEmit(emit, silent)
+setSlot(slot, silent)
+setInject(inject, silent)
+setDataSource(source, silent)
+lock(silent)
+unlock(silent)
}
class NodeModel {
+id : string
+name : string
+from : NodeFrom
+invisible : boolean
+locked : boolean
+children : NodeModel[]|string|JSExpression
+slot? : NodeSlot
+props : Record
+events : Record
+directives : DirectiveModel[]
+update(schema, silent)
+setChildren(children, silent)
+setSlot(slot, silent)
+setProp(name, value, default?, silent)
+removeProp(name, silent)
+getPropValue(name)
+setEvent(schema, silent)
+removeEvent(name, silent)
+setDirective(schema, silent)
+removeDirective(directive, silent)
+appendChild(node, silent)
+insertAfter(node, silent)
+insertBefore(node, silent)
+movePrev(silent)
+moveNext(silent)
+toDsl()
+dispose(silent)
+lock(silent)
+unlock(silent)
+setVisible(visible, silent)
}
ProjectModel --> BlockModel : "持有/创建"
BlockModel --> NodeModel : "拥有"
NodeModel --> PropModel : "使用"
NodeModel --> EventModel : "使用"
NodeModel --> DirectiveModel : "使用"
详细组件分析
ProjectModel 设计与生命周期
- 数据属性:平台类型、名称、描述、主页、依赖、页面树、区块集、API 列表、Meta、当前激活文件、配置、国际化、环境变量等
- 生命周期关键点
- 初始化:根据传入模式 schema 填充字段,生成唯一标识
- 更新:批量更新受控属性列表,支持静默更新避免重复广播
- 序列化:toDsl 输出项目 DSL,清理页面 DSL 中的冗余字段
- 文件激活/失活:active/deactivate 广播当前文件变更
- 依赖管理:setDeps/removeDeps 广播依赖变更与整体变更
- 页面管理:创建/更新/移动/复制/删除页面,维护目录树与 homepage
- 区块管理:创建/更新/复制/删除区块,支持从页面保存为区块
- API 管理:按名称或 ID 增删改,批量设置
- 事件系统:统一通过事件总线广播项目级变更,便于上层订阅
sequenceDiagram
participant Dev as "调用方"
participant PM as "ProjectModel"
participant EM as "事件总线"
Dev->>PM : "createPage(page, parentId?, silent)"
PM->>PM : "填充id/name/type/dsl"
alt "指定父目录"
PM->>PM : "插入到父目录children"
else "根目录"
PM->>PM : "push到pages"
end
alt "非静默"
PM->>EM : "EVENT_PROJECT_PAGES_CHANGE"
PM->>EM : "EVENT_PROJECT_CHANGE"
end
opt "首次创建且无激活文件"
PM->>PM : "delay(1000)"
PM->>PM : "active(page)"
end
PM-->>Dev : "返回page"
BlockModel 实现细节
- 数据结构:名称、注入、状态、生命周期/方法/计算属性、监听、CSS、属性、事件、暴露、插槽、数据源、节点树、锁定、销毁标记
- 节点操作
- 添加/删除/移动:支持相对目标节点的 left/right/top/bottom/inner 五种位置
- 克隆:基于深拷贝 DSL 重建节点并插入
- 排序:支持同级前后移动
- 锁定/解锁:递归作用于子节点
- 功能管理
- setFunction/removeFunction:methods/computed/lifeCycles
- setState/removeState:区块级状态
- setCss:样式内容
- setWatch/removeWatch:监听器
- setProp/removeProp:区块属性
- setEmit/removeEmit:事件声明
- setExpose:暴露列表
- setSlot/removeSlot:插槽声明
- setInject/removeInject:注入
- setDataSource/removeDataSource:数据源
- 序列化:toDsl 输出区块 DSL,包含版本号与节点树
flowchart TD
Start(["调用 addNode"]) --> HasTarget{"是否有目标节点?"}
HasTarget -- 否 --> Append["追加到末尾"]
HasTarget -- 是 --> Pos{"位置(left/right/top/bottom/inner)"}
Pos -- "left/top" --> InsertBefore["插入到目标前"]
Pos -- "right/bottom" --> InsertAfter["插入到目标后"]
Pos -- "inner" --> AppendChild["作为目标子节点"]
Append --> Emit["广播变更"]
InsertBefore --> Emit
InsertAfter --> Emit
AppendChild --> Emit
NodeModel 抽象机制
- 数据抽象:属性、事件、指令均以独立模型封装,支持解析与序列化
- 层级操作:支持 appendChild/insertAfter/insertBefore/前后移动/删除子节点
- 可见性与锁定:支持整棵子树传播
- 销毁:递归销毁子节点并从父节点移除,释放全局索引
- 序列化:toDsl 将属性/事件/指令转为 DSL 结构
classDiagram
class PropModel {
+name : string
+value
+defaultValue
+isUnset : boolean
+setValue(value)
+getValue()
+toDsl(props)
+parse(props)
}
class EventModel {
+name : string
+handler : JSFunction
+modifiers : NodeModifiers
+update(schema)
+toDsl(events)
+parse(events)
}
class DirectiveModel {
+id : string
+name
+arg
+modifiers
+value
+iterator
+update(schema)
+toDsl(directives)
+parse(directives)
}
NodeModel --> PropModel : "使用"
NodeModel --> EventModel : "使用"
NodeModel --> DirectiveModel : "使用"
事件系统设计
- 事件总线:集中发布/订阅,屏蔽底层实现
- 项目级事件:如页面变更、区块变更、依赖变更、API 变更、Meta 变更、发布、出码等
- 模型级事件:如节点变更、区块变更
- 使用建议:在初始化阶段订阅所需事件,避免在渲染热路径频繁订阅
依赖分析
- 模块内聚:模型间通过组合与父子关系耦合,职责清晰
- 外部依赖:依赖 @vtj/base 提供唯一 ID、深拷贝、字符串处理、延时等基础能力
- 事件耦合:通过事件总线解耦广播与订阅者
- 可能的循环依赖:当前结构未见直接循环导入
graph LR
Base["@vtj/base"] --> PM["ProjectModel"]
Base["@vtj/base"] --> BM["BlockModel"]
Base["@vtj/base"] --> NM["NodeModel"]
EM["事件总线"] --> PM
EM --> BM
EM --> NM
性能考虑
- 静默更新:大量批处理时使用 silent,减少事件风暴
- 深拷贝与序列化:toDsl 与 cloneDsl 仅在必要时执行,避免频繁深拷贝
- 事件广播:集中于关键节点,避免在高频操作中广播
- 节点树遍历:移动/查找/克隆等操作注意 O(n) 复杂度,必要时引入缓存或索引
故障排查指南
- 事件未触发:确认未使用静默模式;检查事件常量是否正确
- 页面/区块未更新:确认已调用对应更新方法并满足条件分支
- 节点移动异常:检查目标节点是否存在、位置参数是否合法
- 依赖/API 未生效:确认 setXxx 后是否触发了相应事件广播
结论
核心引擎以协议为契约、以模型为中心、以事件为纽带,构建了高内聚、低耦合的数据模型体系。通过 ProjectModel、BlockModel、NodeModel 的分层抽象,开发者可以高效地完成页面与区块的全生命周期管理,并借助事件系统与工具库实现复杂交互与扩展。
附录:API 参考
ProjectModel
- 构造与更新
- 构造函数:接收项目模式,生成唯一标识并初始化
- update(schema, silent=false):批量更新受控属性,支持静默
- toDsl(version?):输出项目 DSL,清理页面 DSL 冗余字段
- 文件激活
- active(file, silent=false):激活文件
- deactivate(silent=false):取消激活
- 依赖管理
- setDeps(item, silent=false):新增/更新依赖
- removeDeps(item, silent=false):删除依赖
- 页面管理
- createPage(page, parentId?, silent=false):创建页面,自动填充 id/name/type/dsl
- updatePage(page, silent=false):更新页面
- movePageTo(pageId, parentId?, silent=false):移动页面到指定目录
- clonePage(page, parentId?, silent=false):复制页面
- saveToBlock(page, silent=false):将页面保存为区块
- removePage(id, silent=false):删除页面
- getPage(id):按 id 查找页面或目录
- getPages():获取全部页面(不含目录)
- findParent(id):查找父级
- getPageTree():返回页面树(已清理 dsl)
- getHomepage():获取首页
- 区块管理
- createBlock(block, silent=false):创建区块
- updateBlock(block, silent=false):更新区块
- cloneBlock(block, silent=false):复制区块
- removeBlock(id, silent=false):删除区块
- getBlock(id):按 id 查找区块
- getFile(id):按 id 查找页面或区块
- API 管理
- setApi(item, silent=false):新增/更新 API
- setApis(items, silent=false):批量设置 API
- removeApi(name, silent=false):按名称或 id 删除 API
BlockModel
- 构造与更新
- 构造函数:接收区块模式,生成唯一标识并初始化
- update(schema, silent=false):更新受控属性,重置节点树
- toDsl(version?):输出区块 DSL,包含版本号与节点树
- dispose():销毁节点树并标记自身销毁
- 节点操作
- addNode(node, target?, position='inner', silent=false):添加节点
- removeNode(node, silent=false):删除节点
- move(node, target?, position='inner', silent=false):移动节点
- movePrev(node, silent=false)/moveNext(node, silent=false):同级前后移动
- cloneNode(target, silent=false):克隆节点
- lock(silent=false)/unlock(silent=false):锁定/解锁
- isChild(node):判断是否为后代
- 功能管理
- setFunction(type, name, value, silent=false):设置方法/计算属性/生命周期
- removeFunction(type, name, silent=false):删除方法/计算属性/生命周期
- setState(name, value, silent=false):设置状态
- removeState(name, silent=false):删除状态
- setCss(content, silent=false):设置 CSS
- setWatch(watch, silent=false)/removeWatch(watch, silent=false):监听器
- setProp(prop, silent=false)/removeProp(prop, silent=false):属性
- setEmit(emit, silent=false)/removeEmit(emit, silent=false):事件
- setExpose(expose, silent=false):暴露列表
- setSlot(slot, silent=false)/removeSlot(slot, silent=false):插槽
- setInject(inject, silent=false)/removeInject(inject, silent=false):注入
- setDataSource(source, silent=false)/removeDataSource(name, silent=false):数据源
NodeModel
- 构造与更新
- 构造函数:接收节点模式,生成唯一标识并注册到全局索引
- update(schema, silent=false):更新属性、事件、指令与子节点
- toDsl():输出节点 DSL
- dispose(silent=false):销毁并从父节点移除
- 子节点管理
- setChildren(children, silent=false):设置子节点(数组或表达式)
- setSlot(slot, silent=false):设置插槽
- appendChild(node, silent=false):追加子节点
- insertAfter(node, silent=false):插入到兄弟之后
- insertBefore(node, silent=false):插入到兄弟之前
- removeChild(node, silent=false):删除子节点
- movePrev(silent=false)/moveNext(silent=false):同级前后移动
- 属性/事件/指令
- setProp(name, value, default?, silent=false):设置属性
- removeProp(name, silent=false):删除属性
- getPropValue(name):获取属性值
- setEvent(schema, silent=false):设置事件
- removeEvent(name, silent=false):删除事件
- setDirective(schema, silent=false):设置指令
- removeDirective(directive, silent=false):删除指令
- 可见性与锁定
- setVisible(visible, silent=false):整棵子树设置可见性
- lock(silent=false)/unlock(silent=false):锁定/解锁
- 辅助
- isChild(node):判断是否为后代
- findChildIndex(child):查找子节点索引
工具与协议
- 工具入口:导出事件总线与通用工具
- 协议入口:导出共享、资产、模式、服务、插件协议
参考资料
VTJ.PRO 是一个开源的、AI 驱动的 Vue 3 企业级应用开发平台。它通过 AI 智能体与可视化编排实现高效开发,并支持导出标准 Vue 代码以避免平台锁定。更多信息请访问:
- 📘 官方文档:vtj.pro/
- 🌐 在线平台:app.vtj.pro/
- 📦 开源仓库:gitee.com/newgateway/...