Initial TrueGrowth source import
This commit is contained in:
266
docs/TOOL_TITLEBAR_DRAGGING.md
Normal file
266
docs/TOOL_TITLEBAR_DRAGGING.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# 工具标题栏拖动功能
|
||||
|
||||
## 问题描述
|
||||
|
||||
画布上的工具是通过 iframe 方式插入的,由于画布上的元素支持拖动,导致 iframe 内的页面无法正常点击和滚动。
|
||||
|
||||
## 解决方案
|
||||
|
||||
添加一个工具标题栏,将拖动功能只应用在标题栏上,iframe 页面可以正常操作。
|
||||
|
||||
## 实现细节
|
||||
|
||||
### 1. 标题栏结构 (`tool.generator.ts`)
|
||||
|
||||
添加了一个标题栏组件,包含以下元素:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 🔧 工具名称 [↻] │ ← 标题栏(可拖动)
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ iframe 内容区域 │ ← 可交互区域
|
||||
│ (可点击、滚动) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 标题栏功能:
|
||||
- **工具图标** (🔧): 视觉标识
|
||||
- **工具名称**: 显示工具的名称(来自 `element.metadata.name`)
|
||||
- **刷新按钮** (↻): 重新加载 iframe
|
||||
|
||||
### 2. 拖动逻辑修改
|
||||
|
||||
#### 原来的逻辑(有问题):
|
||||
```typescript
|
||||
// 整个工具元素都可拖动
|
||||
cursor: move;
|
||||
iframe.style.pointerEvents = 'none'; // iframe 无法交互
|
||||
```
|
||||
|
||||
#### 新的逻辑(修复后):
|
||||
```typescript
|
||||
// 只有标题栏可拖动
|
||||
titleBar.style.cursor = 'move';
|
||||
iframe.style.pointerEvents = 'auto'; // iframe 可以正常交互
|
||||
|
||||
// 碰撞检测只在标题栏和边缘生效
|
||||
function isHitToolElement(element, point) {
|
||||
const inTitleBar = y >= rect.y && y <= rect.y + 36;
|
||||
const nearEdge = /* 边缘检测 */;
|
||||
return inTitleBar || nearEdge;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 关键修改点
|
||||
|
||||
#### `tool.generator.ts` - 创建标题栏
|
||||
```typescript
|
||||
// 容器改为 flex 布局
|
||||
container.style.cssText = `
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
...
|
||||
`;
|
||||
|
||||
// 添加标题栏(36px 高)
|
||||
const titleBar = this.createTitleBar(element);
|
||||
titleBar.setAttribute('data-draggable', 'true');
|
||||
titleBar.style.cursor = 'move';
|
||||
|
||||
// iframe 启用交互
|
||||
iframe.style.pointerEvents = 'auto';
|
||||
```
|
||||
|
||||
#### `with-tool.ts` - 修改碰撞检测
|
||||
```typescript
|
||||
function isHitToolElement(element: PlaitTool, point: Point): boolean {
|
||||
const TITLEBAR_HEIGHT = 36;
|
||||
const EDGE_THRESHOLD = 8;
|
||||
|
||||
// 只有标题栏或边缘才算命中
|
||||
const inTitleBar = y >= rect.y && y <= rect.y + TITLEBAR_HEIGHT;
|
||||
const nearEdge = /* ... */;
|
||||
|
||||
return inTitleBar || nearEdge;
|
||||
}
|
||||
```
|
||||
|
||||
#### `tool.component.scss` - 样式更新
|
||||
```scss
|
||||
.plait-tool-titlebar {
|
||||
height: 36px;
|
||||
cursor: move;
|
||||
background: linear-gradient(180deg, #f5f5f5 0%, #ebebeb 100%);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(180deg, #f8f8f8 0%, #efefef 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.plait-tool-content iframe {
|
||||
pointer-events: auto; // 确保可交互
|
||||
}
|
||||
```
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. 拖动功能
|
||||
- ✅ 点击标题栏可以拖动整个工具
|
||||
- ✅ 点击边缘可以调整大小(resize)
|
||||
- ✅ 点击 iframe 内容不会触发拖动
|
||||
|
||||
### 2. 标题栏按钮
|
||||
|
||||
#### 刷新按钮 (↻)
|
||||
- 重新加载 iframe
|
||||
- 用于刷新工具内容
|
||||
|
||||
### 3. 视觉反馈
|
||||
|
||||
#### 普通状态
|
||||
- 浅灰色渐变背景
|
||||
- `cursor: move` 指示可拖动
|
||||
|
||||
#### Hover 状态
|
||||
- 背景变亮
|
||||
- 按钮显示 hover 效果
|
||||
|
||||
#### 选中状态
|
||||
- 标题栏变为浅蓝色
|
||||
- 边框高亮显示
|
||||
|
||||
#### 拖动状态
|
||||
- `cursor: grabbing`
|
||||
- 阴影增强
|
||||
|
||||
## 交互行为
|
||||
|
||||
### iframe 内容区域
|
||||
- ✅ **可以点击**:链接、按钮等元素正常响应
|
||||
- ✅ **可以滚动**:鼠标滚轮、触摸滚动都正常
|
||||
- ✅ **可以选择文本**:可以复制内容
|
||||
- ✅ **可以输入**:表单输入框正常工作
|
||||
|
||||
### 标题栏区域
|
||||
- ✅ **可以拖动**:鼠标按下并移动可拖动工具
|
||||
- ✅ **按钮可点击**:刷新、关闭按钮正常工作
|
||||
- ❌ **不能选择文本**:`user-select: none` 避免误选
|
||||
|
||||
### 边缘区域
|
||||
- ✅ **可以调整大小**:拖动边缘调整工具尺寸
|
||||
- ✅ **显示 resize 光标**:根据位置显示对应光标
|
||||
|
||||
## 代码结构
|
||||
|
||||
```
|
||||
packages/drawnix/src/
|
||||
├── components/tool-element/
|
||||
│ ├── tool.generator.ts # 修改:添加标题栏创建逻辑
|
||||
│ ├── tool.component.ts # 无修改
|
||||
│ └── tool.component.scss # 修改:添加标题栏样式
|
||||
└── plugins/
|
||||
└── with-tool.ts # 修改:碰撞检测逻辑
|
||||
```
|
||||
|
||||
## 测试方法
|
||||
|
||||
### 1. 拖动测试
|
||||
```
|
||||
1. 在画布上插入一个工具
|
||||
2. 点击标题栏并拖动 ✅ 应该可以移动
|
||||
3. 点击 iframe 内容 ❌ 不应该触发拖动
|
||||
```
|
||||
|
||||
### 2. iframe 交互测试
|
||||
```
|
||||
1. 在画布上插入一个工具(如 posemaniacs)
|
||||
2. 点击 iframe 内的链接 ✅ 应该跳转
|
||||
3. 滚动 iframe 内容 ✅ 应该正常滚动
|
||||
4. 选择 iframe 内文本 ✅ 应该可以选择
|
||||
```
|
||||
|
||||
### 3. 测试方法
|
||||
|
||||
```
|
||||
1. 点击刷新按钮 ✅ iframe 应该重新加载
|
||||
2. 按钮 hover ✅ 应该显示背景高亮
|
||||
```
|
||||
|
||||
### 4. 调整大小测试
|
||||
|
||||
```
|
||||
1. 移动鼠标到工具边缘
|
||||
2. 应该显示 resize 光标
|
||||
3. 拖动边缘调整大小 ✅ 应该正常工作
|
||||
```
|
||||
|
||||
## 兼容性
|
||||
|
||||
- ✅ Chrome/Edge: 完全支持
|
||||
- ✅ Firefox: 完全支持
|
||||
- ✅ Safari: 完全支持
|
||||
- ✅ 移动浏览器: 触摸拖动支持
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 1. 事件委托
|
||||
- 按钮事件使用 `stopPropagation()` 避免冒泡
|
||||
- 减少事件监听器数量
|
||||
|
||||
### 2. CSS 优化
|
||||
- 使用 CSS 渐变而非图片
|
||||
- 硬件加速的 transform 动画
|
||||
- 最小化重排/重绘
|
||||
|
||||
### 3. 内存管理
|
||||
- 组件销毁时移除事件监听
|
||||
- 及时清理 iframe 引用
|
||||
|
||||
## 已知限制
|
||||
|
||||
### 1. 标题栏高度固定
|
||||
- 当前固定为 36px
|
||||
- 未来可配置
|
||||
|
||||
### 2. 最小化功能未实现
|
||||
- 代码中已预留接口
|
||||
- 可在后续版本实现
|
||||
|
||||
### 3. 标题栏自定义
|
||||
- 当前样式固定
|
||||
- 未来可支持主题定制
|
||||
|
||||
## 未来改进
|
||||
|
||||
### 短期
|
||||
- [ ] 支持双击标题栏最大化/还原
|
||||
- [ ] 支持标题栏右键菜单
|
||||
- [ ] 支持拖拽标题栏到边缘吸附
|
||||
|
||||
### 中期
|
||||
- [ ] 支持最小化到托盘
|
||||
- [ ] 支持多窗口管理
|
||||
- [ ] 支持工具间通信
|
||||
|
||||
### 长期
|
||||
- [ ] 支持标题栏主题定制
|
||||
- [ ] 支持自定义标题栏按钮
|
||||
- [ ] 支持标题栏插件系统
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `packages/drawnix/src/components/tool-element/tool.generator.ts` - 标题栏创建
|
||||
- `packages/drawnix/src/components/tool-element/tool.component.scss` - 标题栏样式
|
||||
- `packages/drawnix/src/plugins/with-tool.ts` - 拖动逻辑
|
||||
- `packages/drawnix/src/types/toolbox.types.ts` - 类型定义
|
||||
|
||||
## 总结
|
||||
|
||||
通过添加标题栏并修改碰撞检测逻辑,成功解决了工具拖动与 iframe 交互冲突的问题:
|
||||
|
||||
✅ **拖动功能**:保留在标题栏和边缘
|
||||
✅ **iframe 交互**:完全恢复,可点击可滚动
|
||||
✅ **用户体验**:符合桌面应用习惯
|
||||
✅ **代码质量**:结构清晰,易于维护
|
||||
Reference in New Issue
Block a user