DockLayout 可停靠布局系统
项目概述
DockLayout 是一个基于 Vue 3 的可停靠布局系统,提供了灵活的面板管理、拖拽停靠、标签页切换、窗口调整大小等功能。该系统采用事件驱动架构,支持浮动面板、停靠面板、并排布局等多种布局模式,适用于需要复杂界面布局的应用场景。
核心特性
- 灵活的面板管理:支持浮动面板、停靠面板、标签页面板
- 拖拽停靠:支持面板拖拽到不同位置进行停靠
- 动态调整大小:支持通过拖拽边框或调整条改变面板大小
- 标签页系统:支持多标签页切换、拖拽重排
- 并排布局:支持面板并排显示,可动态调整比例
- 事件驱动架构:采用事件总线实现组件间通信
- 内存保护机制:自动清理过期资源,防止内存泄漏
- 性能监控:内置性能监控和集成测试框架
系统架构
整体架构
DockLayout
├── 核心组件层
│ ├── DockLayout.vue # 根组件,布局管理器
│ ├── Area.vue # 面板区容器
│ ├── TabPage.vue # 标签页容器
│ ├── Panel.vue # 面板组件
│ ├── Render.vue # 动态组件渲染器
│ ├── DockIndicator.vue # 停靠指示器
│ └── ResizeBar.vue # 调整条组件
├── 事件处理层
│ ├── DragStateManager.js # 拖拽状态管理
│ ├── EventBusManager.js # 事件总线管理
│ ├── AreaHandler.js # Area事件处理
│ ├── PanelHandler.js # Panel事件处理
│ ├── TabPageHandler.js # TabPage事件处理
│ ├── GlobalEventManager.js # 全局事件管理
│ └── IntegrationTester.js # 集成测试
├── 工具层
│ ├── eventBus.js # 增强事件总线
│ ├── dockLayers.js # Z-index层级管理
│ └── types.d.ts # TypeScript类型定义
└── 文档层
├── DockIndicator指示器命名约定.md
└── ToDoList.md
架构设计原则
- 分层架构:组件层、事件层、工具层清晰分离
- 事件驱动:所有组件间通信通过事件总线实现
- 单例模式:关键管理器采用单例模式确保全局唯一
- 内存保护:自动清理过期资源,防止内存泄漏
- 类型安全:使用TypeScript提供类型检查
- 可扩展性:模块化设计,易于扩展新功能
核心功能模块
1. 布局管理模块
功能:
- 管理所有浮动面板和隐藏面板
- 提供面板添加、移除、查找接口
- 协调组件间的事件通信
- 资源清理和生命周期管理
核心接口:
{
// 数据
floatingAreas: ref([]), // 浮动面板列表
hiddenAreas: ref([]), // 隐藏面板列表
// 方法
addFloatingPanel(panel), // 添加浮动面板
findOrCreateMainAreaTabPage(), // 查找或创建主区域标签页
handleDockingEnding(), // 停靠结束处理
handleEdgeDocking(), // 边缘停靠处理
handleSideBySideDocking(), // 并排停靠处理
}
2. 面板区模块
组件:Area.vue
功能:
- 面板区容器,支持浮动和停靠两种模式
- 拖拽移动(带边界约束)
- 调整大小(8个方向)
- 最大化/还原/关闭
- 单面板时显示标题栏
核心特性:
- 初始尺寸:300px × 250px,居中显示
- 最大化时填充父容器
- 拖拽时不超出父容器边界
- 支持边框拖拽改变大小
- 单面板时标题栏与Panel联动
事件系统:
EVENT_TYPES = {
AREA_DRAG_START, // 面板拖拽开始
AREA_DRAG_MOVE, // 面板拖拽移动
AREA_DRAG_END, // 面板拖拽结束
AREA_RESIZE_START, // 面板调整开始
AREA_RESIZE_MOVE, // 面板调整移动
AREA_RESIZE_END, // 面板调整结束
AREA_MAXIMIZE, // 面板最大化
AREA_RESTORE, // 面板还原
AREA_CLOSE, // 面板关闭
AREA_POSITION_UPDATE, // 面板位置更新
}
3. 标签页模块
组件:TabPage.vue
功能:
- 多标签页容器
- 标签页切换
- 标签页拖拽重排
- 标签页关闭
- 支持4个方向(上/右/下/左)
样式特性:
- 背景颜色:#5D6B99
- 激活标签:#F5CC84,文字黑色
- 未激活标签:与Area背景相同,文字白色
- 激活标签不显示关闭按钮
- 激活标签鼠标显示移动,否则显示手型
方向支持:
top:标签在上方(默认)right:标签在右侧bottom:标签在下方left:标签在左侧
4. 面板模块
组件:Panel.vue
功能:
- 单个面板内容容器
- 填充父容器
- 最大化/还原
- 拖拽(单面板时拖动标题栏相当于拖动Area)
核心特性:
- 始终填充父容器
- 最大化时图标变为还原图标
- 单面板时与Area标题栏联动
5. 停靠指示器模块
功能:
- 提供可视化的停靠位置指示
- 支持全局边缘停靠
- 支持中心区域停靠
- 支持子区域停靠
- 动态显示停靠预览
指示器分类:
-
外部边缘指示器(全局停靠)
global-top-indicator:全局顶部global-right-indicator:全局右侧global-bottom-indicator:全局底部global-left-indicator:全局左侧
-
中心区域指示器
center-dock-zone:中心停靠区center-edge-top:中心上边缘center-edge-right:中心右边缘center-edge-bottom:中心下边缘center-edge-left:中心左边缘
-
子区域指示器
center-top-area:中心上方区域center-right-area:中心右侧区域center-bottom-area:中心下方区域center-left-area:中心左侧区域
-
独立中心指示器
center-main-indicator:独立中心指示器(z-index: 10000)
命名约定:详见 DockIndicator指示器命名约定.md
6. 调整条模块
功能:
- 在并排布局中提供尺寸调整功能
- 支持水平和垂直两种方向
- 实时调整面板大小
- 支持最小/最大尺寸限制
事件系统:
EVENT_TYPES = {
RESIZE_START, // 调整开始
RESIZE_MOVE, // 调整移动
RESIZE_END, // 调整结束
}
使用场景:
- 外部边缘停靠后的并排布局
- 两个Area之间的尺寸调整
- 保持比例总和为1
7. 拖拽状态管理模块
功能:
- 管理拖拽状态
- 跟踪拖拽位置和速度
- 冲突检测和解决
- 性能监控
核心功能:
class DragStateManager {
// 状态管理
startDrag(dragId, source, position)
updateDrag(dragId, position)
endDrag(dragId)
// 冲突检测
checkConflict(dragId)
resolveConflict(dragId, conflictId)
// 性能监控
startPerformanceMonitor(operation)
endPerformanceMonitor(monitorId)
}
8. 事件总线管理模块
功能:
- 统一事件路由和分发
- 全局错误处理
- 事件去重
- 性能监控
核心功能:
class EventBusManager {
// 事件管理
registerEventRoute(eventType, handler)
unregisterEventRoute(eventType)
routeEvent(eventType, data)
// 监控
startMonitoring(eventId, eventData)
completeMonitoring(eventId)
getExecutionStats()
}
9. 全局事件管理模块
功能:
- 系统级事件管理
- 跨组件通信
- 事件链执行
- 性能监控和告警
核心功能:
class GlobalEventManager {
// 系统事件
handleSystemInit(data)
handleSystemError(data)
handlePerformanceThresholdExceeded(data)
// 跨组件通信
broadcast(message, data, targetComponents)
request(targetComponent, action, payload)
// 事件链
createEventChain(chainName, events)
getEventChainStatus()
}
10. Area事件处理模块
处理器:AreaHandler.js
功能:
- 处理Area相关事件
- Area状态管理
- 停靠逻辑实现
- 并排布局创建
核心功能:
class AreaHandler {
// Area管理
handleAreaCreated(data)
handleAreaDestroyed(data)
handleAreaDragStart(data)
handleAreaDragEnd(data)
// 停靠逻辑
handleEdgeDocking(data)
handleSideBySideDocking(data)
createSideBySideLayout(sourceArea, targetArea, direction)
}
11. Panel事件处理模块
处理器:PanelHandler.js
功能:
- 处理Panel相关事件
- Panel状态管理
- Panel生命周期管理
核心功能:
class PanelHandler {
// Panel管理
handlePanelCreated(data)
handlePanelDestroyed(data)
handlePanelDragStart(data)
handlePanelDragEnd(data)
// 状态管理
getPanelState(panelId)
updatePanelState(panelId, updates)
}
12. TabPage事件处理模块
功能:
- 处理TabPage相关事件
- TabPage状态管理
- 标签页拖拽和切换
- 标签页组合并
核心功能:
class TabPageHandler {
// TabPage管理
handleTabPageCreated(data)
handleTabPageDestroyed(data)
handleTabPageDragStart(data)
handleTabPageDragEnd(data)
// 标签页操作
handleTabPageSwitch(data)
handleTabPageCloseRequest(data)
handleTabPageGroupMerge(data)
}
13. 集成测试模块
功能:
- 集成测试框架
- 性能监控
- 测试报告生成
核心功能:
class IntegrationTester {
// 测试执行
runTestSuite(testSuite)
runSingleTest(testCase)
// 性能监控
startPerformanceMonitor()
endPerformanceMonitor()
getPerformanceStats()
}
关键技术栈及依赖
核心技术栈
-
Vue 3:渐进式JavaScript框架
- Composition API
- 响应式系统
- 组件化开发
-
TypeScript:JavaScript超集
- 类型安全
- 接口定义
- 类型推断
-
Vite:下一代前端构建工具
- 快速热更新
- 优化的生产构建
- 原生ES模块支持
依赖库
根据项目package.json分析:
{
"dependencies": {
"vue": "^3.x.x",
"pinia": "^2.x.x" // 状态管理
},
"devDependencies": {
"vite": "^5.x.x",
"typescript": "^5.x.x"
}
}
内部依赖
DockLayout模块内部依赖:
- eventBus.js:增强事件总线
- dockLayers.js:Z-index层级管理
- types.d.ts:类型定义
项目目录结构
DockLayout/
├── handlers/ # 事件处理器目录
│ ├── DragStateManager.js # 拖拽状态管理器
│ ├── EventBusManager.js # 事件总线管理器
│ ├── AreaHandler.js # Area事件处理器
│ ├── PanelHandler.js # Panel事件处理器
│ ├── TabPageHandler.js # TabPage事件处理器
│ ├── GlobalEventManager.js # 全局事件管理器
│ └── IntegrationTester.js # 集成测试器
├── Area.vue # 面板区组件
├── DockIndicator.vue # 停靠指示器组件
├── DockLayout.vue # 根组件
├── Panel.vue # 面板组件
├── Render.vue # 动态组件渲染器
├── ResizeBar.vue # 调整条组件
├── TabPage.vue # 标签页组件
├── dockLayers.js # Z-index层级管理
├── eventBus.js # 增强事件总线
├── types.d.ts # TypeScript类型定义
├── DockIndicator指示器命名约定.md # 指示器命名约定文档
└── ToDoList.md # 待办事项文档
组件设计
组件层次结构
DockLayout (根组件)
├── Render (动态组件渲染器)
│ ├── Area (面板区)
│ │ ├── TabPage (标签页)
│ │ │ └── Panel (面板)
│ │ └── ResizeBar (调整条)
│ └── DockIndicator (停靠指示器)
组件通信机制
- 父子通信:props和emit
- 兄弟通信:事件总线(eventBus)
- 跨层级通信:事件总线(eventBus)
- 全局通信:全局事件管理器(GlobalEventManager)
组件生命周期
-
创建阶段:
- 组件初始化
- 事件监听器注册
- 状态初始化
-
运行阶段:
- 事件处理
- 状态更新
- UI渲染
-
销毁阶段:
- 事件监听器清理
- 状态清理
- 资源释放
事件系统
事件总线架构
DockLayout采用增强的事件总线系统,支持以下特性:
- 优先级队列:事件按优先级处理
- 去重机制:防止重复事件
- 性能监控:跟踪事件处理时间
- 错误处理:全局错误捕获
事件分类
1. 系统级事件
GLOBAL_EVENT_TYPES = {
SYSTEM_INIT: 'system.init',
SYSTEM_READY: 'system.ready',
SYSTEM_DESTROY: 'system.destroy',
SYSTEM_ERROR: 'system.error',
SYSTEM_PERFORMANCE: 'system.performance',
}
2. Area事件
AREA_EVENT_TYPES = {
AREA_CREATED: 'area.created',
AREA_DESTROYED: 'area.destroyed',
AREA_DRAG_START: 'area.drag.start',
AREA_DRAG_MOVE: 'area.drag.move',
AREA_DRAG_END: 'area.drag.end',
AREA_RESIZE_START: 'area.resize.start',
AREA_RESIZE_MOVE: 'area.resize.move',
AREA_RESIZE_END: 'area.resize.end',
AREA_MAXIMIZE: 'area.maximize',
AREA_RESTORE: 'area.restore',
AREA_CLOSE: 'area.close',
AREA_POSITION_UPDATE: 'area.position.update',
}
3. Panel事件
PANEL_EVENT_TYPES = {
PANEL_CREATED: 'panel.created',
PANEL_DESTROYED: 'panel.destroyed',
PANEL_DRAG_START: 'panel.drag.start',
PANEL_DRAG_MOVE: 'panel.drag.move',
PANEL_DRAG_END: 'panel.drag.end',
PANEL_MAXIMIZE: 'panel.maximize',
PANEL_RESTORE: 'panel.restore',
PANEL_CLOSE: 'panel.close',
}
4. TabPage事件
TABPAGE_EVENT_TYPES = {
TABPAGE_CREATED: 'tabPage.created',
TABPAGE_DESTROYED: 'tabPage.destroyed',
TABPAGE_SWITCH: 'tabPage.switch',
TABPAGE_CLOSE_REQUEST: 'tabPage.close.request',
TABPAGE_CLOSE: 'tabPage.close',
TABPAGE_DRAG_START: 'tabPage.drag.start',
TABPAGE_DRAG_MOVE: 'tabPage.drag.move',
TABPAGE_DRAG_END: 'tabPage.drag.end',
TABPAGE_GROUP_MERGE: 'tabPage.group.merge',
TABPAGE_ACTIVATED: 'tabPage.activated',
TABPAGE_DEACTIVATED: 'tabPage.deactivated',
}
5. ResizeBar事件
RESIZE_EVENT_TYPES = {
RESIZE_START: 'resize.start',
RESIZE_MOVE: 'resize.move',
RESIZE_END: 'resize.end',
}
事件流程示例
面板拖拽流程
1. 用户开始拖拽面板
↓
2. Panel触发 PANEL_DRAG_START 事件
↓
3. DragStateManager记录拖拽状态
↓
4. EventBusManager路由事件到相关处理器
↓
5. AreaHandler处理拖拽逻辑
↓
6. DockIndicator显示停靠指示器
↓
7. 用户拖拽面板移动
↓
8. Panel触发 PANEL_DRAG_MOVE 事件
↓
9. 更新拖拽状态和UI
↓
10. 用户释放面板
↓
11. Panel触发 PANEL_DRAG_END 事件
↓
12. 执行停靠逻辑(如果停靠到指示器)
↓
13. 清理拖拽状态
类型定义
核心类型
文件:types.d.ts
1. 面板位置类型
export type PanelPosition = 'left' | 'right' | 'top' | 'bottom' | 'center' | 'floating';
2. 面板元数据
export interface PanelMeta {
id: string;
title: string;
icon?: string;
component?: unknown;
initialPosition?: PanelPosition;
tags?: string[];
flags?: { collapsed?: boolean; floating?: boolean };
}
3. 面板区
export interface PanelArea {
id: string;
parentAreaId?: string;
position: PanelPosition;
subAreas: SubArea[];
activeTabIndex?: number;
influence: InfluenceEntry[];
influencedBy: InfluenceEntry[];
pendingUpdates: Set<string>;
x: number;
y: number;
width: number;
height: number;
widthRatios: number;
heightRatios: number;
}
4. 子面板区
export interface SubArea {
id: string;
position: PanelPosition;
panels: Panel[];
activePanelId?: string;
}
5. 面板
export interface Panel {
id: string;
title: string;
component?: unknown;
isMaximized: boolean;
isMinimized: boolean;
}
测试和监控
集成测试
测试配置
TEST_CONFIG = {
performanceThresholds: {
eventEmitTime: 10, // 事件发射时间阈值(毫秒)
eventHandleTime: 50, // 事件处理时间阈值(毫秒)
memoryUsage: 50 * 1024 * 1024, // 内存使用阈值(50MB)
cpuUsage: 80, // CPU使用率阈值(%)
dragFPS: 30, // 拖拽帧率阈值
dragDuration: 3000, // 拖拽持续时间阈值(毫秒)
concurrentEvents: 100 // 并发事件数量阈值
},
testCases: {
panel: {
createPanel: { priority: 1, timeout: 5000 },
destroyPanel: { priority: 1, timeout: 5000 },
maximizePanel: { priority: 1, timeout: 3000 },
minimizePanel: { priority: 1, timeout: 3000 },
restorePanel: { priority: 1, timeout: 3000 },
closePanel: { priority: 1, timeout: 5000 }
},
tabPage: {
createTabPage: { priority: 1, timeout: 5000 },
switchTabPage: { priority: 1, timeout: 3000 },
closeTabPage: { priority: 1, timeout: 5000 },
mergeTabPage: { priority: 1, timeout: 5000 }
},
area: {
createArea: { priority: 1, timeout: 5000 },
dragArea: { priority: 1, timeout: 5000 },
resizeArea: { priority: 1, timeout: 5000 },
maximizeArea: { priority: 1, timeout: 3000 },
restoreArea: { priority: 1, timeout: 3000 }
},
drag: {
startDrag: { priority: 1, timeout: 3000 },
moveDrag: { priority: 1, timeout: 5000 },
endDrag: { priority: 1, timeout: 3000 },
dockToEdge: { priority: 1, timeout: 5000 },
dockToCenter: { priority: 1, timeout: 5000 }
}
}
}
性能监控
class PerformanceMonitor {
start() // 开始监控
stop() // 停止监控
recordMetric(name, value) // 记录指标
getMetrics() // 获取指标
checkThresholds() // 检查阈值
}
内存保护
所有处理器都实现了内存保护机制:
- 自动清理:定期清理过期数据
- 数量限制:限制最大对象数量
- 历史清理:限制历史记录大小
- 泄漏检测:检测和报告内存泄漏
使用指南
基本使用
1. 添加浮动面板
import { ref } from 'vue';
const floatingAreas = ref([]);
// 添加浮动面板
const addFloatingPanel = (panel) => {
floatingAreas.value.push({
id: `area-${Date.now()}`,
x: 100,
y: 100,
width: 300,
height: 250,
panels: [panel]
});
};
2. 创建面板
const panel = {
id: 'panel-1',
title: '示例面板',
component: 'ExampleComponent'
};
3. 监听事件
import { eventBus } from './eventBus';
// 监听面板拖拽开始
eventBus.on('panel.drag.start', (data) => {
console.log('面板拖拽开始:', data);
});
// 监听面板停靠
eventBus.on('panel.dock', (data) => {
console.log('面板停靠:', data);
});
高级使用
1. 自定义停靠逻辑
import { eventBus } from './eventBus';
// 监听停靠事件
eventBus.on('panel.dock', (data) => {
const { panel, targetArea, position } = data;
// 自定义停靠逻辑
if (position === 'center') {
// 中心停靠逻辑
} else if (position === 'edge') {
// 边缘停靠逻辑
}
});
2. 性能监控
import { getIntegrationTester } from './handlers/IntegrationTester';
const tester = getIntegrationTester();
// 开始性能监控
tester.startPerformanceMonitor();
// 执行测试
await tester.runTestSuite('panel');
// 获取性能报告
const report = tester.getPerformanceReport();
console.log(report);
3. 自定义事件处理器
import { eventBus } from './eventBus';
// 注册自定义事件处理器
eventBus.on('custom.event', (data) => {
console.log('自定义事件:', data);
}, {
priority: 1,
deduplication: { type: 'TTL_BASED', ttl: 100 }
});
最佳实践
1. 组件开发
- 使用Composition API编写组件
- 遵循单一职责原则
- 合理拆分组件
- 使用TypeScript提供类型安全
2. 事件处理
- 使用事件总线进行组件通信
- 合理设置事件优先级
- 启用事件去重
- 及时清理事件监听器
3. 性能优化
- 避免频繁的状态更新
- 使用computed缓存计算结果
- 合理使用v-show和v-if
- 及时清理过期数据
4. 内存管理
- 在组件卸载时清理资源
- 使用单例模式避免重复创建
- 定期清理过期数据
- 监控内存使用情况
5. 错误处理
- 使用try-catch捕获错误
- 记录错误日志
- 提供友好的错误提示
- 实现错误恢复机制
常见问题
Q1: 如何添加自定义面板?
A: 创建面板组件,然后在DockLayout中添加浮动面板或停靠面板。
const customPanel = {
id: 'custom-panel',
title: '自定义面板',
component: CustomPanelComponent
};
Q2: 如何实现自定义停靠逻辑?
A: 监听停靠事件,在事件处理器中实现自定义逻辑。
eventBus.on('panel.dock', (data) => {
// 自定义停靠逻辑
});
Q3: 如何优化性能?
A:
- 使用事件去重
- 及时清理过期数据
- 避免频繁的状态更新
- 使用性能监控工具
Q4: 如何处理内存泄漏?
A:
- 在组件卸载时清理事件监听器
- 使用单例模式避免重复创建
- 定期清理过期数据
- 使用内存监控工具
Q5: 如何调试事件?
A:
- 启用调试模式
- 使用事件监控工具
- 查看事件日志
- 使用浏览器开发者工具
更新日志
v1.8
- 修正DockIndicator文档,移除不准确的描述
- 增强中文沟通用词建议
- 修正独立中心指示器z-index为10000
v1.7
- 实现将中心指示器移到与中心区域容器同级
- 保持中心指示器位置相对于中心区域容器正中央
- 更新层级结构图
v1.6
- 根据实际代码情况更新文档结构
- 移除独立中心指示器相关内容
- 更新层级结构图
v1.3
- 添加独立中心指示器相关命名约定
- 更新层级结构图
- 更新中文沟通用词建议
v1.2
- 添加子区域指示器功能实现记录
- 更新文档以反映半透明依靠区功能的完成状态
v1.1
- 修正层级结构图,添加完整的外部边缘指示器
- 在层级结构图中标注当前实际使用的类名
- 完善命名体系的一致性
v1.0
- 初始版本,建立基础命名约定体系
贡献指南
欢迎贡献代码、报告问题或提出改进建议。
开发环境
- 克隆项目
- 安装依赖:
npm install - 启动开发服务器:
npm run dev - 运行测试:
npm run test
代码规范
- 使用ESLint进行代码检查
- 使用Prettier进行代码格式化
- 遵循Vue 3风格指南
- 编写单元测试和集成测试
提交规范
- 使用清晰的提交信息
- 遵循Conventional Commits规范
- 提交前运行测试
- 更新相关文档
许可证
本项目采用 MIT 许可证。
联系方式
如有问题或建议,请联系项目维护者。
文档版本:v1.0
创建日期:2024年
最后更新:2024年
适用范围:DockLayout 可停靠布局系统