- 将包名从 @fishdingding/bim-engine-sdk 改为 iflow-engine - 将构建输出文件从 bim-engine-sdk.*.js 改为 iflow-engine.*.js - 将全局变量从 LyzBimEngineSDK 改为 IflowEngine - 将第三方引擎SDK从本地引入改为npm包引入 (iflow-engine-base) - 移除本地 src/engine_base 目录,移至回收站 - 更新所有文档和demo中的引用
32 KiB
ButtonGroup 组件详细文档
本文档详细描述 ButtonGroup 组件的实现细节,包括 API、UI 结构、逻辑流程等,供 AI 根据文档重现组件。
1. 组件概述
1.1 基本信息
- 组件名称:
BimButtonGroup - 文件路径:
src/components/button-group/index.ts - 类型定义:
src/components/button-group/index.type.ts - 样式文件:
src/components/button-group/index.css - 实现接口:
IBimComponent - 用途: 提供通用的按钮组组件,支持按钮、菜单、分组、嵌套菜单等功能
1.2 在 SDK 中的位置
- ButtonGroup 组件是独立的 UI 组件
- 必须通过
ButtonGroupManager或ToolbarManager使用,不允许直接使用 ButtonGroupManager位于src/managers/button-group-manager.tsToolbarManager位于src/managers/toolbar-manager.ts
2. 组件类 API 文档
2.1 构造函数
constructor(options: ButtonGroupOptions)
参数:
options:ButtonGroupOptions- 按钮组配置选项(详见类型定义)
默认配置:
{
showLabel: true,
visibility: {},
direction: 'row', // 默认横向排列
position: 'static', // 默认静态定位
align: 'vertical', // 默认图标在上
expand: 'down' // 默认向下展开
}
行为:
- 解析容器元素(支持字符串 ID 或 HTMLElement)
- 合并用户配置和默认配置
- 记录用户自定义的颜色属性
- 初始化容器
- 应用样式
2.2 公共方法
setEngine(engine: BimEngine): void
设置引擎实例
参数:
engine:BimEngine- 引擎实例
功能:
- 保存引擎引用,用于发送事件
init(): Promise<void>
初始化组件功能(实现 IBimComponent 接口)
功能:
- 调用
render()渲染按钮组 - 订阅语言变更:
localeManager.subscribe() - 订阅主题变更:
themeManager.subscribe()
返回: Promise(异步方法,但当前实现是同步的)
setTheme(theme: ThemeConfig): void
设置主题(实现 IBimComponent 接口)
参数:
theme:ThemeConfig- 全局主题配置
功能:
- 将主题颜色映射到按钮组颜色
- 只应用没有被用户自定义的颜色属性
- 如果用户已自定义颜色,保持用户自定义
主题颜色映射:
theme.panelBackground→backgroundColortheme.componentBackground→btnBackgroundColortheme.componentHover→btnHoverColortheme.componentActive→btnActiveColortheme.icon→iconColortheme.iconActive→iconActiveColortheme.textSecondary→textColortheme.textPrimary→textActiveColor
setLocales(): void
设置语言(实现 IBimComponent 接口)
功能:
- 调用
render()重新渲染,更新所有按钮的标签文本
setColors(colors: ButtonGroupColors): void
直接设置颜色(强制覆盖)
参数:
colors:ButtonGroupColors- 颜色配置对象
功能:
- 更新配置选项
- 标记这些颜色为自定义,后续的
setTheme()不会覆盖它们 - 应用样式
setBackgroundColor(color: string): void
设置背景颜色
参数:
color:string- 背景颜色值
功能:
- 调用
setColors({ backgroundColor: color })
addGroup(groupId: string, beforeGroupId?: string): void
添加按钮组
参数:
groupId:string- 组 ID(必须唯一)beforeGroupId:string(可选) - 在此组之前插入
功能:
- 创建新的按钮组
- 如果组已存在,忽略
- 如果指定了
beforeGroupId,在该组之前插入;否则追加到末尾
addButton(config: ButtonConfig): void
添加按钮
参数:
config:ButtonConfig- 按钮配置
功能:
- 将按钮添加到指定组
- 如果指定了
parentId,将按钮添加为父按钮的子项(嵌套菜单) - 如果未指定
parentId,将按钮添加到组的根级别
按钮类型:
type: 'button'- 普通按钮type: 'menu'- 菜单按钮(有子项)
render(): void
渲染按钮组
功能:
- 清空容器
- 清空按钮引用映射
- 遍历所有组,渲染每个组
- 每个组渲染为一个
.bim-btn-group-section元素
updateButtonVisibility(id: string, visible: boolean): void
更新按钮可见性
参数:
id:string- 按钮 IDvisible:boolean- 是否可见
功能:
- 更新
options.visibility对象 - 调用
render()重新渲染
setShowLabel(show: boolean): void
设置是否显示标签
参数:
show:boolean- 是否显示标签
功能:
- 更新
options.showLabel - 调用
updateLabelsVisibility()更新所有按钮的标签显示状态
destroy(): void
销毁组件(实现 IBimComponent 接口)
功能:
- 取消语言和主题订阅
- 关闭下拉菜单(如果打开)
- 清空容器
- 清空按钮引用映射
2.3 受保护方法
emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]): void
发送事件
功能:
- 如果引擎已设置,通过引擎发送事件
- 如果引擎未设置,输出警告
2.4 私有方法(供理解实现细节)
initContainer(): void
初始化容器
功能:
- 清空容器内容
- 添加
bim-btn-group-root类 - 根据
direction添加dir-row或dir-column类 - 如果提供了
className,添加自定义类 - 调用
updatePosition()更新位置
updatePosition(): void
更新容器位置
功能:
- 根据
position选项设置容器位置 - 支持预设位置(如 'center', 'top-left' 等)或坐标对象
{ x, y } - 如果
position是 'static',使用相对定位
位置计算逻辑:
static: 使用相对定位,不设置绝对定位属性{ x, y }: 直接使用坐标值- 预设位置: 使用
margin: 20px和transform实现定位
applyStyles(): void
应用样式到容器
功能:
- 将配置的颜色值设置到 CSS 变量
- CSS 变量映射:
backgroundColor→--bim-btn-group-section-bgbtnBackgroundColor→--bim-btn-bgbtnHoverColor→--bim-btn-hover-bgbtnActiveColor→--bim-btn-active-bgiconColor→--bim-icon-coloriconActiveColor→--bim-icon-active-colortextColor→--bim-btn-text-colortextActiveColor→--bim-btn-text-active-color
renderGroup(group: ButtonGroup, index: number, total: number): HTMLElement
渲染按钮组
参数:
group:ButtonGroup- 按钮组对象index:number- 组索引total:number- 总组数
返回: 组元素
功能:
- 创建
.bim-btn-group-section元素 - 如果不是最后一组,添加
has-divider类(用于显示分隔线) - 遍历组内的按钮,渲染每个可见的按钮
renderButton(button: OptButton): HTMLElement
渲染单个按钮
参数:
button:OptButton- 按钮配置
返回: 按钮包装元素
功能:
- 创建
.opt-btn-wrapper和.opt-btn元素 - 根据按钮的
align或全局align设置布局方向 - 如果按钮是激活状态,添加
active类 - 如果按钮是禁用状态,添加
disabled类 - 如果按钮没有标签,添加
no-label类 - 创建图标元素(
.opt-btn-icon) - 创建文字包装器(
.opt-btn-text-wrapper),包含标签和箭头(如果有子项) - 绑定点击、鼠标进入、鼠标离开事件
- 保存按钮引用到
btnRefsMap
renderDropdownItem(button: OptButton): HTMLElement
渲染下拉菜单项
参数:
button:OptButton- 按钮配置
返回: 菜单项元素
功能:
- 创建
.opt-btn-dropdown-item元素 - 根据按钮的
align设置布局方向(默认 'horizontal') - 创建图标和标签
- 绑定点击事件
handleClick(button: OptButton): void
处理按钮点击
功能:
- 如果按钮是禁用状态,忽略
- 如果按钮没有子项:
- 如果
keepActive为 true,切换激活状态 - 关闭下拉菜单
- 调用
onClick回调(如果存在)
- 如果
- 如果按钮有子项,不处理(由鼠标悬停处理)
handleMouseEnter(button: OptButton, btnEl: HTMLElement): void
处理鼠标进入
功能:
- 清除悬停超时
- 如果按钮有子项,显示下拉菜单
- 如果按钮没有子项,关闭下拉菜单
handleMouseLeave(): void
处理鼠标离开
功能:
- 设置 200ms 延迟后关闭下拉菜单(防止鼠标移动到菜单时关闭)
showDropdown(button: OptButton, btnEl: HTMLElement): void
显示下拉菜单
功能:
- 关闭当前打开的下拉菜单
- 创建
.opt-btn-dropdown元素 - 根据主按钮组的方向设置菜单的布局方向:
- 如果主组是横向(
direction: 'row'),菜单纵向排列 - 如果主组是纵向(
direction: 'column'),菜单横向排列
- 如果主组是横向(
- 渲染所有可见的子按钮
- 计算菜单位置(根据
expand选项):up: 向上展开,与按钮水平居中对齐down: 向下展开,与按钮水平居中对齐right: 向右展开,与按钮垂直居中对齐left: 向左展开,与按钮垂直居中对齐
- 将菜单添加到
document.body(绝对定位) - 绑定鼠标进入和离开事件(保持菜单打开)
closeDropdown(): void
关闭下拉菜单
功能:
- 移除下拉菜单元素
- 移除所有按钮箭头元素的
rotated类
updateButtonState(buttonId: string): void
更新按钮状态
功能:
- 根据
activeBtnIdsSet 更新按钮的active类
findButton(buttons: OptButton[], id: string): OptButton | undefined
查找按钮(递归)
功能:
- 在按钮数组中查找指定 ID 的按钮
- 递归查找子按钮
findButtonById(id: string): OptButton | undefined
根据 ID 查找按钮
功能:
- 在所有组中查找指定 ID 的按钮
isVisible(id: string): boolean
检查按钮是否可见
功能:
- 检查
options.visibility对象 - 如果未设置或为 true,返回 true
- 如果设置为 false,返回 false
getIcon(icon?: string): string
获取图标 HTML
功能:
- 如果提供了图标,返回图标 HTML
- 否则返回默认图标
updateLabelsVisibility(): void
更新标签可见性
功能:
- 遍历所有按钮引用
- 根据
showLabel选项和按钮是否有标签,更新no-label类
3. 分化组件说明
3.1 Toolbar
文件路径: src/components/button-group/toolbar/index.ts
继承关系: Toolbar extends BimButtonGroup
特殊功能:
- 预定义了底部工具栏的配置
- 自动加载默认按钮(首页、漫游、定位、设置、信息等)
- 使用固定的配置(底部居中、横向排列、图标在上、向上展开)
实现方式:
- 重写
init()方法 - 先调用
super.init() - 动态导入所有默认按钮配置
- 创建两个组('group-1' 和 'group-2')
- 添加所有默认按钮
- 调用
render()渲染
默认按钮列表:
group-1:home- 首页按钮(通过工厂函数创建,注入 engine)walk-menu- 漫游菜单walk-person- 人视walk-bird- 鸟瞰location- 定位
group-2:setting- 设置info- 信息
与父类的差异:
- 固定了配置选项(
position: 'bottom-center',direction: 'row',align: 'vertical',expand: 'up') - 自动加载默认按钮
- 其他功能完全继承自
BimButtonGroup
4. Manager API 文档
4.1 ButtonGroupManager 类
文件路径: src/managers/button-group-manager.ts
继承关系: ButtonGroupManager extends BimComponent
构造函数
constructor(engine: BimEngine, container: HTMLElement)
参数:
engine:BimEngine- 引擎实例container:HTMLElement- 按钮组挂载的目标容器
公共方法
create(id: string, options: Omit<ButtonGroupOptions, 'container'>): BimButtonGroup
创建按钮组
参数:
id:string- 按钮组唯一标识options:Omit<ButtonGroupOptions, 'container'>- 配置选项(不需要传 container)
返回: BimButtonGroup 实例
功能:
- 自动使用 Manager 绑定的容器
- 创建
BimButtonGroup实例 - 注入引擎实例
- 调用
init()初始化 - 将按钮组保存到 Map 中
get(id: string): BimButtonGroup | undefined
获取按钮组
参数:
id:string- 按钮组 ID
返回: BimButtonGroup 实例或 undefined
updateTheme(theme: ThemeConfig): void
更新所有按钮组的主题
参数:
theme:ThemeConfig- 主题配置
destroy(): void
销毁管理器
功能:
- 销毁所有按钮组
- 清空 Map
4.2 ToolbarManager 类
文件路径: src/managers/toolbar-manager.ts
继承关系: ToolbarManager extends BimComponent
构造函数
constructor(engine: BimEngine, container: HTMLElement)
参数:
engine:BimEngine- 引擎实例container:HTMLElement- 工具栏挂载的目标容器
行为:
- 自动调用
init()创建工具栏
公共方法
updateTheme(theme: ThemeConfig): void
更新工具栏主题
refresh(): void
刷新工具栏
功能:
- 调用工具栏的
render()方法重新渲染
addGroup(groupId: string, beforeGroupId?: string): void
添加按钮组
功能:
- 转发到工具栏的
addGroup()方法 - 自动调用
render()重新渲染
addButton(config: ButtonConfig): void
添加按钮
功能:
- 转发到工具栏的
addButton()方法 - 自动调用
render()重新渲染
setButtonVisibility(id: string, v: boolean): void
设置按钮可见性
功能:
- 转发到工具栏的
updateButtonVisibility()方法
setShowLabel(show: boolean): void
设置是否显示标签
功能:
- 转发到工具栏的
setShowLabel()方法
setVisible(visible: boolean): void
设置工具栏可见性
功能:
- 通过设置容器的
visibilityCSS 属性控制显示/隐藏
setBackgroundColor(color: string): void
设置背景颜色
功能:
- 转发到工具栏的
setBackgroundColor()方法
setColors(colors: ButtonGroupColors): void
设置颜色
功能:
- 转发到工具栏的
setColors()方法
destroy(): void
销毁管理器
功能:
- 销毁工具栏实例
5. UI 详细描述
5.1 DOM 结构
完整 HTML 结构:
<div class="bim-btn-group-root [dir-row|dir-column] [static] [className]">
<!-- 按钮组 1 -->
<div class="bim-btn-group-section [has-divider]">
<!-- 按钮包装器 -->
<div class="opt-btn-wrapper">
<div class="opt-btn [align-vertical|align-horizontal] [active] [disabled] [no-label]">
<div class="opt-btn-icon">[图标 SVG]</div>
<div class="opt-btn-text-wrapper">
<span class="opt-btn-label">标签文本</span>
[<span class="opt-btn-arrow [rotated]">▼</span>] <!-- 如果有子项 -->
</div>
</div>
</div>
<!-- 更多按钮... -->
</div>
<!-- 按钮组 2 -->
<div class="bim-btn-group-section">
<!-- 更多按钮... -->
</div>
</div>
<!-- 下拉菜单(动态创建,添加到 document.body) -->
<div class="opt-btn-dropdown" style="[位置样式]">
<div class="opt-btn-dropdown-item [align-horizontal|align-vertical]">
<div class="opt-btn-icon">[图标 SVG]</div>
<span class="opt-btn-dropdown-label">标签文本</span>
</div>
<!-- 更多菜单项... -->
</div>
5.2 CSS 类名和样式
.bim-btn-group-root (根容器)
display: flex- Flex 布局gap: 8px- 组之间的间距z-index: 1000- 层级position: absolute- 绝对定位(除非是 static)pointer-events: auto- 确保可接收事件
.bim-btn-group-root.static (静态定位)
position: relative- 相对定位- 清除所有绝对定位属性
.bim-btn-group-root.dir-row (横向排列)
flex-direction: row- 横向排列align-items: center- 垂直居中
.bim-btn-group-root.dir-column (纵向排列)
flex-direction: column- 纵向排列align-items: stretch- 拉伸对齐
.bim-btn-group-section (按钮组)
display: flex- Flex 布局gap: 4px- 按钮之间的间距background-color: var(--bim-btn-group-section-bg)- 背景色border-radius: 6px- 圆角padding: 4px- 内边距box-shadow- 阴影效果
.opt-btn-wrapper (按钮包装器)
position: relative- 相对定位(为下拉菜单提供定位参考)
.opt-btn (按钮本体)
display: flex- Flex 布局cursor: pointer- 指针光标border-radius: 4px- 圆角transition: background-color 0.2s, color 0.2s- 过渡动画padding: 6px- 内边距align-items: center- 垂直居中justify-content: center- 水平居中
.opt-btn:hover (按钮悬停)
background-color: var(--bim-btn-hover-bg)- 悬停背景色
.opt-btn.active (按钮激活)
background-color: var(--bim-btn-active-bg)- 激活背景色color: var(--bim-btn-text-active-color)- 激活文字颜色
.opt-btn.disabled (按钮禁用)
opacity: 0.5- 半透明cursor: not-allowed- 禁止光标
.opt-btn-icon (图标)
width/height: var(--bim-icon-size)- 图标尺寸display: flex- Flex 布局align-items: center- 垂直居中justify-content: center- 水平居中color: var(--bim-icon-color)- 图标颜色flex-shrink: 0- 不收缩
.opt-btn-text-wrapper (文字包装器)
display: flex- Flex 布局align-items: center- 垂直居中justify-content: center- 水平居中pointer-events: none- 不接收鼠标事件
.opt-btn-label (标签)
display: inline- 内联显示
.opt-btn.no-label .opt-btn-label (无标签时隐藏)
display: none- 隐藏
.opt-btn.align-vertical (垂直布局 - 图标在上)
flex-direction: column- 纵向排列text-align: center- 文字居中
.opt-btn.align-horizontal (水平布局 - 图标在左)
flex-direction: row- 横向排列
.opt-btn-arrow (箭头)
font-size: 10px- 字体大小opacity: 0.6- 半透明transition: transform 0.2s- 旋转过渡margin-left: 4px- 左边距
.opt-btn-arrow.rotated (箭头旋转)
transform: rotate(180deg)- 旋转 180 度
.opt-btn-dropdown (下拉菜单)
position: absolute- 绝对定位background-color: var(--bim-toolbar-bg)- 背景色border-radius: 4px- 圆角padding: 4px- 内边距box-shadow- 阴影效果z-index: 1001- 层级display: flex- Flex 布局flex-direction: column- 纵向排列(默认)border: 1px solid rgba(255, 255, 255, 0.1)- 边框animation: dropdown-fade-in 0.2s- 淡入动画
.opt-btn-dropdown-item (菜单项)
display: flex- Flex 布局align-items: center- 垂直居中padding: 8px 12px- 内边距cursor: pointer- 指针光标border-radius: 4px- 圆角color: var(--bim-btn-text-color)- 文字颜色transition: background 0.2s- 背景过渡
.opt-btn-dropdown-item:hover (菜单项悬停)
background-color: var(--bim-btn-hover-bg)- 悬停背景色color: #fff- 白色文字
5.3 CSS 变量
定义位置: 容器元素的内联样式
变量列表:
--bim-btn-group-section-bg: 按钮组背景颜色--bim-btn-bg: 按钮背景颜色--bim-btn-hover-bg: 按钮悬停背景颜色--bim-btn-active-bg: 按钮激活背景颜色--bim-icon-color: 图标颜色--bim-icon-active-color: 图标激活颜色--bim-btn-text-color: 文字颜色--bim-btn-text-active-color: 文字激活颜色--bim-toolbar-bg: 工具栏背景颜色(用于下拉菜单)
5.4 交互行为
按钮点击
- 触发条件: 点击按钮元素
- 行为:
- 如果按钮是禁用状态,忽略
- 如果按钮没有子项:
- 如果
keepActive为 true,切换激活状态 - 关闭下拉菜单
- 调用
onClick回调
- 如果
- 如果按钮有子项,不处理(由鼠标悬停处理)
鼠标悬停
- 触发条件: 鼠标进入按钮
- 行为:
- 如果按钮有子项,显示下拉菜单
- 如果按钮没有子项,关闭下拉菜单
鼠标离开
- 触发条件: 鼠标离开按钮或下拉菜单
- 行为:
- 延迟 200ms 后关闭下拉菜单(防止鼠标移动到菜单时关闭)
下拉菜单显示
- 触发条件: 鼠标悬停在有子项的按钮上
- 行为:
- 创建下拉菜单元素
- 计算位置(根据
expand选项) - 添加到
document.body - 显示淡入动画
下拉菜单关闭
- 触发条件:
- 鼠标离开按钮和菜单区域
- 点击按钮(非菜单按钮)
- 行为:
- 移除下拉菜单元素
- 移除箭头旋转状态
5.5 响应式行为
- 按钮组位置会根据容器尺寸自动调整(如果使用绝对定位)
- 下拉菜单位置会根据按钮位置和窗口尺寸自动计算
- 标签文本支持多语言切换
- 按钮可见性可以动态控制
6. 逻辑流程详细描述
6.1 初始化流程
-
构造函数调用:
- 解析容器元素
- 合并配置选项
- 记录用户自定义的颜色属性
- 调用
initContainer()初始化容器 - 调用
applyStyles()应用样式
-
init() 方法执行:
- 调用
render()渲染按钮组 - 订阅语言变更:
localeManager.subscribe() - 订阅主题变更:
themeManager.subscribe()
- 调用
6.2 渲染流程
-
render() 方法:
- 清空容器
- 清空按钮引用映射
- 遍历所有组,调用
renderGroup()渲染每个组
-
renderGroup() 方法:
- 创建组元素
- 如果不是最后一组,添加分隔线类
- 遍历组内按钮,调用
renderButton()渲染每个可见按钮
-
renderButton() 方法:
- 创建按钮包装器和按钮元素
- 设置布局方向(根据按钮或全局配置)
- 设置激活/禁用状态
- 创建图标元素
- 创建文字包装器(包含标签和箭头)
- 绑定事件监听器
- 保存按钮引用
6.3 事件处理流程
按钮点击流程
- 用户点击按钮 →
click事件 handleClick()被调用- 检查按钮是否禁用
- 如果按钮没有子项:
- 如果
keepActive为 true,切换激活状态 - 更新按钮的
active类 - 关闭下拉菜单
- 调用
onClick回调
- 如果
下拉菜单显示流程
- 鼠标进入按钮 →
mouseenter事件 handleMouseEnter()被调用- 清除悬停超时
- 如果按钮有子项,调用
showDropdown() showDropdown()执行:- 关闭当前打开的下拉菜单
- 创建下拉菜单元素
- 设置菜单布局方向(根据主组方向)
- 渲染所有可见的子按钮
- 计算菜单位置(根据
expand选项) - 添加到
document.body - 绑定鼠标事件(保持菜单打开)
下拉菜单关闭流程
- 鼠标离开按钮或菜单 →
mouseleave事件 handleMouseLeave()被调用- 设置 200ms 延迟
- 延迟后调用
closeDropdown() closeDropdown()执行:- 移除下拉菜单元素
- 移除箭头旋转状态
6.4 状态管理
内部状态
groups: 按钮组数组activeBtnIds: 激活按钮 ID 的 SetbtnRefs: 按钮元素引用的 MapdropdownElement: 当前打开的下拉菜单元素hoverTimeout: 悬停超时的 IDcustomColors: 用户自定义颜色属性的 Set
订阅管理
unsubscribeLocale: 语言订阅取消函数unsubscribeTheme: 主题订阅取消函数
6.5 与其他组件的交互
- 与 ButtonGroupManager/ToolbarManager: 通过 Manager 创建和管理
- 与 ThemeManager: 订阅主题变更
- 与 LocaleManager: 订阅语言变更
- 与 BimEngine: 通过引擎发送事件(如果设置了引擎)
7. 国际化支持
7.1 使用的翻译键
button.label: 按钮标签(每个按钮的label属性)
7.2 语言变更处理
- 组件订阅
localeManager.subscribe() - 语言变更时,
setLocales()方法被调用 - 调用
render()重新渲染,更新所有按钮的标签文本
7.3 实现细节
public setLocales(): void {
this.render(); // 重新渲染,标签会通过 t() 函数获取最新翻译
}
// 在 renderButton() 中
label.textContent = t(button.label);
8. 主题支持
8.1 使用的主题变量
theme.panelBackground→backgroundColortheme.componentBackground→btnBackgroundColortheme.componentHover→btnHoverColortheme.componentActive→btnActiveColortheme.icon→iconColortheme.iconActive→iconActiveColortheme.textSecondary→textColortheme.textPrimary→textActiveColor
8.2 主题变更处理
- 组件订阅
themeManager.subscribe() - 主题变更时,
setTheme()方法被调用 - 只应用没有被用户自定义的颜色属性
- 如果用户已自定义颜色,保持用户自定义
8.3 自定义颜色保护机制
- 构造函数中记录用户自定义的颜色属性
setTheme()时只更新未自定义的颜色setColors()时标记颜色为自定义
9. 使用示例
9.1 基本使用(通过 ButtonGroupManager)
import { BimEngine } from 'iflow-engine';
const engine = new BimEngine('container');
// 创建按钮组
const buttonGroup = engine.buttonGroup.create('my-group', {
position: 'top-right',
direction: 'row',
showLabel: true
});
// 添加组
buttonGroup.addGroup('group-1');
// 添加按钮
buttonGroup.addButton({
id: 'btn-1',
groupId: 'group-1',
type: 'button',
label: 'toolbar.home',
icon: '<svg>...</svg>',
onClick: (button) => {
console.log('按钮被点击:', button.id);
}
});
9.2 使用工具栏(通过 ToolbarManager)
// 工具栏已自动创建,直接使用
engine.toolbar.addButton({
id: 'custom-btn',
groupId: 'group-1',
type: 'button',
label: 'toolbar.custom',
icon: '<svg>...</svg>',
onClick: (button) => {
console.log('自定义按钮被点击');
}
});
// 控制按钮可见性
engine.toolbar.setButtonVisibility('location', false);
// 控制标签显示
engine.toolbar.setShowLabel(false);
9.3 使用嵌套菜单
// 添加菜单按钮
buttonGroup.addButton({
id: 'menu-btn',
groupId: 'group-1',
type: 'menu',
label: 'toolbar.menu',
icon: '<svg>...</svg>',
children: [
{
id: 'sub-1',
type: 'button',
label: 'toolbar.sub1',
onClick: () => console.log('子项 1')
},
{
id: 'sub-2',
type: 'button',
label: 'toolbar.sub2',
onClick: () => console.log('子项 2')
}
]
});
10. 实现细节(供 AI 重现)
10.1 关键算法
位置计算算法
function calculatePosition(position, containerWidth, containerHeight) {
const margin = 20;
switch (position) {
case 'top-left': return { top: margin, left: margin };
case 'top-center': return { top: margin, left: '50%', transform: 'translateX(-50%)' };
case 'top-right': return { top: margin, right: margin };
// ... 其他位置
}
}
下拉菜单位置计算算法
function calculateDropdownPosition(expand, buttonRect, dropdownRect) {
switch (expand) {
case 'up':
return {
bottom: window.innerHeight - buttonRect.top + 8,
left: buttonRect.left + (buttonRect.width - dropdownRect.width) / 2
};
case 'down':
return {
top: buttonRect.bottom + 8,
left: buttonRect.left + (buttonRect.width - dropdownRect.width) / 2
};
// ... 其他方向
}
}
激活状态切换算法
function toggleActiveState(buttonId, activeBtnIds) {
if (activeBtnIds.has(buttonId)) {
activeBtnIds.delete(buttonId);
} else {
activeBtnIds.add(buttonId);
}
}
10.2 性能优化点
-
按钮引用缓存:
- 使用
btnRefsMap 缓存按钮元素引用 - 避免重复查询 DOM
- 使用
-
延迟关闭下拉菜单:
- 使用 200ms 延迟,防止鼠标移动到菜单时关闭
- 使用
setTimeout和clearTimeout管理
-
条件渲染:
- 只渲染可见的按钮(根据
visibility选项) - 减少 DOM 操作
- 只渲染可见的按钮(根据
-
CSS 变量:
- 使用 CSS 变量应用主题和颜色
- 主题变更时无需重新渲染 DOM
10.3 注意事项和边界情况
-
按钮 ID 唯一性:
- 按钮 ID 必须唯一
- 如果重复,可能导致状态管理错误
-
组 ID 唯一性:
- 组 ID 必须唯一
addGroup()会检查重复
-
嵌套菜单深度:
- 当前实现只支持一级嵌套(按钮 → 子项)
- 不支持多级嵌套
-
下拉菜单定位:
- 下拉菜单添加到
document.body,使用绝对定位 - 需要根据按钮位置和窗口尺寸计算位置
- 可能需要处理边界情况(菜单超出窗口)
- 下拉菜单添加到
-
事件清理:
- 组件销毁时必须清理所有事件监听
- 必须取消主题和语言订阅
- 必须关闭下拉菜单
-
翻译键处理:
- 标签可能是翻译键或普通文本
- 只有翻译键才需要通过
t()函数处理
-
自定义颜色保护:
- 用户自定义的颜色不会被主题覆盖
- 需要正确记录和管理自定义颜色
11. 类型定义
11.1 ButtonGroupOptions
interface ButtonGroupOptions extends ButtonGroupColors {
container: HTMLElement | string; // 容器(必需)
position?: GroupPosition; // 位置(可选)
direction?: GroupDirection; // 排列方向(可选,默认 'row')
align?: ButtonAlign; // 按钮内部布局(可选,默认 'vertical')
expand?: ExpandDirection; // 菜单展开方向(可选,默认 'down')
showLabel?: boolean; // 是否显示标签(可选,默认 true)
visibility?: Record<string, boolean>; // 按钮可见性(可选)
className?: string; // 自定义类名(可选)
}
11.2 ButtonConfig
interface ButtonConfig {
id: string; // 按钮 ID(必需,必须唯一)
type: ButtonType; // 按钮类型(必需,'button' | 'menu')
label: string; // 标签(必需,支持翻译键)
icon?: string; // 图标 SVG(可选)
keepActive?: boolean; // 是否保持激活状态(可选)
disabled?: boolean; // 是否禁用(可选)
onClick?: (button: OptButton) => void; // 点击回调(可选)
children?: ButtonConfig[]; // 子项(可选,用于菜单)
groupId?: string; // 所属组 ID(可选)
parentId?: string; // 父按钮 ID(可选,用于嵌套)
align?: ButtonAlign; // 按钮内部布局(可选)
iconSize?: number; // 图标大小(可选,默认 32)
minWidth?: number; // 最小宽度(可选,默认 50)
}
11.3 其他类型
type ButtonType = 'button' | 'menu';
type GroupPosition = 'center' | 'top-left' | 'top-center' | 'top-right'
| 'left-center' | 'right-center'
| 'bottom-left' | 'bottom-center' | 'bottom-right'
| { x: number; y: number } | 'static';
type GroupDirection = 'row' | 'column';
type ButtonAlign = 'vertical' | 'horizontal';
type ExpandDirection = 'up' | 'down' | 'left' | 'right';
12. 文件清单
12.1 相关文件
src/components/button-group/index.ts- 主组件类src/components/button-group/index.type.ts- 类型定义src/components/button-group/index.css- 样式文件src/components/button-group/toolbar/index.ts- 工具栏(分化组件)src/managers/button-group-manager.ts- 通用按钮组管理器src/managers/toolbar-manager.ts- 工具栏管理器
12.2 依赖文件
src/types/component.ts- IBimComponent 接口src/themes/types.ts- ThemeConfig 类型src/services/theme.ts- ThemeManagersrc/services/locale.ts- LocaleManagersrc/types/events.ts- EngineEvents 类型
13. 更新记录
| 日期 | 修改内容 | 修改人 |
|---|---|---|
| 2024-XX-XX | 初始创建 | AI Assistant |
重要提醒: 本文档必须与组件代码保持同步。任何组件修改都必须更新本文档!