885 lines
24 KiB
Markdown
885 lines
24 KiB
Markdown
# Dialog 组件详细文档
|
||
|
||
> 本文档详细描述 Dialog 组件的实现细节,包括 API、UI 结构、逻辑流程等,供 AI 根据文档重现组件。
|
||
|
||
---
|
||
|
||
## 1. 组件概述
|
||
|
||
### 1.1 基本信息
|
||
- **组件名称**: `BimDialog`
|
||
- **文件路径**: `src/components/dialog/index.ts`
|
||
- **类型定义**: `src/components/dialog/index.type.ts`
|
||
- **样式文件**: `src/components/dialog/index.css`
|
||
- **实现接口**: `IBimComponent`
|
||
- **用途**: 提供可拖拽、可缩放的通用弹窗组件,支持自定义内容和样式
|
||
|
||
### 1.2 在 SDK 中的位置
|
||
- Dialog 组件是独立的 UI 组件
|
||
- 必须通过 `DialogManager` 使用,不允许直接使用
|
||
- `DialogManager` 位于 `src/managers/dialog-manager.ts`
|
||
|
||
---
|
||
|
||
## 2. 组件类 API 文档
|
||
|
||
### 2.1 构造函数
|
||
|
||
```typescript
|
||
constructor(options: DialogOptions)
|
||
```
|
||
|
||
**参数**:
|
||
- `options`: `DialogOptions` - 弹窗配置选项(详见类型定义)
|
||
|
||
**默认配置**:
|
||
```typescript
|
||
{
|
||
title: 'Dialog',
|
||
width: 300,
|
||
height: 'auto',
|
||
position: 'center',
|
||
draggable: true,
|
||
resizable: false,
|
||
minWidth: 200,
|
||
minHeight: 100
|
||
}
|
||
```
|
||
|
||
**行为**:
|
||
- 合并用户配置和默认配置
|
||
- 创建 DOM 结构
|
||
- 自动调用 `init()` 方法
|
||
|
||
### 2.2 公共方法
|
||
|
||
#### `init(): void`
|
||
初始化组件功能(实现 `IBimComponent` 接口)
|
||
|
||
**功能**:
|
||
- 将弹窗元素添加到容器
|
||
- 初始化位置
|
||
- 如果 `draggable` 为 true,初始化拖拽功能
|
||
- 如果 `resizable` 为 true,初始化缩放功能
|
||
- 订阅主题和语言变更
|
||
- 调用 `onOpen` 回调
|
||
|
||
**调用时机**: 构造函数中自动调用,也可手动调用
|
||
|
||
#### `setTheme(theme: ThemeConfig): void`
|
||
设置主题(实现 `IBimComponent` 接口)
|
||
|
||
**参数**:
|
||
- `theme`: `ThemeConfig` - 全局主题配置
|
||
|
||
**功能**:
|
||
- 将主题颜色映射到 CSS 变量
|
||
- 如果用户未自定义颜色,使用主题颜色
|
||
- 如果用户已自定义颜色,保持用户自定义
|
||
|
||
**CSS 变量映射**:
|
||
- `--bim-dialog-bg` ← `theme.panelBackground` (如果未自定义 `backgroundColor`)
|
||
- `--bim-dialog-header-bg` ← `theme.componentHover` (如果未自定义 `headerBackgroundColor`)
|
||
- `--bim-dialog-title-color` ← `theme.textPrimary` (如果未自定义 `titleColor`)
|
||
- `--bim-dialog-text-color` ← `theme.textPrimary` (如果未自定义 `textColor`)
|
||
- `--bim-dialog-border-color` ← `theme.border` (如果未自定义 `borderColor`)
|
||
|
||
#### `setLocales(): void`
|
||
设置语言(实现 `IBimComponent` 接口)
|
||
|
||
**功能**:
|
||
- 更新标题文本(如果标题是翻译键)
|
||
- 使用 `t()` 函数获取翻译后的文本
|
||
|
||
**行为**:
|
||
- 查找 `.bim-dialog-title` 元素
|
||
- 如果 `options.title` 存在,使用 `t(options.title)` 更新文本
|
||
|
||
#### `setContent(content: HTMLElement | string): void`
|
||
动态设置弹窗内容
|
||
|
||
**参数**:
|
||
- `content`: `HTMLElement | string` - 内容元素或 HTML 字符串
|
||
|
||
**功能**:
|
||
- 清空当前内容
|
||
- 设置新内容(支持 HTML 字符串或 DOM 元素)
|
||
|
||
#### `close(): void`
|
||
关闭弹窗并销毁
|
||
|
||
**功能**:
|
||
- 清理 `requestAnimationFrame`(如果存在)
|
||
- 取消主题和语言订阅
|
||
- 从 DOM 中移除元素
|
||
- 标记为已销毁
|
||
- 调用 `onClose` 回调
|
||
|
||
#### `destroy(): void`
|
||
销毁组件(实现 `IBimComponent` 接口)
|
||
|
||
**功能**:
|
||
- 调用 `close()` 方法
|
||
|
||
### 2.3 私有方法(供理解实现细节)
|
||
|
||
#### `createDom(): HTMLElement`
|
||
创建弹窗的 DOM 结构
|
||
|
||
**返回**: 创建的弹窗根元素
|
||
|
||
**DOM 结构**:
|
||
```html
|
||
<div class="bim-dialog" [id="..."]>
|
||
<div class="bim-dialog-header" [class="draggable"]>
|
||
<span class="bim-dialog-title">标题文本</span>
|
||
<span class="bim-dialog-close">×</span>
|
||
</div>
|
||
<div class="bim-dialog-content">
|
||
<!-- 用户内容 -->
|
||
</div>
|
||
[<div class="bim-dialog-resize-handle"></div>] <!-- 如果 resizable -->
|
||
</div>
|
||
```
|
||
|
||
**关键实现**:
|
||
1. 创建根元素,应用 CSS 变量和尺寸
|
||
2. 创建标题栏,包含标题和关闭按钮
|
||
3. 创建内容区域,支持 HTML 字符串或 DOM 元素
|
||
4. 如果 `resizable` 为 true,创建缩放手柄
|
||
5. **事件拦截**: 绑定所有鼠标/触摸事件,使用 `stopPropagation()` 阻止冒泡,防止传递给 3D 引擎
|
||
|
||
**事件拦截列表**:
|
||
```typescript
|
||
['click', 'dblclick', 'contextmenu', 'wheel',
|
||
'mousedown', 'mouseup', 'mousemove',
|
||
'touchstart', 'touchend', 'touchmove',
|
||
'pointerdown', 'pointerup', 'pointermove',
|
||
'pointerenter', 'pointerleave', 'pointerover', 'pointerout']
|
||
```
|
||
|
||
#### `initPosition(): void`
|
||
初始化弹窗位置
|
||
|
||
**功能**:
|
||
- 根据 `position` 选项计算弹窗位置
|
||
- 支持预设位置(如 'center', 'top-left' 等)或坐标对象 `{ x, y }`
|
||
- 确保弹窗不超出容器边界
|
||
|
||
**位置计算逻辑**:
|
||
- `center`: `left = (containerWidth - dialogWidth) / 2`, `top = (containerHeight - dialogHeight) / 2`
|
||
- `top-left`: `left = 0`, `top = 0`
|
||
- `top-center`: `left = (containerWidth - dialogWidth) / 2`, `top = 0`
|
||
- `top-right`: `left = containerWidth - dialogWidth`, `top = 0`
|
||
- `left-center`: `left = 0`, `top = (containerHeight - dialogHeight) / 2`
|
||
- `right-center`: `left = containerWidth - dialogWidth`, `top = (containerHeight - dialogHeight) / 2`
|
||
- `bottom-left`: `left = 0`, `top = containerHeight - dialogHeight`
|
||
- `bottom-center`: `left = (containerWidth - dialogWidth) / 2`, `top = containerHeight - dialogHeight`
|
||
- `bottom-right`: `left = containerWidth - dialogWidth`, `top = containerHeight - dialogHeight`
|
||
- `{ x, y }`: 直接使用坐标值
|
||
|
||
**边界限制**:
|
||
```typescript
|
||
left = Math.max(0, Math.min(left, containerWidth - dialogWidth));
|
||
top = Math.max(0, Math.min(top, containerHeight - dialogHeight));
|
||
```
|
||
|
||
#### `initDrag(): void`
|
||
初始化拖拽功能
|
||
|
||
**功能**:
|
||
- 在标题栏上绑定 `mousedown` 事件
|
||
- 实现拖拽移动功能
|
||
- 使用 `requestAnimationFrame` 优化性能
|
||
- 使用 `capture: true` 确保事件在捕获阶段处理
|
||
|
||
**拖拽流程**:
|
||
1. `mousedown`: 记录起始位置和弹窗当前位置,缓存容器和弹窗尺寸
|
||
2. `mousemove`: 计算偏移量,更新弹窗位置,限制在容器边界内
|
||
3. `mouseup`: 清理事件监听和动画帧
|
||
|
||
**性能优化**:
|
||
- 使用 `requestAnimationFrame` 节流更新
|
||
- 缓存容器和弹窗尺寸,减少 reflow
|
||
- 使用 `capture: true` 确保事件处理
|
||
|
||
#### `initResize(): void`
|
||
初始化缩放功能
|
||
|
||
**功能**:
|
||
- 在缩放手柄上绑定 `mousedown` 事件
|
||
- 实现右下角拖拽缩放功能
|
||
- 使用 `requestAnimationFrame` 优化性能
|
||
- 限制最小尺寸
|
||
|
||
**缩放流程**:
|
||
1. `mousedown`: 记录起始位置和弹窗当前尺寸
|
||
2. `mousemove`: 计算偏移量,更新弹窗尺寸,限制最小尺寸
|
||
3. `mouseup`: 清理事件监听和动画帧
|
||
|
||
**尺寸限制**:
|
||
```typescript
|
||
newWidth = Math.max(minWidth || 100, startWidth + deltaX);
|
||
newHeight = Math.max(minHeight || 50, startHeight + deltaY);
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 分化组件说明
|
||
|
||
### 3.1 BimInfoDialog
|
||
|
||
**文件路径**: `src/components/dialog/bimInfoDialog/index.ts`
|
||
|
||
**继承关系**: `BimInfoDialog extends BimDialog`
|
||
|
||
**特殊功能**:
|
||
- 预定义了信息展示的内容结构
|
||
- 包含标题、信息列表和操作按钮
|
||
- 使用固定的配置(宽度 320px,可缩放,可拖拽)
|
||
|
||
**实现方式**:
|
||
- 在构造函数中创建内容 DOM
|
||
- 调用父类构造函数,传入预定义的配置
|
||
- 不需要重写其他方法,直接继承父类功能
|
||
|
||
**内容结构**:
|
||
```html
|
||
<div class="bim-info-dialog-content">
|
||
<h3>Model Information</h3>
|
||
<ul>
|
||
<li><strong>Name:</strong> Sample Project</li>
|
||
<li><strong>Version:</strong> 1.0.0</li>
|
||
<li><strong>Date:</strong> 当前日期</li>
|
||
<li><strong>Status:</strong> <span style="color: green;">Active</span></li>
|
||
</ul>
|
||
<button>Update Status</button>
|
||
</div>
|
||
```
|
||
|
||
**与父类的差异**:
|
||
- 固定了内容结构
|
||
- 固定了部分配置选项
|
||
- 其他功能完全继承自 `BimDialog`
|
||
|
||
---
|
||
|
||
## 4. Manager API 文档
|
||
|
||
### 4.1 DialogManager 类
|
||
|
||
**文件路径**: `src/managers/dialog-manager.ts`
|
||
|
||
**继承关系**: `DialogManager extends BimComponent`
|
||
|
||
### 4.2 构造函数
|
||
|
||
```typescript
|
||
constructor(engine: BimEngine, container: HTMLElement)
|
||
```
|
||
|
||
**参数**:
|
||
- `engine`: `BimEngine` - 引擎实例
|
||
- `container`: `HTMLElement` - 弹窗挂载的目标容器
|
||
|
||
**行为**:
|
||
- 保存容器引用
|
||
- 监听 `ui:open-dialog` 事件
|
||
- 如果事件 payload.id 是 'info',自动打开信息弹窗
|
||
|
||
### 4.3 公共方法
|
||
|
||
#### `create(options: Omit<DialogOptions, 'container'>): BimDialog`
|
||
创建一个通用弹窗
|
||
|
||
**参数**:
|
||
- `options`: `Omit<DialogOptions, 'container'>` - 弹窗配置(不需要传 container)
|
||
|
||
**返回**: `BimDialog` 实例
|
||
|
||
**功能**:
|
||
- 自动使用 Manager 绑定的容器
|
||
- 创建 `BimDialog` 实例
|
||
- 应用当前主题
|
||
- 将弹窗添加到活跃列表
|
||
- 在 `onClose` 回调中自动从列表移除
|
||
|
||
**使用示例**:
|
||
```typescript
|
||
const dialog = engine.dialog.create({
|
||
title: '测试弹窗',
|
||
content: '这是内容',
|
||
width: 400,
|
||
height: 300
|
||
});
|
||
```
|
||
|
||
#### `showInfoDialog(): void`
|
||
显示二次封装的模型信息弹窗
|
||
|
||
**功能**:
|
||
- 创建 `BimInfoDialog` 实例
|
||
- 直接显示信息弹窗
|
||
|
||
**注意**: 此方法创建的弹窗不会自动加入管理列表(遗留逻辑)
|
||
|
||
#### `updateTheme(theme: ThemeConfig): void`
|
||
响应全局主题变更
|
||
|
||
**参数**:
|
||
- `theme`: `ThemeConfig` - 全局主题配置
|
||
|
||
**功能**:
|
||
- 遍历所有活跃弹窗
|
||
- 调用每个弹窗的 `setTheme()` 方法
|
||
|
||
#### `destroy(): void`
|
||
销毁管理器
|
||
|
||
**功能**:
|
||
- 销毁所有活跃弹窗
|
||
- 清空活跃列表
|
||
|
||
---
|
||
|
||
## 5. UI 详细描述
|
||
|
||
### 5.1 DOM 结构
|
||
|
||
**完整 HTML 结构**:
|
||
```html
|
||
<div class="bim-dialog" id="[可选ID]" style="[CSS变量和尺寸]">
|
||
<!-- 标题栏 -->
|
||
<div class="bim-dialog-header [draggable]">
|
||
<span class="bim-dialog-title">标题文本</span>
|
||
<span class="bim-dialog-close">×</span>
|
||
</div>
|
||
|
||
<!-- 内容区域 -->
|
||
<div class="bim-dialog-content">
|
||
<!-- 用户内容(HTML字符串或DOM元素) -->
|
||
</div>
|
||
|
||
<!-- 缩放手柄(如果 resizable) -->
|
||
<div class="bim-dialog-resize-handle"></div>
|
||
</div>
|
||
```
|
||
|
||
### 5.2 CSS 类名和样式
|
||
|
||
#### `.bim-dialog` (根元素)
|
||
- `position: absolute` - 绝对定位
|
||
- `background-color: var(--bim-dialog-bg)` - 背景色(CSS 变量)
|
||
- `border: 1px solid var(--bim-dialog-border-color)` - 边框
|
||
- `border-radius: 6px` - 圆角
|
||
- `box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3)` - 阴影
|
||
- `display: flex` + `flex-direction: column` - 垂直布局
|
||
- `z-index: 10001` - 层级(确保在 3D 引擎之上)
|
||
- `min-width: 200px` - 最小宽度
|
||
- `min-height: 100px` - 最小高度
|
||
- `pointer-events: auto` - 确保可接收事件
|
||
|
||
#### `.bim-dialog-header` (标题栏)
|
||
- `height: 32px` - 固定高度
|
||
- `background-color: var(--bim-dialog-header-bg)` - 背景色
|
||
- `display: flex` + `align-items: center` + `justify-content: space-between` - 水平布局
|
||
- `padding: 0 10px` - 内边距
|
||
- `cursor: default` - 默认光标
|
||
- `user-select: none` - 禁止选中
|
||
- `border-bottom: 1px solid var(--bim-dialog-border-color)` - 底边框
|
||
|
||
#### `.bim-dialog-header.draggable` (可拖拽标题栏)
|
||
- `cursor: move` - 移动光标
|
||
|
||
#### `.bim-dialog-title` (标题文本)
|
||
- `font-size: 14px` - 字体大小
|
||
- `font-weight: 500` - 字体粗细
|
||
- `white-space: nowrap` - 不换行
|
||
- `overflow: hidden` - 隐藏溢出
|
||
- `text-overflow: ellipsis` - 文本省略
|
||
- `color: var(--bim-dialog-title-color)` - 文字颜色
|
||
|
||
#### `.bim-dialog-close` (关闭按钮)
|
||
- `cursor: pointer` - 指针光标
|
||
- `font-size: 18px` - 字体大小
|
||
- `color: #999` - 默认颜色
|
||
- `line-height: 1` - 行高
|
||
- `margin-left: 8px` - 左边距
|
||
|
||
#### `.bim-dialog-close:hover` (关闭按钮悬停)
|
||
- `color: #fff` - 悬停颜色
|
||
|
||
#### `.bim-dialog-content` (内容区域)
|
||
- `flex: 1` - 占据剩余空间
|
||
- `padding: 10px` - 内边距
|
||
- `overflow: auto` - 内容溢出时滚动
|
||
- `font-size: 14px` - 字体大小
|
||
- `color: var(--bim-dialog-text-color)` - 文字颜色
|
||
|
||
#### `.bim-dialog-resize-handle` (缩放手柄)
|
||
- `position: absolute` - 绝对定位
|
||
- `width: 10px` + `height: 10px` - 尺寸
|
||
- `bottom: 0` + `right: 0` - 右下角位置
|
||
- `cursor: se-resize` - 缩放光标
|
||
- `z-index: 10` - 层级
|
||
|
||
#### `.bim-dialog-resize-handle::after` (缩放装饰)
|
||
- 使用伪元素创建右下角斜线装饰
|
||
- `border-right` + `border-bottom` - 创建斜线效果
|
||
|
||
### 5.3 CSS 变量
|
||
|
||
**定义位置**: `:root` 或元素内联样式
|
||
|
||
**变量列表**:
|
||
- `--bim-dialog-bg`: 窗体背景颜色(默认 `rgba(17, 17, 17, 0.95)`)
|
||
- `--bim-dialog-header-bg`: 标题栏背景颜色(默认 `#2a2a2a`)
|
||
- `--bim-dialog-title-color`: 标题文字颜色(默认 `#fff`)
|
||
- `--bim-dialog-text-color`: 内容文字颜色(默认 `#ccc`)
|
||
- `--bim-dialog-border-color`: 边框颜色(默认 `#444`)
|
||
|
||
### 5.4 交互行为
|
||
|
||
#### 拖拽
|
||
- **触发区域**: 标题栏(`.bim-dialog-header`)
|
||
- **触发条件**: `draggable: true`
|
||
- **行为**:
|
||
- 鼠标按下标题栏时开始拖拽
|
||
- 鼠标移动时弹窗跟随移动
|
||
- 鼠标释放时结束拖拽
|
||
- 弹窗位置限制在容器边界内
|
||
|
||
#### 缩放
|
||
- **触发区域**: 缩放手柄(`.bim-dialog-resize-handle`)
|
||
- **触发条件**: `resizable: true`
|
||
- **行为**:
|
||
- 鼠标按下缩放手柄时开始缩放
|
||
- 鼠标移动时弹窗尺寸跟随变化
|
||
- 鼠标释放时结束缩放
|
||
- 尺寸限制在最小尺寸以上
|
||
|
||
#### 关闭
|
||
- **触发方式**:
|
||
- 点击关闭按钮(`.bim-dialog-close`)
|
||
- 调用 `close()` 方法
|
||
- **行为**: 弹窗从 DOM 移除,调用 `onClose` 回调
|
||
|
||
### 5.5 响应式行为
|
||
|
||
- 弹窗位置会根据容器尺寸自动调整,确保不超出边界
|
||
- 内容区域支持滚动(`overflow: auto`)
|
||
- 标题文本过长时显示省略号(`text-overflow: ellipsis`)
|
||
|
||
---
|
||
|
||
## 6. 逻辑流程详细描述
|
||
|
||
### 6.1 初始化流程
|
||
|
||
1. **构造函数调用**:
|
||
- 合并配置选项(用户配置 + 默认配置)
|
||
- 调用 `createDom()` 创建 DOM 结构
|
||
- 保存 header 和 contentArea 引用
|
||
- 自动调用 `init()`
|
||
|
||
2. **init() 方法执行**:
|
||
- 检查是否已初始化,如果是则返回
|
||
- 将弹窗元素添加到容器
|
||
- 调用 `initPosition()` 计算并设置位置
|
||
- 如果 `draggable` 为 true,调用 `initDrag()`
|
||
- 如果 `resizable` 为 true,调用 `initResize()`
|
||
- 标记为已初始化
|
||
- 调用 `onOpen` 回调(如果存在)
|
||
- 订阅主题变更:`themeManager.subscribe()`
|
||
- 订阅语言变更:`localeManager.subscribe()`
|
||
|
||
### 6.2 生命周期
|
||
|
||
#### 创建阶段
|
||
- 构造函数 → `createDom()` → `init()`
|
||
|
||
#### 运行阶段
|
||
- 响应主题变更:`setTheme()` 被调用
|
||
- 响应语言变更:`setLocales()` 被调用
|
||
- 用户交互:拖拽、缩放、关闭
|
||
|
||
#### 销毁阶段
|
||
- `close()` 或 `destroy()` 被调用
|
||
- 清理 `requestAnimationFrame`
|
||
- 取消主题和语言订阅
|
||
- 从 DOM 移除元素
|
||
- 调用 `onClose` 回调
|
||
|
||
### 6.3 事件处理流程
|
||
|
||
#### 拖拽事件流程
|
||
1. 用户在标题栏按下鼠标 → `mousedown` 事件
|
||
2. 记录起始位置和弹窗当前位置
|
||
3. 缓存容器和弹窗尺寸
|
||
4. 在 document 上绑定 `mousemove` 和 `mouseup`(捕获阶段)
|
||
5. 鼠标移动时 → `mousemove` 事件
|
||
- 计算偏移量
|
||
- 使用 `requestAnimationFrame` 更新位置
|
||
- 限制在容器边界内
|
||
6. 鼠标释放时 → `mouseup` 事件
|
||
- 清理事件监听
|
||
- 清理动画帧
|
||
|
||
#### 缩放事件流程
|
||
1. 用户在缩放手柄按下鼠标 → `mousedown` 事件
|
||
2. 记录起始位置和弹窗当前尺寸
|
||
3. 在 document 上绑定 `mousemove` 和 `mouseup`(捕获阶段)
|
||
4. 鼠标移动时 → `mousemove` 事件
|
||
- 计算偏移量
|
||
- 使用 `requestAnimationFrame` 更新尺寸
|
||
- 限制在最小尺寸以上
|
||
5. 鼠标释放时 → `mouseup` 事件
|
||
- 清理事件监听
|
||
- 清理动画帧
|
||
|
||
#### 事件拦截流程
|
||
- 弹窗根元素上绑定所有鼠标/触摸事件
|
||
- 使用 `stopPropagation()` 阻止事件冒泡
|
||
- 防止事件传递给 3D 引擎
|
||
- 使用 `passive: false` 允许阻止默认行为
|
||
|
||
### 6.4 状态管理
|
||
|
||
#### 内部状态
|
||
- `_isInitialized`: 是否已初始化
|
||
- `_isDestroyed`: 是否已销毁
|
||
- `rafId`: `requestAnimationFrame` 的 ID(用于节流)
|
||
|
||
#### 订阅管理
|
||
- `unsubscribeTheme`: 主题订阅取消函数
|
||
- `unsubscribeLocale`: 语言订阅取消函数
|
||
|
||
### 6.5 与其他组件的交互
|
||
|
||
- **与 DialogManager**: 通过 Manager 创建和管理
|
||
- **与 ThemeManager**: 订阅主题变更
|
||
- **与 LocaleManager**: 订阅语言变更
|
||
- **与 3D 引擎**: 通过事件拦截防止交互冲突
|
||
|
||
---
|
||
|
||
## 7. 国际化支持
|
||
|
||
### 7.1 使用的翻译键
|
||
|
||
- `options.title`: 弹窗标题(如果提供,会通过 `t()` 函数翻译)
|
||
|
||
### 7.2 语言变更处理
|
||
|
||
- 组件订阅 `localeManager.subscribe()`
|
||
- 语言变更时,`setLocales()` 方法被调用
|
||
- 更新标题文本:`titleEl.textContent = t(this.options.title)`
|
||
|
||
### 7.3 实现细节
|
||
|
||
```typescript
|
||
public setLocales(): void {
|
||
if (this.options.title) {
|
||
const titleEl = this.header.querySelector('.bim-dialog-title');
|
||
if (titleEl) {
|
||
titleEl.textContent = t(this.options.title);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 主题支持
|
||
|
||
### 8.1 使用的主题变量
|
||
|
||
- `theme.panelBackground` → `--bim-dialog-bg`
|
||
- `theme.componentHover` → `--bim-dialog-header-bg`
|
||
- `theme.textPrimary` → `--bim-dialog-title-color` 和 `--bim-dialog-text-color`
|
||
- `theme.border` → `--bim-dialog-border-color`
|
||
|
||
### 8.2 主题变更处理
|
||
|
||
- 组件订阅 `themeManager.subscribe()`
|
||
- 主题变更时,`setTheme()` 方法被调用
|
||
- 如果用户未自定义颜色,使用主题颜色
|
||
- 如果用户已自定义颜色,保持用户自定义
|
||
|
||
### 8.3 实现细节
|
||
|
||
```typescript
|
||
public setTheme(theme: ThemeConfig) {
|
||
const style = this.element.style;
|
||
if (!this.options.backgroundColor)
|
||
style.setProperty('--bim-dialog-bg', theme.panelBackground);
|
||
if (!this.options.headerBackgroundColor)
|
||
style.setProperty('--bim-dialog-header-bg', theme.componentHover);
|
||
// ... 其他颜色映射
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 使用示例
|
||
|
||
### 9.1 基本使用(通过 Manager)
|
||
|
||
```typescript
|
||
import { BimEngine } from 'bim-engine-sdk';
|
||
|
||
const engine = new BimEngine('container');
|
||
|
||
// 创建简单弹窗
|
||
const dialog = engine.dialog.create({
|
||
title: 'dialog.testTitle', // 使用翻译键
|
||
content: '这是内容',
|
||
width: 400,
|
||
height: 300
|
||
});
|
||
|
||
// 创建可缩放弹窗
|
||
const resizableDialog = engine.dialog.create({
|
||
title: '可缩放弹窗',
|
||
content: '<div>内容</div>',
|
||
width: 500,
|
||
height: 400,
|
||
resizable: true,
|
||
draggable: true
|
||
});
|
||
|
||
// 创建自定义位置弹窗
|
||
const positionedDialog = engine.dialog.create({
|
||
title: '自定义位置',
|
||
content: '内容',
|
||
position: { x: 100, y: 100 },
|
||
width: 300,
|
||
height: 200
|
||
});
|
||
```
|
||
|
||
### 9.2 高级使用
|
||
|
||
```typescript
|
||
// 创建带自定义样式的弹窗
|
||
const styledDialog = engine.dialog.create({
|
||
title: '自定义样式',
|
||
content: '<div>内容</div>',
|
||
backgroundColor: 'rgba(100, 0, 0, 0.95)',
|
||
headerBackgroundColor: '#cc0000',
|
||
titleColor: '#ffffff',
|
||
textColor: '#ffcccc',
|
||
borderColor: '#ff6666',
|
||
width: 300,
|
||
height: 200
|
||
});
|
||
|
||
// 创建带回调的弹窗
|
||
const callbackDialog = engine.dialog.create({
|
||
title: '带回调',
|
||
content: '内容',
|
||
onOpen: () => {
|
||
console.log('弹窗已打开');
|
||
},
|
||
onClose: () => {
|
||
console.log('弹窗已关闭');
|
||
}
|
||
});
|
||
|
||
// 动态更新内容
|
||
const dynamicDialog = engine.dialog.create({
|
||
title: '动态内容',
|
||
content: '初始内容'
|
||
});
|
||
|
||
// 稍后更新内容
|
||
dynamicDialog.setContent('<div>新内容</div>');
|
||
```
|
||
|
||
### 9.3 使用信息弹窗
|
||
|
||
```typescript
|
||
// 通过 Manager 显示信息弹窗
|
||
engine.dialog.showInfoDialog();
|
||
|
||
// 通过事件总线打开(如果配置了监听)
|
||
engine.emit('ui:open-dialog', { id: 'info' });
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 实现细节(供 AI 重现)
|
||
|
||
### 10.1 关键算法
|
||
|
||
#### 位置计算算法
|
||
```typescript
|
||
// 计算居中位置
|
||
function calculateCenterPosition(containerWidth, containerHeight, dialogWidth, dialogHeight) {
|
||
return {
|
||
left: (containerWidth - dialogWidth) / 2,
|
||
top: (containerHeight - dialogHeight) / 2
|
||
};
|
||
}
|
||
|
||
// 边界限制算法
|
||
function clampPosition(left, top, containerWidth, containerHeight, dialogWidth, dialogHeight) {
|
||
return {
|
||
left: Math.max(0, Math.min(left, containerWidth - dialogWidth)),
|
||
top: Math.max(0, Math.min(top, containerHeight - dialogHeight))
|
||
};
|
||
}
|
||
```
|
||
|
||
#### 拖拽算法
|
||
```typescript
|
||
// 拖拽位置更新
|
||
function updateDragPosition(startX, startY, currentX, currentY, startLeft, startTop) {
|
||
const deltaX = currentX - startX;
|
||
const deltaY = currentY - startY;
|
||
return {
|
||
left: startLeft + deltaX,
|
||
top: startTop + deltaY
|
||
};
|
||
}
|
||
```
|
||
|
||
#### 缩放算法
|
||
```typescript
|
||
// 缩放尺寸更新
|
||
function updateResizeSize(startX, startY, currentX, currentY, startWidth, startHeight, minWidth, minHeight) {
|
||
const deltaX = currentX - startX;
|
||
const deltaY = currentY - startY;
|
||
return {
|
||
width: Math.max(minWidth, startWidth + deltaX),
|
||
height: Math.max(minHeight, startHeight + deltaY)
|
||
};
|
||
}
|
||
```
|
||
|
||
### 10.2 性能优化点
|
||
|
||
1. **requestAnimationFrame 节流**:
|
||
- 拖拽和缩放使用 `requestAnimationFrame` 节流更新
|
||
- 避免频繁的 DOM 操作
|
||
|
||
2. **尺寸缓存**:
|
||
- 拖拽开始时缓存容器和弹窗尺寸
|
||
- 减少 `getBoundingClientRect()` 调用
|
||
|
||
3. **事件捕获**:
|
||
- 使用 `capture: true` 确保事件在捕获阶段处理
|
||
- 即使内部元素阻止冒泡,也能捕获事件
|
||
|
||
4. **CSS 变量**:
|
||
- 使用 CSS 变量应用主题
|
||
- 主题变更时无需重新渲染 DOM
|
||
|
||
### 10.3 注意事项和边界情况
|
||
|
||
1. **容器尺寸为 0**:
|
||
- 位置计算时可能出现除零或负数
|
||
- 使用 `Math.max()` 确保位置不为负
|
||
|
||
2. **弹窗尺寸大于容器**:
|
||
- 位置计算时确保弹窗不超出容器
|
||
- 使用边界限制算法
|
||
|
||
3. **快速连续操作**:
|
||
- 使用 `rafId` 防止多个动画帧同时执行
|
||
- 确保动画帧正确清理
|
||
|
||
4. **事件清理**:
|
||
- 组件销毁时必须清理所有事件监听
|
||
- 必须取消主题和语言订阅
|
||
|
||
5. **事件拦截**:
|
||
- 必须拦截所有鼠标/触摸事件
|
||
- 防止事件传递给 3D 引擎
|
||
|
||
6. **翻译键处理**:
|
||
- 标题可能是翻译键或普通文本
|
||
- 只有翻译键才需要通过 `t()` 函数处理
|
||
|
||
---
|
||
|
||
## 11. 类型定义
|
||
|
||
### 11.1 DialogOptions
|
||
|
||
```typescript
|
||
interface DialogOptions extends DialogColors {
|
||
container: HTMLElement; // 弹窗挂载的父容器(必需)
|
||
title?: string; // 弹窗标题(可选,支持翻译键)
|
||
content?: HTMLElement | string; // 弹窗内容(可选)
|
||
width?: number | string; // 宽度(可选,默认 300)
|
||
height?: number | string; // 高度(可选,默认 'auto')
|
||
position?: DialogPosition; // 位置(可选,默认 'center')
|
||
draggable?: boolean; // 是否可拖拽(可选,默认 true)
|
||
resizable?: boolean; // 是否可缩放(可选,默认 false)
|
||
minWidth?: number; // 最小宽度(可选,默认 200)
|
||
minHeight?: number; // 最小高度(可选,默认 100)
|
||
onClose?: () => void; // 关闭回调(可选)
|
||
onOpen?: () => void; // 打开回调(可选)
|
||
id?: string; // 弹窗 ID(可选)
|
||
}
|
||
```
|
||
|
||
### 11.2 DialogPosition
|
||
|
||
```typescript
|
||
type DialogPosition =
|
||
| 'center'
|
||
| 'top-left' | 'top-center' | 'top-right'
|
||
| 'left-center' | 'right-center'
|
||
| 'bottom-left' | 'bottom-center' | 'bottom-right'
|
||
| { x: number; y: number };
|
||
```
|
||
|
||
### 11.3 DialogColors
|
||
|
||
```typescript
|
||
interface DialogColors {
|
||
backgroundColor?: string; // 窗体背景颜色
|
||
headerBackgroundColor?: string; // 标题栏背景颜色
|
||
titleColor?: string; // 标题文字颜色
|
||
textColor?: string; // 内容文字颜色
|
||
borderColor?: string; // 边框颜色
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 12. 文件清单
|
||
|
||
### 12.1 相关文件
|
||
|
||
- `src/components/dialog/index.ts` - 主组件类
|
||
- `src/components/dialog/index.type.ts` - 类型定义
|
||
- `src/components/dialog/index.css` - 样式文件
|
||
- `src/components/dialog/bimInfoDialog/index.ts` - 信息弹窗(分化组件)
|
||
- `src/components/dialog/bimInfoDialog/index.css` - 信息弹窗样式
|
||
- `src/managers/dialog-manager.ts` - 管理器类
|
||
|
||
### 12.2 依赖文件
|
||
|
||
- `src/types/component.ts` - IBimComponent 接口
|
||
- `src/themes/types.ts` - ThemeConfig 类型
|
||
- `src/services/theme.ts` - ThemeManager
|
||
- `src/services/locale.ts` - LocaleManager
|
||
|
||
---
|
||
|
||
## 13. 更新记录
|
||
|
||
| 日期 | 修改内容 | 修改人 |
|
||
|------|---------|--------|
|
||
| 2024-XX-XX | 初始创建 | AI Assistant |
|
||
|
||
---
|
||
|
||
**重要提醒**: 本文档必须与组件代码保持同步。任何组件修改都必须更新本文档!
|
||
|
||
|
||
|