document-events
本文回答:
CadEvents枚举里有 10 个基础文档事件DocumentCreating/Created/Opening/Opened/Closing/Closed/Saving/Saved/Modified/Switched,外加协作类(DocumentUploading/Uploaded/Downloading/Downloaded/SyncStatusChanged)和缓存类(DocumentCaching/Cached/Restoring/Restored/CacheCleared)。当前版本真正派发的只有DocumentCreating/Created/Modified/Switched;DocumentOpening/Opened/Closing/Closed/Saving/Saved及协作、缓存、分支、Patch、冲突类事件没有任何派发点(订阅永不触发)。阻止保存/关闭请在命令层用CommandStarting拦截QSAVE/SAVEAS/SAVESERVER/SAVELOCAL/CLOSE;"打开/保存之后"用CommandEnded。
一、基础事件清单
| 事件 | 说明 | 可取消 | 当前版本 |
|---|---|---|---|
DocumentCreating |
新建前(Engine.docs.add();打开文件时也会先建空文档) |
是 | ✓ 派发 |
DocumentCreated |
新建后(打开文件时此刻内容尚未载入) | 否 | ✓ 派发 |
DocumentOpening |
打开前 | 是 | ✗ 未派发 |
DocumentOpened |
打开后 | 否 | ✗ 未派发 |
DocumentClosing |
关闭前 | 是 | ✗ 未派发 |
DocumentClosed |
关闭后 | 否 | ✗ 未派发 |
DocumentSaving |
保存前 | 是 | ✗ 未派发 |
DocumentSaved |
保存后 | 否 | ✗ 未派发 |
DocumentModified |
文档从"未修改"变为"已修改"(DBMOD 0→1)时触发一次 |
否 | ✓ 派发 |
DocumentSwitched |
切换活动文档后(args {previousDocument, currentDocument}) |
否 | ✓ 派发 |
MCP 参考:vjcad/doc/event/event-types.md(清单);派发点以发布包中实际 emit(CadEvents.*) 为准。
二、最小用法
Engine.eventManager.on(CadEvents.DocumentCreated, (args) => {
console.log('新文档:', args.document.name); // 打开文件时内容此刻尚未载入
});
Engine.eventManager.on(CadEvents.DocumentSwitched, (args) => {
console.log('切换到:', args.currentDocument.name);
});
// "打开 / 保存之后":DocumentOpened / DocumentSaved 不派发,改看命令结束
// (用户取消也会触发 CommandEnded;success 只表示 main 没抛异常)
Engine.eventManager.on(CadEvents.CommandEnded, (args) => {
if (['OPEN', 'OPENFROMSERVER', 'OPENFROMLOCAL'].includes(args.commandName)) console.log('打开命令结束');
if (['QSAVE', 'SAVEAS', 'SAVESERVER', 'SAVELOCAL'].includes(args.commandName)) console.log('保存命令结束');
});
Engine.eventManager.on(CadEvents.DocumentModified, () => {
scheduleAutoSave(); // 仅 clean→dirty 时触发一次
});
MCP 参考:vjcad/example/event/05documentevents.js、vjcad/doc/event/event-usage.md(官方示例里的 DocumentOpened/DocumentSaved 订阅在当前版本不会触发)。
三、阻止保存空文档
DocumentSaving 不派发,在命令启动前拦截:
Engine.eventManager.on(CadEvents.CommandStarting, (args) => {
const saveCmds = ['QSAVE', 'SAVEAS', 'SAVESERVER', 'SAVELOCAL'];
if (saveCmds.includes(args.commandName) && Engine.getEntities(e => e.isAlive).length === 0) {
args.cancel = true;
alert('文档为空,无法保存');
}
});
四、关闭确认
DocumentClosing 不派发;内置 CLOSE 命令自己已对未保存文档(DBMOD === 1)弹确认框。要追加自定义检查,同样拦截命令(注意:文档标签上的 × 按钮走 DocumentTabs 自己的关闭逻辑,不经过 CLOSE 命令,拦不到):
Engine.eventManager.on(CadEvents.CommandStarting, (args) => {
if (args.commandName === 'CLOSE' && !myBusinessCheckPassed()) {
args.cancel = true;
writeMessage('<br/>业务校验未通过,禁止关闭');
}
});
MCP 参考:vjcad/doc/event/event-usage.md(原文用 DocumentClosing,当前版本不触发)。
五、协作 / 同步事件(✗ 均未派发)
| 事件 | 说明 | 可取消 |
|---|---|---|
DocumentUploading / DocumentUploaded |
上传到服务端 | 是 / 否 |
DocumentDownloading / DocumentDownloaded |
从服务端下载 | 是 / 否 |
DocumentSyncStatusChanged |
同步状态变化 | 否 |
以上只存在于枚举,当前版本没有派发点;需要同步状态时在 SAVESERVER 等命令的 CommandEnded 里自行查询。
MCP 参考:vjcad/doc/event/event-types.md。
六、本地缓存事件(✗ 均未派发)
| 事件 | 说明 | 可取消 |
|---|---|---|
DocumentCaching / DocumentCached |
保存到本地缓存 | 是 / 否 |
DocumentRestoring / DocumentRestored |
从本地缓存恢复 | 是 / 否 |
DocumentCacheCleared |
缓存清理后 | 否 |
MCP 参考:vjcad/doc/event/event-types.md。
七、分支 / Patch / 冲突事件(✗ 均未派发)
| 事件 | 说明 |
|---|---|
BranchCreating/Created/Switching/Switched/Merging/Merged/Deleting/Deleted |
分支生命周期 |
PatchCreating/Created/Applying/Applied/Reverting/Reverted |
Patch 生命周期 |
ConflictDetected/Resolving/Resolved/Skipped |
冲突 |
这组事件目前只是枚举占位,订阅不会触发;协作 UI 提示请基于版本 API 的返回值(见 version)。
MCP 参考:vjcad/doc/event/event-types.md、version。
反例
- 订阅
DocumentSaving / DocumentOpened / DocumentClosing等未派发事件,以为拦截/回调生效:永远不会触发。 - 用
CommandStarting拦截保存但不调用任何用户提示:用户以为没存上但其实是被静默阻止。 - 在打开命令的
CommandEnded里调耗时操作(5+ 秒):阻塞 UI,建议异步触发。 - 拿
DocumentModified统计"每次修改":它只在 clean→dirty 时触发一次,直到保存(或撤销回保存点)清除DBMOD前不再触发;缩放(setZoom/zoomIn/zoomOut)还会直接置DBMOD=1而不派发,之后的编辑也不再触发。逐次变更请监听EntityModified / EntityAdded / EntitiesErased / UndoStackChanged。
参考(官方文档 MCP)
- 文档:
vjcad/doc/event/event-types.md、vjcad/doc/event/event-usage.md - 示例:
vjcad/example/event/05documentevents.js