
Univer 与 Vue 3 集成实战univerjs/ui-adapter-vue3 适配器插件深度解析【免费下载链接】univerUniver is a full-stack framework for creating and editing spreadsheets / word processor / presentation on both web and server.项目地址: https://gitcode.com/GitHub_Trending/un/univeruniverjs/ui-adapter-vue3是 Univer 官方提供的 Vue 3 适配器插件它让基于 React 构建的 Univer UI 层能够直接注册、渲染 Vue 3 组件从而让 Vue 3 技术栈的团队可以复用既有组件生态来定制电子表格、文档与演示文稿的界面。本文将以 packages/ui-adapter-vue3/README.md 为主线结合插件源码、底层ComponentManager机制与仓库内真实示例从安装、注册到桥接原理逐一展开读完即可在自己的 Univer 实例中接入 Vue 3 自定义组件。包概览一个纯桥接层无 UI、无样式、无本地化负担官方文档首先以一张表格给出了包的核心信息PackageUMD globalCSSLocalesFacade entryuniverjs/ui-adapter-vue3UniverUiAdapterVue3NoNoNo从这张表可以读出它的定位这是一个纯粹的适配桥接包——不提供 UMD 之外的任何 UI 资产不携带 CSS样式由 Vue 组件自身负责不包含多语言文案也没有独立的 Facade 入口。它唯一要做的事情就是把 Univer UI 服务与 Vue 3 运行时的组件渲染能力连接起来。这一点在 packages/ui-adapter-vue3/package.json 中可以得到印证该包的peerDependencies只有一项vue: 3.0.0运行时依赖仅为univerjs/core与univerjs/ui均为workspace:*keywords为univer / ui / vue3 / adapter / plugin版本号为1.0.0-beta.2采用 Apache-2.0 许可。安装与所有 univerjs 包保持同一版本官方文档给出的安装方式非常直接pnpm add univerjs/ui-adapter-vue3 # or npm install univerjs/ui-adapter-vue3文档随后强调了一条关键约束Keep alluniverjs/*packages on the same version.由于 Univer 的插件体系通过univerjs/core的依赖注入DI与univerjs/ui的ComponentManager协作各包版本不一致极易导致类型或运行时的不兼容。建议在 monorepo 中统一使用workspace:*协议仓库内 examples/package.json 即以univerjs/ui-adapter-vue3: workspace:*方式引入或在独立项目里固定到同一发布版本。快速上手注册插件即可启用 Vue 3 组件能力官方文档给出了最小可用用法import { UniverVue3AdapterPlugin } from univerjs/ui-adapter-vue3; univer.registerPlugin(UniverVue3AdapterPlugin);注意这里的registerPlugin是 Univer 实例Univer类的方法因此更完整的场景通常是在new Univer({...})之后与其他基础插件一起批量注册。仓库的示例 examples/src/sheets/main.ts 展示了这一点import { UniverVue3AdapterPlugin } from univerjs/ui-adapter-vue3; univer.registerPlugins([ // ...基础插件 [UniverUIPlugin, { container: app, ribbonType: grid }], [UniverWebComponentAdapterPlugin], [UniverVue3AdapterPlugin], [UniverDocsUIPlugin], // ... ]);同样的用法也出现在 Web Component 示例 examples/src/sheets-webcomponent/main.tsx 中univer.registerPlugin(UniverWebComponentAdapterPlugin); univer.registerPlugin(UniverVue3AdapterPlugin);。可以看到Vue 3 适配器与 Web Component 适配器可以共存它们各自为不同的组件框架注册了渲染通道。工作原理从 Plugin 到 ComponentManager 的桥接链路只看两行注册代码很难理解这个插件做了什么。深入 packages/ui-adapter-vue3/src/plugin.ts 源码可以完整还原它的运行机制。插件声明与配置注入UniverVue3AdapterPlugin继承自univerjs/core的Plugin基类并声明了三个静态元数据export class UniverVue3AdapterPlugin extends Plugin { static override pluginName UNIVER_UI_ADAPTER_VUE3_PLUGIN; static override packageName pkg.name; static override version pkg.version; }构造函数接收可选的PartialIUniverVue3AdapterConfig配置将其与defaultPluginConfig合并后写入IConfigService键名为UI_ADAPTER_VUE3_PLUGIN_CONFIG_KEY。在 packages/ui-adapter-vue3/src/config/config.ts 中可以查到export const UI_ADAPTER_VUE3_PLUGIN_CONFIG_KEY ui-adapter-vue3.config; export const configSymbol Symbol(UI_ADAPTER_VUE3_PLUGIN_CONFIG_KEY); export interface IUniverVue3AdapterConfig {} export const defaultPluginConfig: IUniverVue3AdapterConfig {};当前版本中IUniverVue3AdapterConfig是一个空接口、defaultPluginConfig为空对象说明该适配器目前无需额外配置项即可工作配置通道为后续能力扩展预留了空间。onStarting向 ComponentManager 注册 vue3 框架处理器插件生命周期中的核心逻辑在onStarting()中完成override onStarting(): void { const { createElement, useEffect, useRef } this._componentManager.reactUtils; this._componentManager.setHandler(vue3, (component: IComponent[component]) { return (props: Recordstring, unknown) createElement(VueComponentWrapper, { component, props: Object.keys(props).reduceRecordstring, unknown((acc, key) { if (key ! key) { acc[key] props[key]; } return acc; }, {}), reactUtils: { createElement, useEffect, useRef }, }); }); }要理解这段代码需要先了解ComponentManager位于 packages/ui/src/common/component-manager.ts。Univer UI 的组件注册中心ComponentManager以框架名 组件名组织所有 UI 组件register(name, component, options?)注册组件options.framework默认是reactsetHandler(framework, handler)为某个框架注册取组件时的包装处理器get(name)取出组件时先用对应框架的 handler 包装再返回内置的reactUtils字段直接暴露了 React 的createElement、useEffect、useRef三个 API供适配器复用。值得特别注意的是ComponentManager.register中的守卫逻辑if (framework vue3 !this._handler.vue3) { throw new Error([ComponentManager] Vue3 support is no longer built-in since v0.9.0, please install univerjs/ui-adapter-vue3 plugin.); }也就是说自 Univer v0.9.0 起Vue 3 支持不再是内置能力。如果用户不安装univerjs/ui-adapter-vue3就试图以framework: vue3注册组件ComponentManager会直接抛出引导性错误提示安装本插件。对应的单元测试位于 packages/ui/src/common/tests/component-manager.spec.tsit(should throw when registering vue3 without handler, () { const manager new ComponentManager(logService); expect(() manager.register(vue-comp, () null, { framework: vue3 })).toThrow( [ComponentManager] Vue3 support is no longer built-in since v0.9.0, please install univerjs/ui-adapter-vue3 plugin. ); });UniverVue3AdapterPlugin所做的正是通过setHandler(vue3, ...)补上这个缺失的处理器让vue3框架的组件在get()时被正确包装。VueComponentWrapperReact 容器内的 Vue 渲染桥处理器返回的是一个 React 组件工厂最终渲染的是VueComponentWrapperexport function VueComponentWrapper(options: { component: ReturnTypetypeof defineComponent; props: Recordstring, unknown; reactUtils: typeof ComponentManager.prototype.reactUtils; }) { const { component, props, reactUtils } options; const { createElement, useEffect, useRef } reactUtils; const domRef useRefHTMLDivElement(null); useEffect(() { if (!domRef.current) return; const vnode h(component, props); render(vnode, domRef.current); return () { domRef.current render(null, domRef.current); }; }, [props]); return createElement(div, { ref: domRef }); }这个桥接组件体现了非常典型的跨框架渲染模式外层是 React 组件VueComponentWrapper使用 React 的useRef持有容器div的 DOM 引用useEffect在挂载后执行渲染清理时卸载。内层用 Vue 运行时渲染通过 Vue 的h(component, props)创建 Vue 虚拟节点再调用render(vnode, domRef.current)将 Vue 组件渲染到 React 管理的容器 DOM 中。生命周期对齐useEffect的 cleanup 函数调用render(null, domRef.current)把 Vue 组件从容器中卸载避免跨框架组件造成内存泄漏。props 透传处理器在组装props时过滤掉了 React 保留的key字段其余属性全部透传给 Vue 组件。由此可以总结出该适配器的定位它不改变 Univer 自身基于 React 的渲染管线而是在组件出口处为 Vue 3 组件开了一个侧门——Univer 内部依然用 React 渲染容器容器内部再挂载 Vue 组件树。这正是adapter一词的含义。在 Univer UI 中注册与使用 Vue 3 组件插件注册完成后即可在任意需要自定义 UI 组件的位置使用 Vue 3 组件。注册入口有两条路径方式一Facade APIuniverAPI.registerComponent在 packages/ui/src/facade/f-univer.ts 中FUniverUIMixin.registerComponent的实现为override registerComponent(name: string, component: any, options?: IComponentOptions): IDisposable { const componentManager this._injector.get(ComponentManager); return this.disposeWithMe(componentManager.register(name, component, options)); }可见 Facade 层最终委托给ComponentManager.register因此只需传入options: { framework: vue3 }即可将组件注册为 Vue 3 组件。仓库示例 examples/src/sheets/custom/custom-float-dom/float-dom.ts 中展示了常规React组件的注册与使用方式Vue 3 组件仅需在 options 中声明框架即可univerAPI.registerComponent(FloatDomContentBoxProbe, FloatDomContentBoxProbe); const worksheet univerAPI.getActiveWorkbook()!.getActiveSheet(); const disposable worksheet.addFloatDomToPosition({ componentKey: FloatDomContentBoxProbe, initPosition: { startX: 120, startY: 100, endX: 600, endY: 420 }, data: { border: false }, allowTransform: true, eventPassThrough: true, }, FLOAT_DOM_CONTENT_BOX_FIXTURE_ID);addFloatDomToRange/addFloatDomToPosition这类 API 允许在画布范围内放置一个浮层 DOM组件配合registerComponent即可实现加载提示、区域弹层等自定义浮层——这些位置都可以无缝换成 Vue 3 组件。方式二直接注入ComponentManager注册在自定义插件中通过依赖注入获取ComponentManager然后调用componentManager.register(MyVuePanel, MyVueComponent, { framework: vue3 });注册后的组件会被get()时经过vue3handler 包装即上面提到的VueComponentWrapper流程从而以 React 容器 Vue 内容的形态被 Univer UI 正常消费。适用范围包括但不限于自定义菜单图标、按钮、弹窗、抽屉等 UI 部件区域浮层Range Popup与浮层 DOMFloat DOM内容工具栏 / 状态栏等 UI Part 的自定义替换。仓库示例 examples/src/sheets/custom/custom-range-popup/custom-range-popup.tsx 展示了 24 种RectPopupDirection方向下的浮层组件注册与range.attachRangePopup({ componentKey, direction })的挂载流程可作为设计 Vue 3 浮层组件的参考模板。与 Web Component 适配器的异同仓库中还有一个姊妹包univerjs/ui-adapter-web-componentpackages/ui-adapter-web-component/src/plugin.ts两者采用完全相同的架构都通过ComponentManager.setHandler注册自己的框架名vue3/web-component都用 React 的reactUtils创建包装组件都通过各自的运行时Vue 的h/render、浏览器的customElements把外部框架组件挂载进 Univer 的 React 渲染树。区别在于Vue 3 适配器用 Vue 运行时挂载组件组件可被 Vue 响应式系统管理能天然享受 Vue 3 的 Composition API 与响应式状态Web Component 适配器把组件注册为自定义元素custom element适合与任何基于浏览器标准的技术栈互通。如果团队同时使用 Web Component 和 Vue 3两个适配器插件可以同时注册如示例 examples/src/sheets/main.ts 所示互不干扰。使用注意事项结合源码与仓库实践使用该适配器时有几点需要留意必须安装插件否则注册即报错自 v0.9.0 起 Vue 3 支持移出内核。未注册UniverVue3AdapterPlugin时任何framework: vue3的组件注册都会抛出引导性异常提示安装本插件见 component-manager.ts 第 46-48 行。peer 依赖要求 Vue 3.0.0包内部直接使用h与render因此宿主项目必须安装 Vue 3 运行时vue: 3.0.0。版本对齐所有univerjs/*包应保持同一版本避免 DI 符号或类型不匹配。props 的 React 保留字段会被过滤key不会被透传给 Vue 组件其余 props 原样传递。当前无配置项IUniverVue3AdapterConfig为空接口直接registerPlugin(UniverVue3AdapterPlugin)即可无需传参。小结univerjs/ui-adapter-vue3用不到 70 行核心代码完成了一件关键的事让 Vue 3 组件以标准化的方式进入 Univer 的 React 渲染体系。它通过ComponentManager的框架处理器机制注册vue3通道再以VueComponentWrapper在 React 容器中挂载 Vue 组件实现了两种视图层的平滑共存。对于希望复用 Vue 3 组件生态来扩展 Univer 界面浮层、弹窗、自定义 UI 部件的开发者而言这个轻量插件就是官方推荐的官方入口。深入阅读插件源码packages/ui-adapter-vue3/src/plugin.ts配置与导出packages/ui-adapter-vue3/src/config/config.ts、packages/ui-adapter-vue3/src/index.ts底层组件注册中心packages/ui/src/common/component-manager.ts 及其测试 packages/ui/src/common/tests/component-manager.spec.ts仓库集成示例examples/src/sheets/main.ts、examples/src/sheets-webcomponent/main.tsxFacade 注册入口packages/ui/src/facade/f-univer.ts【免费下载链接】univerUniver is a full-stack framework for creating and editing spreadsheets / word processor / presentation on both web and server.项目地址: https://gitcode.com/GitHub_Trending/un/univer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考