onload-lifecycle
本文回答:
await cadView.onLoad()是异步初始化的同步点;它在 PixiJS 画布创建、WASM 模块加载、字体加载、插件系统初始化、URL 参数处理全部就绪后才 resolve,之前禁止使用Engine。
一、onLoad() 在等什么
引自
vjcad/doc/guide/quick-start.md:
onLoad()返回一个 Promise,在以下初始化完成后 resolve:
- PixiJS 画布创建
- WASM 模块加载
- 字体加载
- 插件系统初始化
- URL 参数处理(自动打开图纸、激活侧边栏面板等)
支持的 URL 参数包括
vcad_mapid(图纸ID)、vcad_panel(激活面板)等。
二、最小用法
const { MainView, initCadContainer, Engine, LineEnt, message } = vjcad;
const cadView = new MainView({
appname: '唯杰CAD',
version: 'v1.0.0',
serviceUrl: env.serviceUrl,
accessToken: env.accessToken,
});
initCadContainer('map', cadView);
// 必须 await
await cadView.onLoad();
// 此时 Engine 才可用
message.info('初始化完成,开始绑定事件和创建实体...');
const line = new LineEnt([0, 0], [100, 100]);
line.setDefaults();
Engine.addEntities(line);
Engine.zoomExtents();
MCP 参考:vjcad/example/basic/02onload.js。
三、为什么必须 await
onLoad 前访问 Engine.* 的实际行为(并非"全是 undefined"):
| getter | onLoad 前实际返回 | 风险 |
|---|---|---|
Engine.pcanvas |
null(view?.pcanvas ?? null) |
Engine.addEntities 内部 if (!pcanvas) return ——静默丢弃不抛错,实体凭空消失 |
Engine.editor / Engine.view / Engine.trans |
undefined / null |
访问属性抛 TypeError |
Engine.currentDoc / currentSpace / undoManager |
懒创建的孤儿 CadDocument(activeDocument getter 自动 new),不是 undefined |
最阴险:调用"能跑"但写进的是脱离视图的文档,onLoad 后真文档替换,数据丢失 |
Engine.eventManager |
真单例(CadEventManager.getInstance(),与 onLoad 后同一个) |
无——onLoad 前注册监听有效(旧文档"不会注册到真正单例"的说法有误;resetInstance 是 @internal 仅供测试,MainView 初始化不调它) |
- WASM 模块还没加载就调
Engine.editor.executerWithOp('LINE')会失败。 - 字体没加载完就创建
TextEnt,会显示错位或空文字。 - 插件系统未就绪时调用
PluginManager.getInstance().loadByName(...)会丢调用。
四、URL 参数自动打开图纸
onLoad 内部会处理 URL 上的 vcad_mapid / vcad_panel / vcad_version / vcad_branch / vcad_patch / vcad_readonly / vcad_tile / vcad_workspace 等(具体支持详见 vjcad/doc/file/file-operations.md 的 "URL 参数自动打开图纸")。如果你只需要查看图纸,配合 viewer-mode 即可省掉自己的 DrawingManagerService.openDrawing 调用。
五、销毁与重建(cadView.destroy())
vjcad 按"一次一个视图"设计:文档、撤销、命令表、事件管理器都是 Engine 上的全局静态状态。弹框 / 路由反复打开 CAD 时,关闭前必须 await cadView.destroy(),再次打开重新 new MainView + initCadContainer + await onLoad():
// 关闭
await cadView.destroy(); // 依次:卸载全部插件 → 释放 Engine.docs 中全部文档 → 销毁画布 → 清理 Engine 静态缓存 → cad-view 移出 DOM
cadView = null; // 等价写法:await Engine.destroyViewer();
// 再次打开
cadView = new MainView({ /* ... */ });
initCadContainer(hostElement, cadView); // 也可直接传容器元素
await cadView.onLoad();
不 destroy 就重建:Engine 的静态缓存仍指向已卸载的旧画布,第二次打开"初始化成功但不显示图纸"。同一页面不要同时保留多个 MainView(见 trouble/init-pitfalls §7)。
MCP 参考:vjcad/example/basic/07destroyviewer.js。
反例
cadView.onLoad()没await,紧接着调Engine.addEntities(...)—— 不报错但实体根本没进图(pcanvas为 null 时静默 return),比报错更难排查。在—— 此说法有误:onLoad之前监听eventManager事件不会注册到真正的单例上eventManagergetter 就是CadEventManager.getInstance()全局单例,onLoad 前注册有效。- 写成
await initCadContainer(...).onLoad():initCadContainer返回的是HTMLElement(容器元素,同步返回非 Promise),上面没有onLoad;onLoad是MainView实例方法。
参考(官方文档 MCP)
- 文档:
vjcad/doc/guide/quick-start.md、vjcad/doc/file/file-operations.md - 示例:
vjcad/example/basic/02onload.js、vjcad/example/basic/01init.js