lowcode-engine CommonUI:低代码引擎插件 UI 组件库完整指南
2026/9/14 7:12:19 网站建设 项目流程

lowcode-engine CommonUI:低代码引擎插件 UI 组件库完整指南

【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine

导读

CommonUI 是 lowcode-engine 面向插件开发者提供的统一 UI 组件库,位于插件上下文的ctx.commonUI中。本文以官方文档 commonUI.md 为骨架,结合仓库源码(packages/types/src/shell/api/commonUI.tspackages/shell/src/api/commonUI.tsxpackages/utils/src/context-menu.tsx等)与类型定义,系统讲解 CommonUI 的设计动机、组件清单、核心类型、ContextMenu 的两种使用方式与底层实现原理,帮助你在不同项目和主题切换中写出保持视觉一致、可复用的插件界面。

CommonUI 是什么

官方文档给出的定位非常明确:

CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开发的插件,可以保证在不同项目和主题切换中能够保持一致性和兼容性。

也就是说,插件作者不应该直接在自己的代码里引入任意第三方 UI 库,而应统一从ctx.commonUI获取组件。这样,当引擎更换默认主题、升级底层组件库(当前为@alifd/next)时,已开发的插件 UI 依然保持兼容。

从源码结构看,这一设计通过两层抽象实现:

  • 类型契约层IPublicApiCommonUI接口定义了 CommonUI 暴露的全部 API,见 packages/types/src/shell/api/commonUI.ts,插件只需依赖类型即可编译;
  • 实现注入层:引擎在启动时实例化CommonUI并挂载到插件上下文,见 packages/engine/src/engine-core.ts(const commonUI = new CommonUI(editor); ... context.commonUI = commonUI;),真正实现位于 packages/shell/src/api/commonUI.tsx。

在插件中,通过ctx.commonUI即可访问全部组件。以下是 packages/types/src/shell/model/plugin-context.ts 中插件上下文的 CommonUI 挂载示意(引擎侧注入点见上述 engine-core.ts):

// 插件内部使用方式 const { Button, Dialog, Tip } = ctx.commonUI; // 渲染一个按钮 <Button type="primary" onClick={handler}>确定</Button>

组件清单:融合引擎自研组件与主题组件库

CommonUI 提供的组件分为两类:

  1. 引擎自研组件TipHelpTipTitleContextMenu,本文下一节重点展开;
  2. 主题组件库组件:直接透传@alifd/next(Fusion Design 组件库)的 27 个常用组件,见 packages/shell/src/api/commonUI.tsx 与类型定义 packages/types/src/shell/api/commonUI.ts。

完整清单如下:

类别组件
引擎自研Tip、HelpTip、Title、ContextMenu
主题组件库Balloon、Breadcrumb、Button、Card、Checkbox、DatePicker、Dialog、Dropdown、Form、Icon、Input、Loading、Message、Overlay、Pagination、Radio、Search、Select、SplitButton、Step、Switch、Tab、Table、Tree、TreeSelect、Upload、Divider

主题组件库组件的详细 API 与官方文档一致,可参考对应组件的 Fusion Design 文档(例如 Balloon、Breadcrumb、Button、Card、Checkbox、DatePicker、Dialog、Dropdown、Form、Icon、Input、Loading、Message、Overlay、Pagination、Radio、Search、Select、SplitButton、Step、Switch、Tab、Table、Tree、TreeSelect、Upload、Divider)。引擎默认主题支持的 Icon 列表见引擎默认主题文档。

使用注意:虽然ctx.commonUI也透传了Icon组件,但引擎源码中很多自研 UI 组件(如 HelpTip 的 help 图标)直接使用了@alifd/nextIcon(见 packages/editor-core/src/widgets/tip/help-tips.tsx),因此插件中直接用ctx.commonUI.Icon即可保持一致。

引擎自研组件详解

Tip:轻量提示组件

Tip 用于在元素附近展示一段提示内容。文档给出的参数如下:

参数说明类型默认值
classNameclassNamestring(optional)
childrentip 的内容IPublicTypeI18nData \| ReactNode
directiontip 的方向'top' \| 'bottom' \| 'left' \| 'right'

对应类型定义为 packages/types/src/shell/type/tip-config.ts 中的IPublicTypeTipConfig,其中IPublicTypeI18nData{ zh_CN?: string; en_US?: string; [key: string]: string }形式的国际化数据结构。

从源码实现看,Tip 并不是直接渲染一段 DOM,而是一个"声明式注册器":挂载时通过postTip将自身配置投递到全局 Tip 容器(tip-container),由容器决定具体渲染位置与气泡样式,见 packages/editor-core/src/widgets/tip/tip.tsx。这意味着 Tip 的展示机制与引擎的画布悬浮提示(如组件 hover 时的说明)共用同一套体系,插件中用它就能获得一致的交互体验。

