在宿主框架中使用 ElfUI
ElfUI 组件是标准 Custom Element。原生 DOM、React、Vue、Svelte、Angular 或其他宿主应通过 property、attribute、CustomEvent、slot、CSS custom property、::part()、焦点方法与原生表单行为集成,不需要 ElfUI 专用 renderer adapter。
共享宿主契约
| 关注点 | 契约 |
|---|---|
| 基础类型 attribute | 字符串按已声明 prop options 转换。 |
| object/array/function | 使用 property 赋值;ElfUI 保留宿主拥有的引用身份。 |
| 更新 | 替换已声明 property 会触发响应式更新,不会替换 Custom Element 节点。 |
| 事件 | 监听标准 CustomEvent;payload 位于 detail。 |
| Shadow DOM 传播 | 只有需要跨边界的事件才开启 bubbles / composed。 |
| 子内容 | 通过默认 slot 或带 slot attribute 的 named slot 传入 Light DOM。 |
| 样式 | 使用 CSS custom property 与组件公开的 ::part()。 |
| 焦点与方法 | 在元素实例上调用 defineExpose() 暴露的方法。 |
| 表单 | form-associated 组件通过原生 Custom Element internals 参与表单。 |
| 卸载 | 移除 host 会释放组件拥有的 effect 与外部资源。 |
已声明 props 的 property accessor 会在元素构造后、连接前就存在,使宿主能够选择 property 赋值并保留 object、array、function 的引用身份。通用做法是拿到 DOM 节点后直接赋值:
const element = document.querySelector("elf-data-grid")!;
element.rows = rows;
element.formatter = formatter;
element.addEventListener("row-select", (event) => {
const row = (event as CustomEvent<Row>).detail;
});不同宿主的模板语法不同,但底层契约相同。如果宿主对未知自定义事件有额外规则,addEventListener() 始终是平台级兜底方式。
注册与多 App
即使 ElfUI App 的配置、插件、指令和依赖注入彼此隔离,Custom Element 注册仍是页面全局的。应用与组件库应使用稳定且唯一的 tag 前缀。相同构造器重复注册是幂等的;不同构造器占用同一 tag 会抛出 ELF_CUSTOM_ELEMENT_CONFLICT。
如果启动顺序由宿主控制,可用 register: false 定义组件,再在客户端入口调用 registerComponents()。不要让两份被打包的 ElfUI runtime 用同一个 tag 注册不同实现。
SSR 宿主
ElfUI 包与编译后的组件模块可以在没有浏览器全局对象的环境中安全 import,服务端会得到只含元数据的占位构造器。DOM 创建、显式注册和 createApp().mount() 仍只能在客户端执行。
ElfUI 当前支持服务端输出 Custom Element host 外壳,不支持服务端渲染组件 Shadow DOM,也不 hydration 组件内部 DOM。SSR 框架应把 ElfUI 组件视为 client-only island,并确保组件模块在浏览器端重新求值。
已测试兼容基线
发布门禁当前会在真实浏览器中,让 native DOM、React 19.2.7、Vue 3.5.40、Svelte 5.56.6、Angular 22.0.7 运行相同的 property/update/remount、attribute/event、slot/style/focus/form、keyed list/资源清理契约,并验证多个隔离 App 与多份 runtime。
这是已测试基线,不代表任意宿主版本或 wrapper 库都天然兼容。升级 ElfUI 或宿主框架时,应保留一组由应用自己维护的小型集成测试。
