Files
JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout

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

架构设计原则

  1. 分层架构:组件层、事件层、工具层清晰分离
  2. 事件驱动:所有组件间通信通过事件总线实现
  3. 单例模式:关键管理器采用单例模式确保全局唯一
  4. 内存保护:自动清理过期资源,防止内存泄漏
  5. 类型安全使用TypeScript提供类型检查
  6. 可扩展性:模块化设计,易于扩展新功能

核心功能模块

1. 布局管理模块

组件DockLayout.vue

功能

  • 管理所有浮动面板和隐藏面板
  • 提供面板添加、移除、查找接口
  • 协调组件间的事件通信
  • 资源清理和生命周期管理

核心接口

{
  // 数据
  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. 停靠指示器模块

组件DockIndicator.vue

功能

  • 提供可视化的停靠位置指示
  • 支持全局边缘停靠
  • 支持中心区域停靠
  • 支持子区域停靠
  • 动态显示停靠预览

指示器分类

  1. 外部边缘指示器(全局停靠)

    • global-top-indicator:全局顶部
    • global-right-indicator:全局右侧
    • global-bottom-indicator:全局底部
    • global-left-indicator:全局左侧
  2. 中心区域指示器

    • center-dock-zone:中心停靠区
    • center-edge-top:中心上边缘
    • center-edge-right:中心右边缘
    • center-edge-bottom:中心下边缘
    • center-edge-left:中心左边缘
  3. 子区域指示器

    • center-top-area:中心上方区域
    • center-right-area:中心右侧区域
    • center-bottom-area:中心下方区域
    • center-left-area:中心左侧区域
  4. 独立中心指示器

    • center-main-indicator独立中心指示器z-index: 10000

命名约定:详见 DockIndicator指示器命名约定.md

6. 调整条模块

组件ResizeBar.vue

功能

  • 在并排布局中提供尺寸调整功能
  • 支持水平和垂直两种方向
  • 实时调整面板大小
  • 支持最小/最大尺寸限制

事件系统

EVENT_TYPES = {
  RESIZE_START,    // 调整开始
  RESIZE_MOVE,     // 调整移动
  RESIZE_END,      // 调整结束
}

使用场景

  • 外部边缘停靠后的并排布局
  • 两个Area之间的尺寸调整
  • 保持比例总和为1

7. 拖拽状态管理模块

处理器DragStateManager.js

功能

  • 管理拖拽状态
  • 跟踪拖拽位置和速度
  • 冲突检测和解决
  • 性能监控

核心功能

class DragStateManager {
  // 状态管理
  startDrag(dragId, source, position)
  updateDrag(dragId, position)
  endDrag(dragId)
  
  // 冲突检测
  checkConflict(dragId)
  resolveConflict(dragId, conflictId)
  
  // 性能监控
  startPerformanceMonitor(operation)
  endPerformanceMonitor(monitorId)
}

8. 事件总线管理模块

处理器EventBusManager.js

功能

  • 统一事件路由和分发
  • 全局错误处理
  • 事件去重
  • 性能监控

核心功能

class EventBusManager {
  // 事件管理
  registerEventRoute(eventType, handler)
  unregisterEventRoute(eventType)
  routeEvent(eventType, data)
  
  // 监控
  startMonitoring(eventId, eventData)
  completeMonitoring(eventId)
  getExecutionStats()
}

9. 全局事件管理模块

处理器GlobalEventManager.js

功能

  • 系统级事件管理
  • 跨组件通信
  • 事件链执行
  • 性能监控和告警

核心功能

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事件处理模块

处理器TabPageHandler.js

功能

  • 处理TabPage相关事件
  • TabPage状态管理
  • 标签页拖拽和切换
  • 标签页组合并

核心功能

class TabPageHandler {
  // TabPage管理
  handleTabPageCreated(data)
  handleTabPageDestroyed(data)
  handleTabPageDragStart(data)
  handleTabPageDragEnd(data)
  
  // 标签页操作
  handleTabPageSwitch(data)
  handleTabPageCloseRequest(data)
  handleTabPageGroupMerge(data)
}

13. 集成测试模块

处理器IntegrationTester.js

功能

  • 集成测试框架
  • 性能监控
  • 测试报告生成

核心功能

class IntegrationTester {
  // 测试执行
  runTestSuite(testSuite)
  runSingleTest(testCase)
  
  // 性能监控
  startPerformanceMonitor()
  endPerformanceMonitor()
  getPerformanceStats()
}

关键技术栈及依赖

核心技术栈

  • Vue 3渐进式JavaScript框架

    • Composition API
    • 响应式系统
    • 组件化开发
  • TypeScriptJavaScript超集

    • 类型安全
    • 接口定义
    • 类型推断
  • Vite:下一代前端构建工具

    • 快速热更新
    • 优化的生产构建
    • 原生ES模块支持

依赖库

根据项目package.json分析

{
  "dependencies": {
    "vue": "^3.x.x",
    "pinia": "^2.x.x"           // 状态管理
  },
  "devDependencies": {
    "vite": "^5.x.x",
    "typescript": "^5.x.x"
  }
}

内部依赖

DockLayout模块内部依赖

项目目录结构

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 (停靠指示器)

组件通信机制

  1. 父子通信props和emit
  2. 兄弟通信事件总线eventBus
  3. 跨层级通信事件总线eventBus
  4. 全局通信全局事件管理器GlobalEventManager

组件生命周期

  1. 创建阶段

    • 组件初始化
    • 事件监听器注册
    • 状态初始化
  2. 运行阶段

    • 事件处理
    • 状态更新
    • UI渲染
  3. 销毁阶段

    • 事件监听器清理
    • 状态清理
    • 资源释放

事件系统

事件总线架构

DockLayout采用增强的事件总线系统支持以下特性

  1. 优先级队列:事件按优先级处理
  2. 去重机制:防止重复事件
  3. 性能监控:跟踪事件处理时间
  4. 错误处理:全局错误捕获

事件分类

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;
}

测试和监控

集成测试

文件IntegrationTester.js

测试配置

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. 自动清理:定期清理过期数据
  2. 数量限制:限制最大对象数量
  3. 历史清理:限制历史记录大小
  4. 泄漏检测:检测和报告内存泄漏

使用指南

基本使用

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

  • 初始版本,建立基础命名约定体系

贡献指南

欢迎贡献代码、报告问题或提出改进建议。

开发环境

  1. 克隆项目
  2. 安装依赖:npm install
  3. 启动开发服务器:npm run dev
  4. 运行测试:npm run test

代码规范

  • 使用ESLint进行代码检查
  • 使用Prettier进行代码格式化
  • 遵循Vue 3风格指南
  • 编写单元测试和集成测试

提交规范

  • 使用清晰的提交信息
  • 遵循Conventional Commits规范
  • 提交前运行测试
  • 更新相关文档

许可证

本项目采用 MIT 许可证。

联系方式

如有问题或建议,请联系项目维护者。


文档版本v1.0
创建日期2024年
最后更新2024年
适用范围DockLayout 可停靠布局系统