import { IPublicTypeTipConfig } from '@alilc/lowcode-types'; const tipConfig: IPublicTypeTipConfig = { direction: 'top', children: '这是一个提示', }; // 在插件 JSX 中使用 <div> <Tip direction="top">鼠标悬浮查看帮助</Tip> </div>

HelpTip:带问号图标的帮助提示

HelpTip 在文案前渲染一个 help 图标,悬浮时展示帮助内容。文档参数如下:

参数说明类型默认值
help描述IPublicTypeHelpTipConfig
direction方向IPublicTypeTipConfig['direction']'top'
size大小IconProps['size']'small'

其中IPublicTypeHelpTipConfig = string \| { url?: string; content?: string \| ReactElement },定义见 packages/types/src/shell/type/widget-base-config.ts。

源码实现 packages/editor-core/src/widgets/tip/help-tips.tsx 展示了三种用法:

  1. help为字符串:渲染 help 图标 + Tip 展示该字符串;
  2. help{ url, content }:图标变为指向url的外链(新窗口打开),Tip 展示content
  3. help{ content }(无 url):仅渲染 help 图标 + Tip 展示content
// 纯文字帮助 <HelpTip help="用于控制组件层级" /> // 带文档链接的帮助 <HelpTip help={{ url: 'https://example.com/docs', content: '查看完整文档' }} direction="right" size="small" />

Title:标题组件

Title 用于渲染标题,支持国际化内容、图标与自定义点击行为。文档参数如下:

参数说明类型默认值
title标题内容IPublicTypeTitleContent
classNameclassNamestring(optional)
onClick点击事件() => void(optional)

IPublicTypeTitleContent是一个联合类型:string | IPublicTypeI18nData | ReactElement | ReactNode | IPublicTypeTitleConfig,定义见 packages/types/src/shell/type/title-content.ts。其中IPublicTypeTitleConfig可携带label(文本)、icon(图标)、tip(提示)等字段。

源码实现 packages/editor-core/src/widgets/title/index.tsx 提供了几个值得关注的增强能力:

  • 关键字高亮:配合matchkeywords属性(见类型定义 packages/types/src/shell/api/commonUI.ts),可将标题按关键字分割并以红色高亮(splitLabelByKeywords,见 title/index.tsx),适合做搜索命中展示;
  • 图标渲染title.icon会通过createIcon渲染;
  • 外链跳转:点击带docUrl/url的标题会打开新窗口并阻止事件冒泡(防止误触折叠面板等行操作)。
// 简单文本标题 <Title title="组件属性" /> // 国际化标题 + 关键字高亮 <Title title={{ zh_CN: '自定义页面布局', en_US: 'Custom Page Layout' }} match keywords="页面" /> // 带图标与点击回调 <Title title={{ label: '刷新', icon: 'refresh' }} onClick={() => console.log('title clicked')} />

ContextMenu:上下文菜单

ContextMenu 用于在插件 UI 中提供右键菜单能力,是插件面板内交互的核心组件。文档给出的组件参数如下:

参数说明类型默认值
menus定义上下文菜单的动作数组IPublicTypeContextMenuAction[]
children组件的子元素React.ReactElement[]
IPublicTypeContextMenuAction 接口

menus中每一项都遵循IPublicTypeContextMenuAction接口,完整定义见 packages/types/src/shell/type/context-menu.ts:

参数说明类型默认值
name动作的唯一标识符string
title显示的标题,可以是字符串或国际化数据string \| IPublicTypeI18nData(optional)
type菜单项类型IPublicEnumContextMenuType(optional)IPublicEnumContextMenuType.MENU_ITEM
action点击时执行的动作(nodes: IPublicModelNode[]) => void(optional)
items子菜单项或生成子节点的函数,仅支持两级Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => ...)[](optional)
condition显示条件函数(nodes: IPublicModelNode[]) => boolean(optional)
disabled禁用条件函数(nodes: IPublicModelNode[]) => boolean(optional)
help帮助提示IPublicTypeHelpTipConfig(optional)

type字段的取值由枚举 packages/types/src/shell/enum/context-menu.ts 定义:

  • SEPARATOR = 'separator':分隔线;
  • MENU_ITEM = 'menuItem':普通菜单项(默认);
  • NODE_TREE = 'nodeTree':节点树(渲染当前选中的节点层级树,见 packages/engine/src/inner-plugins/default-context-menu.ts 中引擎默认右键菜单的用法)。

注意:actionconditiondisabled的回调都会收到当前选中的节点数组nodes,因此在画布相关插件中可以根据当前选中节点动态决定菜单项行为。

