Appearance
<fmb-load-card>
渐进加载卡。大装配不是「加载中 → 完成」两态,而是骨架 → 几何分块 → 边线 → 收敛四段流入的,而且骨架就绪后模型已经可以转动了。这张卡的职责就是诚实地说出这件事,而不是转一个圈假装什么都没发生。
组件是纯受控的:它不订阅引擎事件,只按 stage / progress 两个属性渲染。把引擎事件翻成这两个数是宿主的事——下面给了完整接法。
最小用法
html
<div class="viewport" style="position: relative">
<canvas id="canvas"></canvas>
<fmb-load-card id="load" hidden></fmb-load-card>
</div>ts
import { FmbLoadCard } from "@modelcubes/viewer-ui";
void [FmbLoadCard];
const card = document.getElementById("load") as FmbLoadCard;
card.stage = 1;
card.progress = 0.4;
card.hidden = false;属性
| 名称 | 类型 | property / attribute | 默认值 | 说明 |
|---|---|---|---|---|
stage | number | property + attribute | 0 | 当前阶段序号 0..3,对应 LOAD_STAGES 四项 |
progress | number | property + attribute | 0 | 总进度 0..1 |
label | string | property + attribute | "" | 模型名;plain 档不显示 |
vocabulary | "plain" | "engineering" | property + attribute | "plain" | plain 只给一条进度 + 一句可交互提示;engineering 列出四阶段清单 |
center | boolean | property + attribute(反射) | false | 居中显示(首屏加载)而不是贴在工具条上方 |
LOAD_STAGES 是导出的常量,四项分别是「骨架 / 几何分块 / 边线 / 收敛」及其副标题,需要自定义展示时可直接读它。
事件
无。
把引擎事件翻成 stage / progress
这是 @fmb/viewer 的真实接法,要点都在注释里:
ts
/** 各阶段的进度权重:骨架很快,几何最久,边线其次,收敛收尾。 */
const STAGE_FLOOR = [0, 0.12, 0.88, 1] as const;
viewer.on("model-loading", () => {
card.stage = 0;
card.progress = 0.04;
card.hidden = false;
});
viewer.on("model-skeleton-ready", () => {
card.stage = 1; // ★ 此刻模型已可交互
card.progress = STAGE_FLOOR[1];
});
viewer.on("model-geom-progress", ({ ready, total }) => {
const frac = total > 0 ? Math.min(1, ready / total) : 0;
card.stage = 1;
card.progress = STAGE_FLOOR[1] + (STAGE_FLOOR[2] - STAGE_FLOOR[1]) * frac;
});
viewer.on("model-loaded", () => {
card.stage = 2;
card.progress = STAGE_FLOOR[2];
});
viewer.on("model-edges-ready", () => {
card.stage = 3;
card.progress = 1;
setTimeout(() => (card.hidden = true), 260); // 补满 100% 再收,让「完成」被看见
});两个必须处理的坑
一、不要在 load() 的 Promise resolve 时收卡。 它在骨架就绪时就 resolve,几何与边线此后仍在后台流入——在那里收卡,进度会永远停在最后一个到达的事件上(实测卡在 96%)。收尾信号是 model-edges-ready。
二、必须挂超时兜底。 在两种情况下 model-loaded / model-edges-ready 不保证到达:模型里有孤儿 mesh(没有节点引用、永不被请求),或相机是固定的局部视锥(离屏 mesh 永不被请求)。没有兜底,进度卡会永远挂在画面上。@fmb/viewer 用的是骨架后 20s、model-loaded 后 4s 两档超时,谁先到谁收卡。
行为细节
- 纯受控:组件自身不碰
viewer,也不订阅任何事件——所有状态由宿主推入。 hidden是标准 HTML 属性,:host([hidden]) { display: none }已在组件内置,直接card.hidden = true即可。- 两种文案档:
plain面向分享场景的最终用户(一条进度条 + 「已经可以转动了」这类提示);engineering面向工程审阅(展开四阶段清单,标出已完成 / 进行中)。
可定制点
卡片底色 / 描边 / 阴影走 --fmb-surface、--fmb-border、--fmb-shadow-lg;进度条填充走 --fmb-accent;文字走 --fmb-fg-1 / --fmb-fg-2。全表见主题定制。