交互机制
更新摘要
变更内容
- 左侧面板宽度从30%增加到36%
- 所有项目组件添加工具提示功能,支持显示完整文本内容
- 表单提交时的节点缓存清理机制更新
简介
本文件系统性梳理设计器的交互机制,覆盖拖拽、点击选择、键盘快捷键、历史记录与撤销重做、状态快照与全局状态同步、事件监听与处理、自定义交互扩展、性能优化与内存防护等主题。目标是帮助开发者快速理解并高效扩展设计器的交互能力。
项目结构
设计器交互相关的关键模块分布如下:
- 引擎层:统一调度与状态管理,负责事件绑定、历史记录持久化、渲染与模拟器桥接
- 模拟器层:在 iframe 中构建渲染环境,注入物料与依赖,承载渲染器与设计器实例
- 设计器层:封装可视化画布上的交互事件(鼠标、拖拽、键盘),维护 hover/selected/dropping 状态
- 钩子层:提供快捷键、设计器状态计算、拖拽指令等可复用能力
- 核心模型:历史记录模型、区块模型等
- 渲染服务:本地/内存/存储三种历史与文件服务实现
graph TB
subgraph "引擎层"
Engine["Engine<br/>事件绑定/历史持久化"]
State["State<br/>全局状态"]
end
subgraph "模拟器层"
Simulator["Simulator<br/>iframe环境/渲染器/设计器"]
end
subgraph "设计器层"
Designer["Designer<br/>事件处理/状态维护"]
Hotkeys["useHotkeys<br/>快捷键"]
UseDesigner["useDesigner<br/>状态计算"]
end
subgraph "核心模型"
HistoryModel["HistoryModel<br/>历史记录"]
BlockModel["BlockModel<br/>区块状态"]
end
subgraph "渲染服务"
Local["LocalService"]
Memory["MemoryService"]
Storage["StorageService"]
end
Engine --> Simulator
Simulator --> Designer
Designer --> Hotkeys
Designer --> UseDesigner
Engine --> HistoryModel
Engine --> Local
Engine --> Memory
Engine --> Storage
Engine --> BlockModel
State --> Engine
核心组件
- 引擎 Engine:集中事件监听、项目/文件/历史持久化、当前区块切换、渲染刷新、发布与源码生成等
- 模拟器 Simulator:在 iframe 中搭建渲染环境,注入物料与依赖,创建渲染器与设计器实例
- 设计器 Designer:封装画布事件(鼠标悬停、拖拽、点击)、计算 hover/selected/dropping 状态、辅助线绘制
- 快捷键 useHotkeys:统一绑定撤销/重做、保存、预览、刷新、复制/粘贴/剪切、方向键导航、全选等
- 设计器钩子 useDesigner:将 Designer 状态映射为 UI 可用的样式与位置信息,联动 outlineEnabled
- 历史模型 HistoryModel:支持前进/后退/加载/清理,事件驱动持久化
- 渲染服务:本地/内存/存储三种实现,分别对接浏览器存储、内存与远端服务
架构总览
设计器交互遵循"引擎-模拟器-设计器"的分层架构:
- 引擎负责跨模块协调与持久化
- 模拟器负责渲染环境隔离与物料注入
- 设计器负责画布交互与状态可视化
- 钩子与指令提供可复用的交互能力
sequenceDiagram
participant User as "用户"
participant Designer as "Designer"
participant Engine as "Engine"
participant Simulator as "Simulator"
participant Renderer as "Renderer"
participant History as "HistoryModel"
User->>Designer : "鼠标/键盘交互"
Designer->>Engine : "更新selected/hover/dropping"
Designer->>Engine : "触发拖拽/点击/键盘事件"
Engine->>History : "事件驱动历史记录"
History-->>Engine : "持久化历史项"
Engine->>Simulator : "刷新渲染"
Simulator->>Renderer : "重新渲染当前区块"
Renderer-->>User : "更新后的画布"
详细组件分析
拖拽交互机制
- 触发链路:dragstart 记录拖拽源(物料描述或节点),dragover 判断允许放置区域(left/right/top/bottom/inner),drop 执行放置逻辑(新增/移动节点)
- 放置判定:allowDrop 校验目标节点类型、父子关系、HTML 标签、物料约束(parentIncludes/childIncludes)
- 插槽选择:当目标为组件节点时,根据动态插槽与物料定义合并生成候选插槽,必要时弹窗选择
- 辅助反馈:dropping 状态与视觉反馈(辅助线/高亮)
flowchart TD
Start(["拖拽开始"]) --> DragStart["记录拖拽源<br/>setDragging/setDraggingNode"]
DragStart --> DragOver["dragover 计算放置类型"]
DragOver --> AllowDrop{"allowDrop 校验"}
AllowDrop --> |否| NoDrop["清除 dropping"]
AllowDrop --> |是| DropSlot["获取目标插槽"]
DropSlot --> |用户取消| Cancel["终止拖拽"]
DropSlot --> |确定| DoDrop["执行放置<br/>addNode/move"]
DoDrop --> Refresh["刷新渲染/清理缓存"]
NoDrop --> End(["结束"])
Cancel --> End
Refresh --> End
点击选择与状态变更
- 点击处理:onSelected 在 activeEvent 开启时,阻止冒泡与默认行为,基于事件路径解析 VTJ 元素,更新 selected 状态
- hover 状态:onMouseOver 仅在非选中元素上更新 hover,避免选中态闪烁
- 选择更新:setSelected 将模型映射为 DesignHelper(含 DOMRect、路径、索引),用于 UI 辅助线与面板联动
- 视图变更:onViewChange 触发 rect 与 lines 更新,保证 UI 与真实 DOM 一致
sequenceDiagram
participant Doc as "Document"
participant Designer as "Designer"
participant Engine as "Engine"
participant Hook as "useDesigner"
Doc->>Designer : "click 事件"
Designer->>Designer : "getHelper 解析 VTJ 元素"
Designer->>Designer : "setSelected 更新选中态"
Designer-->>Hook : "selected.value 变更"
Hook-->>Hook : "计算样式/位置"
Hook-->>Engine : "watch(engine.changed)"
Engine-->>Designer : "updateRect/updateLines"
键盘快捷键支持
- 快捷键注册:useHotkeys 在模拟器 ready 后绑定 hotkeys,支持撤销/重做、保存、预览、刷新、删除、复制/粘贴/剪切、方向键导航、全选、前后移动等
- 粘贴板与缓存:复制/剪切将 DSL 序列化写入剪贴板与 session 缓存;粘贴时读取并创建新节点或更新当前区块
- 事件传播控制:通过 engine.state.activeEvent 控制是否拦截原生事件
sequenceDiagram
participant User as "用户"
participant Hotkeys as "useHotkeys"
participant Engine as "Engine"
participant History as "HistoryModel"
participant Designer as "Designer"
User->>Hotkeys : "按下快捷键"
Hotkeys->>History : "backward/forward/load"
Hotkeys->>Engine : "保存/预览/刷新"
Hotkeys->>Designer : "setSelected/Copy/Cut/Paste"
Designer-->>User : "UI 状态更新"
历史记录系统与撤销重做
- 历史模型:HistoryModel 提供 add/update/remove/load/clear,维护 index 指针,支持 forward/backward
- 事件驱动:引擎监听 HISTORY_CHANGE/HISTORY_LOAD,将变更持久化至服务层(本地/内存/存储)
- 服务层:local/memory/storage 三套实现,分别对接远端 API、内存对象与浏览器存储
- 自动历史:engine.state.autoHistory 控制是否自动记录
classDiagram
class HistoryModel {
+number index
+HistoryItem[] items
+add(dsl, remark, silent)
+update(item, silent)
+remove(id, silent)
+forward(silent)
+backward(silent)
+load(id, silent)
+clear(silent)
}
class Engine {
+saveHistory(e)
+loadHistory(e)
+initHistory(block)
}
class LocalService
class MemoryService
class StorageService
Engine --> HistoryModel : "事件驱动"
Engine --> LocalService : "持久化"
Engine --> MemoryService : "持久化"
Engine --> StorageService : "持久化"
多选与批量编辑、全局状态同步
- 多选与路径:Designer 通过 getNodePath/getNodePathIndex 计算节点路径与索引,selected/dropping/hover 均携带 path,便于批量定位
- 全局状态:State 统一管理 outlineEnabled/activeEvent/autoApply/autoHistory/tour/dark/streaming 等开关,持久化到本地存储
- 状态联动:useDesigner 将 Designer 的 rect/lines 映射为 UI 可用的样式,受 outlineEnabled 控制
事件监听与处理指南
- 事件绑定:Designer 在构造时绑定 mouseover/scroll/resize/mouseleave/dragover/dragstart/dragend/drop/click 等事件
- 事件解绑:dispose/unbindEvents 在销毁时清理,避免内存泄漏
- 浏览器兼容:browser-patch 修正 addEventListener 默认 passive 行为,提升拖拽体验
自定义交互行为与扩展
- 自定义拖拽:可通过 vDraggable 指令扩展拖拽行为(handle/target/edge/delay 等),结合 Designer 的 setDraggingNode 实现拖拽节点的自定义逻辑
- 自定义快捷键:在 useHotkeys 中新增 bind,或通过 hotkeysTrigger 触发已有快捷键
- 自定义状态:通过 State 新增开关,或在 Designer 中扩展 DesignHelper 字段,配合 useDesigner 的计算映射
事件表达式与状态修复
- 状态属性修复:parser 的 state 工具对表达式中的 state 属性进行修复,确保事件表达式正确引用 state.xxx
- 自增/自减与复合赋值:对 prop++/--、++prop/--prop、prop += 等进行特殊处理,避免错误替换
工具提示系统增强
更新 所有项目组件现已添加工具提示功能,支持显示完整文本内容
- 工具提示集成:Field 组件支持 tooltipMessage 属性,自动计算工具提示位置和样式
- 多框架支持:Element Plus、Ant Design Vue、UniApp 等组件库均提供完整的 Tooltip 组件
- 动态配置:支持 placement、trigger、open 等参数的动态配置
- 文本截断:结合文本省略组件,实现长文本的完整显示
flowchart TD
Field["Field 组件"] --> TooltipConfig["工具提示配置"]
TooltipConfig --> Placement["位置计算<br/>placement: bottom-end"]
TooltipConfig --> Trigger["触发行为<br/>trigger: hover"]
TooltipConfig --> Style["样式应用<br/>is-tooltip-${position}"]
Style --> Render["渲染工具提示"]
Render --> FullText["显示完整文本"]
左侧面板宽度调整
更新 左侧面板宽度从30%增加到36%
- 品牌区域宽度:brand-region 宽度从 30% 调整为 36%
- 骨架布局适配:skeleton 布局系统自动适配新的宽度比例
- 响应式设计:左侧面板在收缩状态下仍保持 49px 宽度,确保最小可用空间
flowchart LR
Brand["品牌区域<br/>width: 36%"] --> Skeleton["骨架布局<br/>自动适配"]
Skeleton --> LeftPanel["左侧面板<br/>flex: 1"]
LeftPanel --> MainContent["主内容区域<br/>flex: 2"]
节点缓存清理机制
更新 表单提交时的节点缓存清理机制得到优化
- 缓存清理:表单提交后自动清理相关节点缓存,防止内存泄漏
- 历史记录清理:支持批量清理历史记录项,释放存储空间
- 内存管理:通过 MemoryService 提供的 removeHistoryItem 方法清理指定的历史项
sequenceDiagram
participant Form as "表单组件"
participant Cache as "节点缓存"
participant Memory as "MemoryService"
Form->>Cache : "提交表单"
Cache->>Memory : "清理历史项"
Memory->>Memory : "removeHistoryItem(fId, ids)"
Memory-->>Cache : "缓存清理完成"
依赖关系分析
- 设计器依赖引擎提供的 assets/simulator/current 等上下文
- 引擎依赖渲染服务进行文件/历史持久化
- 快捷键依赖模拟器 contentWindow 的 hotkeys 实例
- 状态由 State 统一管理并通过 storage 持久化
- 工具提示系统依赖各组件库的 Tooltip 组件实现
graph LR
Designer["Designer"] --> Engine["Engine"]
Engine --> Simulator["Simulator"]
Engine --> Services["渲染服务(local/memory/storage)"]
Hotkeys["useHotkeys"] --> Engine
State["State"] --> Engine
Parser["parser/state"] --> BlockModel["BlockModel"]
Tooltip["工具提示系统"] --> Field["Field 组件"]
Field --> Tooltip
性能考量
- DOM 查询与布局:updateRect/updateLines 使用延迟与 nextTick,避免频繁重排
- 事件节流/防抖:建议在高频事件(如 scroll/resize)中引入节流/防抖,减少渲染压力
- 内存泄漏防护:统一在 Designer.dispose/unbindEvents 中解绑事件,确保 iframe 卸载时清理
- 拖拽性能:vDraggable 支持 delay/edge/target 等参数,降低误触与无效拖拽
- 样式内联:capture 截图前进行样式内联,减少外部资源影响
- 工具提示优化:工具提示组件采用虚拟滚动和懒加载,避免大量文本渲染时的性能问题
- 缓存管理:定期清理过期缓存,防止内存占用持续增长
故障排查指南
- 事件不生效
- 检查 engine.state.activeEvent 是否开启
- 确认 Designer 事件绑定是否完成(ready 后)
- 拖拽不可放置
- 校验 allowDrop 的 parentIncludes/childIncludes 与目标类型
- 确认拖拽源与目标非父子递归关系
- 历史记录不同步
- 确认 HISTORY_CHANGE/HISTORY_LOAD 事件是否触发
- 检查服务层 saveHistoryItem/removeHistoryItem/saveHistory 的调用
- 粘贴失败
- 检查剪贴板内容与缓存是否有效
- 确认 isBlockSchema/isNode 判定分支
- 工具提示不显示
- 检查 tooltipMessage 属性配置
- 确认组件是否正确导入 Tooltip 组件
- 左侧面板宽度异常
- 检查 brand.scss 中的 width 配置
- 确认 skeleton 布局系统是否正常工作
- 缓存清理失败
- 检查 MemoryService 的 removeHistoryItem 方法调用
- 确认历史项 ID 格式是否正确
结论
设计器交互机制以"引擎-模拟器-设计器"为核心,通过事件驱动与状态模型实现拖拽、点击、快捷键、历史记录与撤销重做的完整闭环。借助钩子与指令,开发者可快速扩展自定义交互与性能优化策略,同时通过服务层与状态持久化保障数据一致性与可用性。
最新更新增强了工具提示系统、优化了左侧面板布局,并改进了节点缓存清理机制,进一步提升了用户体验和系统性能。
附录
- 交互事件清单
- 鼠标:mouseover/mouseleave/click
- 拖拽:dragstart/dragover/dragend/drop
- 窗口:scroll/resize/load
- 快捷键清单
- 撤销/重做、保存、预览、刷新、删除、复制/粘贴/剪切、方向键、全选、前后移动
- 工具提示组件清单
- Element Plus Tooltip
- Ant Design Vue Tooltip
- UniApp Tooltip
- 文本省略组件