用法一:包裹子元素的组件模式

将 ContextMenu 包裹在任意元素外层,右键该元素即弹出菜单。官方示例:

const App = () => { const menuItems: IPublicTypeContextMenuAction[] = [ { name: 'a', title: '选项 1', action: () => console.log('选项 1 被点击'), }, { name: 'b', title: '选项 2', action: () => console.log('选项 2 被点击'), }, ]; const ContextMenu = ctx.commonUI.ContextMenu; return ( <div> <ContextMenu menus={menuItems}> <div>右键点击这里</div> </ContextMenu> </div> ); }; export default App;
用法二:create 命令式调用

在某些场景(例如把菜单挂在事件处理函数中)需要使用命令式 API。官方示例:

const App = () => { const menuItems: IPublicTypeContextMenuAction[] = [ { name: 'a', title: '选项 1', action: () => console.log('选项 1 被点击'), }, { name: 'b', title: '选项 2', action: () => console.log('选项 2 被点击'), }, ]; const ContextMenu = ctx.commonUI.ContextMenu; return ( <div> <div onClick={(e) => { ContextMenu.create(menuItems, e); }}>点击这里</div> </div> ); }; export default App;

ContextMenu.create(menus, event)接收菜单数组与事件对象(MouseEvent | React.MouseEvent),在事件位置弹出菜单;文档示例用onClick触发,你也可在onContextMenu中调用实现右键菜单。

底层的三级处理管线

从源码可以梳理出 ContextMenu 的完整实现链路,插件侧入口在 packages/shell/src/components/context-menu.tsx,核心逻辑封装在 packages/utils/src/context-menu.tsx:

  1. parseContextMenuProperties(属性归一化):逐项过滤condition不满足的菜单项、计算disabled状态、将action包装为"先销毁菜单再执行"、递归解析最多两级的items子菜单(超过MAX_LEVEL = 2会告警),并按name去重,见 context-menu.tsx;
  2. parseContextMenuAsReactNode(渲染为 React 节点):根据type映射为@alifd/nextMenu 的Item(普通项,含help帮助图标)、PopupItem(含子菜单项)、Divider(分隔线)或NODE_TREE节点树,见 context-menu.tsx;
  3. createContextMenu(定位与挂载):调用event.preventDefault()阻止默认行为,计算菜单宽高(菜单项高度读取 CSS 变量--context-menu-item-height),当菜单位置超出视口时自动向左/向上回退,最后通过Menu.create挂载到document.body,见 context-menu.tsx。

另外有两个值得注意的细节:

  • 全局开关engineConfig.get('enableContextMenu')为 false 时,ContextMenu 直接渲染 children 而不绑定右键,见 packages/shell/src/components/context-menu.tsx;
  • 插件上下文注入:组件与create都会从editor.get('pluginContext')获取插件上下文(见 packages/shell/src/api/commonUI.tsx),因此action中也能访问ctx的能力(如common.utils.intl做国际化,node.select()选中节点)。

最佳实践与注意事项

结合文档说明与源码实现,在插件中合理使用 CommonUI 有几点建议:

  1. 优先从ctx.commonUI取组件,而非直接 import@alifd/next:这样插件界面会跟随引擎主题自动切换,避免因主题升级导致样式错位;
  2. 在插件中通过ctx.commonUI.Tip / HelpTip / Title替代手写悬浮层:它们与引擎画布提示共用同一套渲染体系,交互体验更统一;
  3. 上下文菜单记得设置nameparseContextMenuProperties会按name去重,同名菜单项只保留第一个;
  4. 子菜单最多两级:超过会打印告警日志(context menu level is too deep, please check your context menu config);
  5. 结合选中节点做动态菜单:利用conditiondisabledaction(nodes)中的nodes参数,实现"右键菜单随当前选中组件变化"的效果;
  6. 菜单自动避让视口:靠近窗口边缘时菜单会自动回退,无需手动计算坐标。

如果官方文档中列出的组件不满足你的业务场景,可以按文档说明向引擎仓库提交 issue 申请补充(仓库位于packages/目录下的各子包,CommonUI 相关代码集中在packages/shellpackages/typespackages/utilspackages/editor-core)。

总结

CommonUI 是 lowcode-engine 插件开发的"标准 UI 层":引擎自研的 Tip、HelpTip、Title 提供了与画布一致的悬浮提示与标题渲染,ContextMenu 提供了支持条件过滤、禁用态、两级子菜单与节点树的三级处理管线,而透传的 27 个@alifd/next组件则覆盖了绝大多数表单与展示需求。开发插件时统一使用ctx.commonUI,即可在保证功能完整的同时,获得跨项目、跨主题的一致体验与兼容性。

【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询