解决事件泄漏问题

This commit is contained in:
zqm
2025-12-26 13:09:35 +08:00
parent efa9fd64c7
commit 7f2f31156f
13 changed files with 924 additions and 1098 deletions

View File

@@ -3,9 +3,9 @@
* 专门处理Area相关的所有事件包括浮动区域管理、拖拽、停靠、合并等
*/
import { eventBus } from '../eventBus';
import { eventBus, EVENT_TYPES } from '../eventBus';
// Area事件类型常量
// Area事件类型常量仅包含EVENT_TYPES中没有的
export const AREA_EVENT_TYPES = {
// 基础事件
AREA_CREATED: 'area.created',
@@ -23,16 +23,8 @@ export const AREA_EVENT_TYPES = {
AREA_RESTORE: 'area.restore',
AREA_COLLAPSE: 'area.collapse',
AREA_EXPAND: 'area.expand',
AREA_CLOSE: 'area.close',
AREA_TOGGLE_TOOLBAR: 'area.toggleToolbar',
// 拖拽相关
AREA_DRAG_START: 'area.drag.start',
AREA_DRAG_MOVE: 'area.drag.move',
AREA_DRAG_END: 'area.drag.end',
AREA_DRAG_OVER: 'area.drag.over',
AREA_DRAG_LEAVE: 'area.drag.leave',
// 停靠相关
AREA_DOCK_CENTER: 'area.dock.center',
AREA_DOCK_EDGE: 'area.dock.edge',
@@ -759,12 +751,36 @@ class AreaEventHandler {
* 注册事件监听器
*/
_registerEventListeners() {
const events = Object.values(AREA_EVENT_TYPES);
events.forEach(eventType => {
// 监听 EVENT_TYPES 中的事件
const eventTypes = [
EVENT_TYPES.AREA_DRAG_START,
EVENT_TYPES.AREA_DRAG_MOVE,
EVENT_TYPES.AREA_DRAG_END,
EVENT_TYPES.AREA_DRAG_OVER,
EVENT_TYPES.AREA_DRAG_LEAVE,
EVENT_TYPES.AREA_CLOSE,
EVENT_TYPES.AREA_POSITION_UPDATE,
EVENT_TYPES.AREA_PANEL_CLOSED
];
eventTypes.forEach(eventType => {
const listener = this._onAreaEvent;
eventBus.on(eventType, listener, {
priority: 1,
deduplication: { type: 'TTL_BASED', ttl: 100 }
deduplication: { type: 'TTL_BASED', ttl: 100 },
componentId: 'area-handler'
});
this.areaListeners.set(eventType, listener);
});
// 监听 AREA_EVENT_TYPES 中的事件
const areaEventTypes = Object.values(AREA_EVENT_TYPES);
areaEventTypes.forEach(eventType => {
const listener = this._onAreaEvent;
eventBus.on(eventType, listener, {
priority: 1,
deduplication: { type: 'TTL_BASED', ttl: 100 },
componentId: 'area-handler'
});
this.areaListeners.set(eventType, listener);
});
@@ -775,17 +791,17 @@ class AreaEventHandler {
* @param {Object} data - 事件数据
*/
async _onAreaEvent(data) {
const { eventType } = data;
const eventType = data.eventType;
try {
switch (eventType) {
case AREA_EVENT_TYPES.AREA_DRAG_START:
case EVENT_TYPES.AREA_DRAG_START:
await this._handleAreaDragStart(data);
break;
case AREA_EVENT_TYPES.AREA_DRAG_MOVE:
case EVENT_TYPES.AREA_DRAG_MOVE:
await this._handleAreaDragMove(data);
break;
case AREA_EVENT_TYPES.AREA_DRAG_END:
case EVENT_TYPES.AREA_DRAG_END:
await this._handleAreaDragEnd(data);
break;
case AREA_EVENT_TYPES.AREA_DOCK_CENTER:
@@ -806,13 +822,15 @@ class AreaEventHandler {
case AREA_EVENT_TYPES.AREA_FLOATING_CREATE:
await this._handleFloatingAreaCreate(data);
break;
case AREA_EVENT_TYPES.AREA_ZINDEX_MANAGEMENT:
await this._handleAreaZIndexManagement(data);
break;
default:
// 记录其他事件但不处理
console.log(`📍 Area事件处理器: ${eventType}`, data);
console.log(`📍 Area事件处理器: ${eventType || 'unknown'}`, data);
}
} catch (error) {
console.error(`❌ Area事件处理错误 (${eventType}):`, error);
eventBus.recordError(`areaHandler_${eventType}`, error);
}
}
@@ -884,7 +902,7 @@ class AreaEventHandler {
* @param {Object} data - 事件数据
*/
async _handleAreaDragEnd(data) {
const { areaId, event } = data;
const { areaId, event, finalPosition, left, top } = data;
const dragState = this.areaStateManager.getDragState(areaId);
if (!dragState) return;
@@ -896,7 +914,18 @@ class AreaEventHandler {
// 清理拖拽状态
dragState.isDragging = false;
dragState.endTime = Date.now();
dragState.endPosition = { x: event.clientX, y: event.clientY };
// 使用 finalPosition 或 left/top 作为结束位置
if (finalPosition) {
dragState.endPosition = { x: finalPosition.x, y: finalPosition.y };
} else if (left !== undefined && top !== undefined) {
dragState.endPosition = { x: left, y: top };
} else if (event) {
dragState.endPosition = { x: event.clientX, y: event.clientY };
} else {
dragState.endPosition = dragState.startPosition;
}
dragState.totalDistance = distance;
dragState.duration = dragDuration;
@@ -1126,6 +1155,50 @@ class AreaEventHandler {
});
}
/**
* 处理Area层级管理事件
* @param {Object} data - 事件数据
*/
async _handleAreaZIndexManagement(data) {
const { areaId, action, zIndex, reason } = data;
try {
switch (action) {
case 'activate':
// 激活Area时更新z-index
this.activeAreas.add(areaId);
this.areaStateManager.updateState(areaId, {
lastActivatedAt: Date.now()
});
break;
case 'create_floating':
// 创建浮动Area时设置z-index
if (zIndex) {
this.areaStateManager.updateState(areaId, {
zIndex,
lastActivatedAt: Date.now()
});
}
break;
case 'update':
// 更新z-index
if (zIndex) {
this.areaStateManager.updateState(areaId, {
zIndex
});
}
break;
default:
console.log(`📍 Area层级管理: ${action}`, data);
}
} catch (error) {
console.error(`❌ Area层级管理错误 (${action}):`, error);
}
}
/**
* 启动内存保护机制
*/
@@ -1233,6 +1306,12 @@ class AreaEventHandler {
// 创建单例实例
const areaHandler = new AreaEventHandler();
/**
* 获取Area事件处理器实例
* @returns {AreaEventHandler} AreaEventHandler实例
*/
export const getAreaHandler = () => areaHandler;
// Area便捷操作函数
export const areaActions = {
/**

View File

@@ -495,6 +495,8 @@ class DragStateManager {
};
this.isEnabled = true;
this.debugMode = false;
this.eventListenersRegistered = false; // 初始化监听器注册标志
this.cleanupScheduler = null; // 初始化清理调度器
// 绑定方法
this._onDragEvent = this._onDragEvent.bind(this);
@@ -516,12 +518,24 @@ class DragStateManager {
console.log('🎯 拖拽状态管理器初始化完成');
}
/**
* 生成唯一的拖拽ID
* @param {string} componentType - 组件类型
* @returns {string} 拖拽ID
*/
_generateDragId(componentType) {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2, 9);
return `${componentType}_${timestamp}_${random}`;
}
/**
* 注册事件监听器
*/
_registerEventListeners() {
// 防止重复注册监听器
if (this.eventListenersRegistered) {
console.log('🚫 已经注册了监听器,跳过重复注册');
return;
}
@@ -537,17 +551,22 @@ class DragStateManager {
dragEvents.forEach(eventType => {
eventBus.on(eventType, this._onDragEvent, {
priority: 1,
deduplication: { type: 'EVENT_BASED', key: 'dragState' }
deduplication: { type: 'EVENT_BASED', key: 'dragState' },
componentId: 'drag-state-manager'
});
});
this.eventListenersRegistered = true;
console.log('✅ 拖拽管理器事件监听器注册完成');
}
/**
* 销毁管理器
*/
destroy() {
// 取消所有拖拽
this.cancelAllDrags();
// 清理事件监听器
const dragEvents = [
// Panel拖拽事件
@@ -565,10 +584,17 @@ class DragStateManager {
// 清理清理调度器
this._stopCleanupScheduler();
// 清理拖拽状态
this.dragStates.clear();
// 清理数据
this.activeDrags.clear();
this.dragHistory = [];
this.dragTargets.clear();
// 清理冲突检测器
this.conflictDetector.activeDrags.clear();
this.conflictDetector.conflictHistory = [];
this.isEnabled = false;
this.eventListenersRegistered = false;
console.log('🗑️ 拖拽状态管理器已销毁');
}
@@ -579,34 +605,66 @@ class DragStateManager {
async _onDragEvent(data) {
if (!this.isEnabled) return;
const monitorId = globalEventActions.startMonitor(`drag_${data.eventType || data.type}`);
const monitorId = globalEventActions.startMonitor(`drag_${data.eventType}`);
try {
const { eventType = data.type, dragId, componentType, sourceElement } = data;
// 从事件数据中提取 dragId如果没有则根据组件类型推断
let actualDragId = dragId;
if (!actualDragId) {
if (data.panelId) {
actualDragId = `panel_${data.panelId}_${data.timestamp || Date.now()}`;
} else if (data.tabIndex !== undefined) {
actualDragId = `tabpage_${data.tabId}_${data.tabIndex}_${data.timestamp || Date.now()}`;
} else if (data.areaId) {
actualDragId = `area_${data.areaId}_${data.timestamp || Date.now()}`;
}
}
// 推断组件类型
let actualComponentType = componentType;
if (!actualComponentType) {
if (data.panelId) {
actualComponentType = 'panel';
} else if (data.tabIndex !== undefined) {
actualComponentType = 'tabpage';
} else if (data.areaId) {
actualComponentType = 'area';
}
}
// 准备标准化的拖拽数据
const dragData = {
...data,
dragId: actualDragId,
componentType: actualComponentType,
sourceElement: sourceElement || data.element
};
switch (eventType) {
case 'panel.drag.start':
case 'tabpage.drag.start':
case 'area.drag.start':
await this._handleDragStart(data);
await this._handleDragStart(dragData);
break;
case 'panel.drag.move':
case 'tabpage.drag.move':
case 'area.drag.move':
await this._handleDragMove(data);
await this._handleDragMove(dragData);
break;
case 'panel.drag.end':
case 'tabpage.drag.end':
case 'area.drag.end':
await this._handleDragEnd(data);
await this._handleDragEnd(dragData);
break;
case 'panel.drag.cancel':
case 'tabpage.drag.cancel':
case 'area.drag.cancel':
await this._handleDragCancel(data);
await this._handleDragCancel(dragData);
break;
}
} catch (error) {
@@ -628,28 +686,31 @@ class DragStateManager {
async _handleDragStart(data) {
const { dragId, componentType, sourceElement, position, options = {} } = data;
// 如果没有提供 dragId生成一个唯一的 dragId
const actualDragId = dragId || this._generateDragId(componentType);
// 创建拖拽状态
const dragState = new DragState(dragId, componentType, sourceElement, options);
const dragState = new DragState(actualDragId, componentType, sourceElement, options);
dragState.startPosition = { ...position };
dragState.currentPosition = { ...position };
dragState.status = 'active';
// 保存拖拽状态
this.activeDrags.set(dragId, dragState);
this.activeDrags.set(actualDragId, dragState);
// 注册到冲突检测器
this.conflictDetector.registerDrag(dragState);
// 触发状态变更事件
// 触发状态变更事件,包含 dragId
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
dragId,
dragId: actualDragId,
newStatus: 'active',
dragState: dragState.getSummary()
});
// 发送初始反馈
if (this.debugMode) {
this._updateDragFeedback(dragId, {
this._updateDragFeedback(actualDragId, {
visible: true,
content: `开始拖拽 ${componentType}`,
type: 'default',
@@ -658,8 +719,10 @@ class DragStateManager {
}
if (this.debugMode) {
console.log(`🎯 拖拽开始: ${dragId} (${componentType})`, position);
console.log(`🎯 拖拽开始: ${actualDragId} (${componentType})`, position);
}
return actualDragId;
}
/**
@@ -670,7 +733,10 @@ class DragStateManager {
const { dragId, position, targetElement, targetArea } = data;
const dragState = this.activeDrags.get(dragId);
if (!dragState || dragState.status !== 'active') return;
if (!dragState || dragState.status !== 'active') {
console.warn(`⚠️ 未找到活跃的拖拽状态: ${dragId}`);
return;
}
// 更新位置
dragState.updatePosition(position.x, position.y);
@@ -726,7 +792,10 @@ class DragStateManager {
const { dragId, finalPosition, dropTarget, success = true } = data;
const dragState = this.activeDrags.get(dragId);
if (!dragState) return;
if (!dragState) {
console.warn(`⚠️ 未找到拖拽状态: ${dragId}`);
return;
}
// 完成拖拽
dragState.complete('completed', { success, finalPosition, dropTarget });
@@ -743,7 +812,10 @@ class DragStateManager {
// 从冲突检测器注销
this.conflictDetector.unregisterDrag(dragId);
// 触发状态变更事件
// 清理拖拽目标
this.dragTargets.delete(dragId);
// 触发状态变更事件,包含 dragId
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
dragId,
newStatus: 'completed',
@@ -773,7 +845,10 @@ class DragStateManager {
const { dragId, reason } = data;
const dragState = this.activeDrags.get(dragId);
if (!dragState) return;
if (!dragState) {
console.warn(`⚠️ 未找到拖拽状态: ${dragId}`);
return;
}
// 取消拖拽
dragState.complete('cancelled', { reason });
@@ -790,7 +865,10 @@ class DragStateManager {
// 从冲突检测器注销
this.conflictDetector.unregisterDrag(dragId);
// 触发状态变更事件
// 清理拖拽目标
this.dragTargets.delete(dragId);
// 触发状态变更事件,包含 dragId
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
dragId,
newStatus: 'cancelled',
@@ -1024,11 +1102,24 @@ class DragStateManager {
* 启动清理调度器
*/
_startCleanupScheduler() {
setInterval(() => {
if (this.cleanupScheduler) {
return;
}
this.cleanupScheduler = setInterval(() => {
this._cleanupExpiredData();
}, 300000); // 每5分钟清理一次
}
/**
* 停止清理调度器
*/
_stopCleanupScheduler() {
if (this.cleanupScheduler) {
clearInterval(this.cleanupScheduler);
this.cleanupScheduler = null;
}
}
/**
* 清理过期数据
*/
@@ -1663,26 +1754,6 @@ class DragStateManager {
}
}
/**
* 销毁管理器
*/
destroy() {
// 取消所有拖拽
this.cancelAllDrags();
// 清理数据
this.activeDrags.clear();
this.dragHistory = [];
this.dragTargets.clear();
// 清理冲突检测器
this.conflictDetector.activeDrags.clear();
this.conflictDetector.conflictHistory = [];
this.isEnabled = false;
console.log('🗑️ 拖拽状态管理器已销毁');
}
/**
* Area拖拽开始
* @param {Object} eventData - 拖拽事件数据
@@ -1878,18 +1949,8 @@ class DragStateManager {
}
}
// 延迟创建单例实例
let dragStateManager = null;
/**
* 确保单例实例存在
*/
function ensureDragStateManagerInstance() {
if (!dragStateManager) {
dragStateManager = new DragStateManager();
}
return dragStateManager;
}
// 立即创建单例实例,避免并发初始化问题
const dragStateManager = new DragStateManager();
// 便捷操作函数
export const dragStateActions = {
@@ -1898,150 +1959,153 @@ export const dragStateActions = {
* @param {string} dragId - 拖拽ID
* @returns {Object} 拖拽状态
*/
getDragState: (dragId) => ensureDragStateManagerInstance().getDragState(dragId),
getDragState: (dragId) => dragStateManager.getDragState(dragId),
/**
* 获取所有活跃拖拽
* @returns {Array} 活跃拖拽列表
*/
getActiveDrags: () => ensureDragStateManagerInstance().getActiveDrags(),
getActiveDrags: () => dragStateManager.getActiveDrags(),
/**
* 获取拖拽历史
* @param {number} limit - 限制数量
* @returns {Array} 历史记录
*/
getHistory: (limit = 100) => ensureDragStateManagerInstance().getDragHistory(limit),
getHistory: (limit = 100) => dragStateManager.getDragHistory(limit),
/**
* 获取统计信息
* @returns {Object} 统计信息
*/
getStats: () => ensureDragStateManagerInstance().getDragStats(),
getStats: () => dragStateManager.getDragStats(),
/**
* 设置调试模式
* @param {boolean} enabled - 是否启用
*/
setDebugMode: (enabled) => ensureDragStateManagerInstance().setDebugMode(enabled),
setDebugMode: (enabled) => dragStateManager.setDebugMode(enabled),
/**
* 启用/禁用管理器
* @param {boolean} enabled - 是否启用
*/
setEnabled: (enabled) => ensureDragStateManagerInstance().setEnabled(enabled),
setEnabled: (enabled) => dragStateManager.setEnabled(enabled),
/**
* 取消所有拖拽
*/
cancelAll: () => ensureDragStateManagerInstance().cancelAllDrags(),
cancelAll: () => dragStateManager.cancelAllDrags(),
/**
* 面板拖拽开始
* @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID
*/
onPanelDragStart: (eventData) => ensureDragStateManagerInstance().onPanelDragStart(eventData),
onPanelDragStart: (eventData) => dragStateManager.onPanelDragStart(eventData),
/**
* 面板拖拽移动
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onPanelDragMove: (eventData) => ensureDragStateManagerInstance().onPanelDragMove(eventData),
onPanelDragMove: (eventData) => dragStateManager.onPanelDragMove(eventData),
/**
* 面板拖拽结束
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onPanelDragEnd: (eventData) => ensureDragStateManagerInstance().onPanelDragEnd(eventData),
onPanelDragEnd: (eventData) => dragStateManager.onPanelDragEnd(eventData),
/**
* TabPage拖拽开始
* @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID
*/
onPanelDragStartFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragStartFromTabPage(eventData),
onPanelDragStartFromTabPage: (eventData) => dragStateManager.onPanelDragStartFromTabPage(eventData),
/**
* TabPage拖拽移动
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onPanelDragMoveFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragMoveFromTabPage(eventData),
onPanelDragMoveFromTabPage: (eventData) => dragStateManager.onPanelDragMoveFromTabPage(eventData),
/**
* TabPage拖拽结束
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onPanelDragEndFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragEndFromTabPage(eventData),
onPanelDragEndFromTabPage: (eventData) => dragStateManager.onPanelDragEndFromTabPage(eventData),
/**
* Area拖拽开始
* @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID
*/
onAreaDragStart: (eventData) => ensureDragStateManagerInstance().onAreaDragStart(eventData),
onAreaDragStart: (eventData) => dragStateManager.onAreaDragStart(eventData),
/**
* Area拖拽移动
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onAreaDragMove: (eventData) => ensureDragStateManagerInstance().onAreaDragMove(eventData),
onAreaDragMove: (eventData) => dragStateManager.onAreaDragMove(eventData),
/**
* Area拖拽结束
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onAreaDragEnd: (eventData) => ensureDragStateManagerInstance().onAreaDragEnd(eventData),
onAreaDragEnd: (eventData) => dragStateManager.onAreaDragEnd(eventData),
/**
* Tab拖拽开始
* @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID
*/
onTabDragStart: (eventData) => ensureDragStateManagerInstance().onPanelDragStartFromTabPage(eventData),
onTabDragStart: (eventData) => dragStateManager.onPanelDragStartFromTabPage(eventData),
/**
* Tab拖拽移动
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onTabDragMove: (eventData) => ensureDragStateManagerInstance().onPanelDragMoveFromTabPage(eventData),
onTabDragMove: (eventData) => dragStateManager.onPanelDragMoveFromTabPage(eventData),
/**
* Tab拖拽结束
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onTabDragEnd: (eventData) => ensureDragStateManagerInstance().onPanelDragEndFromTabPage(eventData),
onTabDragEnd: (eventData) => dragStateManager.onPanelDragEndFromTabPage(eventData),
/**
* 初始化拖拽管理器
*/
initialize: () => ensureDragStateManagerInstance(),
initialize: () => dragStateManager,
/**
* 销毁拖拽管理器
*/
destroy: () => {
if (dragStateManager) {
// 清理拖拽管理器资源
dragStateManager.activeDrags.clear();
dragStateManager.dragHistory = [];
// 清理拖拽管理器资源先调用实例的destroy方法清理监听器
try {
dragStateManager.destroy();
} catch (e) {
console.warn('销毁拖拽状态管理器时出错:', e);
}
dragStateManager = null;
console.log('🗑️ 拖拽状态管理器已销毁,所有资源已清理');
console.log('🗑️ 拖拽状态管理器已销毁');
}
}
};
// 导出
export default {
getInstance: ensureDragStateManagerInstance,
getInstance: () => dragStateManager,
actions: dragStateActions
};
export { DragState };

View File

@@ -140,10 +140,10 @@ class EventBusManager {
{ name: 'tabpage', handler: tabPageHandler, events: TABPAGE_EVENT_TYPES },
{ name: 'area', handler: areaHandler, events: AREA_EVENT_TYPES },
{ name: 'global', handler: globalEventManager, events: GLOBAL_EVENT_TYPES },
{ name: 'drag', handler: dragStateManager, events: DRAG_STATE_TYPES }
{ name: 'drag', handler: dragStateManager.getInstance(), events: DRAG_STATE_TYPES, skipEventRegistration: true }
];
for (const { name, handler, events } of handlers) {
for (const { name, handler, events, skipEventRegistration = false } of handlers) {
const handlerConfig = this.config.handlers[name];
if (!handlerConfig?.enabled) {
@@ -154,15 +154,20 @@ class EventBusManager {
try {
console.log(`📝 注册事件处理器: ${name}`);
// 注册事件处理器到事件总线
Object.values(events).forEach(eventType => {
if (typeof handler.handleEvent === 'function') {
eventBus.on(eventType, handler.handleEvent.bind(handler), {
priority: 1,
id: `handler-${name}`
});
}
});
// 注册事件处理器到事件总线(除非跳过)
if (!skipEventRegistration) {
Object.values(events).forEach(eventType => {
if (typeof handler.handleEvent === 'function') {
eventBus.on(eventType, handler.handleEvent.bind(handler), {
priority: 1,
id: `handler-${name}`,
componentId: `handler-${name}`
});
}
});
} else {
console.log(`⏭️ 跳过事件监听器注册(内部自动注册): ${name}`);
}
// 调用初始化方法(如果存在)
if (typeof handler.initialize === 'function') {
@@ -236,7 +241,7 @@ class EventBusManager {
routeTime: Date.now()
});
});
}, { id: 'router', priority: 0 });
}, { id: 'router', priority: 0, componentId: 'event-router' });
});
console.log(`🔗 设置了 ${routes.length} 个事件路由`);

View File

@@ -4,13 +4,6 @@
*/
import { eventBus } from '../eventBus';
import { PANEL_EVENT_TYPES, panelActions, panelHandler } from './PanelHandler';
import tabPageHandlerModule, { TABPAGE_EVENT_TYPES, tabPageActions } from './TabPageHandler';
import areaHandlerModule, { AREA_EVENT_TYPES, areaActions } from './AreaHandler';
// 获取处理器实例
const tabPageHandler = tabPageHandlerModule.getInstance ? tabPageHandlerModule.getInstance() : tabPageHandlerModule;
const areaHandler = areaHandlerModule;
// 全局事件类型常量
export const GLOBAL_EVENT_TYPES = {
@@ -50,59 +43,7 @@ export const GLOBAL_EVENT_TYPES = {
DEBUG_MEMORY: 'debug.memory'
};
// 事件路由配置
const EVENT_ROUTES = {
// Panel事件路由
[PANEL_EVENT_TYPES.PANEL_DRAG_START]: {
handlers: ['panelHandler', 'areaHandler'],
priority: 1,
timeout: 5000
},
[PANEL_EVENT_TYPES.PANEL_MAXIMIZE]: {
handlers: ['panelHandler', 'areaHandler'],
priority: 1,
timeout: 3000
},
[PANEL_EVENT_TYPES.PANEL_CLOSE_REQUEST]: {
handlers: ['panelHandler', 'tabPageHandler'],
priority: 2,
timeout: 5000
},
// TabPage事件路由
[TABPAGE_EVENT_TYPES.TABPAGE_DRAG_START]: {
handlers: ['tabPageHandler', 'areaHandler'],
priority: 1,
timeout: 5000
},
[TABPAGE_EVENT_TYPES.TABPAGE_SWITCH]: {
handlers: ['tabPageHandler', 'panelHandler'],
priority: 2,
timeout: 3000
},
[TABPAGE_EVENT_TYPES.TABPAGE_CLOSE_REQUEST]: {
handlers: ['tabPageHandler', 'panelHandler'],
priority: 2,
timeout: 5000
},
// Area事件路由
[AREA_EVENT_TYPES.AREA_DRAG_START]: {
handlers: ['areaHandler', 'tabPageHandler'],
priority: 1,
timeout: 5000
},
[AREA_EVENT_TYPES.AREA_MERGE]: {
handlers: ['areaHandler', 'tabPageHandler', 'panelHandler'],
priority: 1,
timeout: 10000
},
[AREA_EVENT_TYPES.AREA_DOCK_CENTER]: {
handlers: ['areaHandler', 'tabPageHandler'],
priority: 1,
timeout: 8000
}
};
// 事件路由配置将在构造函数中动态创建
// 事件执行监控
class EventExecutionMonitor {
@@ -297,31 +238,26 @@ class GlobalEventManager {
static instance = null;
constructor() {
// 单例模式实现:如果已经有实例,直接返回现有实例
if (GlobalEventManager.instance) {
return GlobalEventManager.instance;
}
this.eventHandlers = new Map();
this.eventRoutes = new Map(Object.entries(EVENT_ROUTES));
this.eventRoutes = new Map();
this.executionMonitor = new EventExecutionMonitor();
this.eventChains = new Map();
this.crossComponentChannels = new Map();
this.isInitialized = false;
this.isDestroyed = false;
this.eventListenersRegistered = false;
this.componentListenersRegistered = false;
this.debugMode = false;
this.handlerMap = {};
this.eventListenerUnsubscribers = [];
// 绑定方法
this._onGlobalEvent = this._onGlobalEvent.bind(this);
this._onSystemError = this._handleSystemError.bind(this);
this._cleanupExpiredData = this._cleanupExpiredData.bind(this);
// 延迟初始化先不调用_initialize()
// 保存实例到静态属性
GlobalEventManager.instance = this;
}
@@ -329,41 +265,29 @@ class GlobalEventManager {
* 初始化事件管理器
*/
async _initialize() {
// 防止重复初始化
if (this.isInitialized) {
console.warn('⚠️ 全局事件管理器已初始化,跳过重复初始化');
return;
}
// 初始化处理器映射
this.handlerMap = {
panelHandler,
tabPageHandler,
areaHandler
};
this.eventRoutes = new Map();
// 注册全局事件监听器
this._registerGlobalEventListeners();
// 启动定期清理
this._startCleanupScheduler();
// 启动调试模式监听
this._startDebugMode();
this.isInitialized = true;
console.log('✅ 全局事件管理器初始化完成');
// 触发系统就绪事件
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_READY, {
manager: 'globalEventManager',
timestamp: Date.now(),
handlers: Object.keys(this.handlerMap)
timestamp: Date.now()
});
}
/**
* 注册全局事件监听器
* 添加初始化锁防止并发场景下的重复注册
*/
_registerGlobalEventListeners() {
// 检查是否已经注册过事件监听器
@@ -372,236 +296,46 @@ class GlobalEventManager {
return;
}
const globalEvents = Object.values(GLOBAL_EVENT_TYPES);
globalEvents.forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._onGlobalEvent, {
priority: 0, // 最高优先级
deduplication: { type: 'TTL_BASED', ttl: 50 }
});
this.eventListenerUnsubscribers.push(unsubscribe);
});
// 注册所有组件事件监听器
this._registerComponentEventListeners();
// 标记为已注册
// 先标记为正在注册,防止并发
this.eventListenersRegistered = true;
}
/**
* 注册组件事件监听器
*/
_registerComponentEventListeners() {
// 防止重复注册组件事件监听器
if (this.componentListenersRegistered) {
return;
}
// Panel事件监听
Object.values(PANEL_EVENT_TYPES).forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._routeEvent.bind(this, eventType, null, 'panel'), { priority: 1 });
this.eventListenerUnsubscribers.push(unsubscribe);
});
// TabPage事件监听
Object.values(TABPAGE_EVENT_TYPES).forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._routeEvent.bind(this, eventType, null, 'tabPage'), { priority: 1 });
this.eventListenerUnsubscribers.push(unsubscribe);
});
// Area事件监听
Object.values(AREA_EVENT_TYPES).forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._routeEvent.bind(this, eventType, null, 'area'), { priority: 1 });
this.eventListenerUnsubscribers.push(unsubscribe);
});
this.componentListenersRegistered = true;
}
/**
* 路由事件到相应的处理器
* @param {string} eventType - 事件类型
* @param {Object} eventData - 事件数据
* @param {string} source - 事件源
*/
async _routeEvent(eventType, eventData, source) {
const eventId = `${eventType}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const routeConfig = this.eventRoutes.get(eventType);
// 开始监控
this.executionMonitor.startMonitoring(eventId, { ...eventData, eventType });
eventBus.emit(GLOBAL_EVENT_TYPES.EVENT_ROUTE_START, {
eventId,
eventType,
source,
routeConfig
});
try {
if (routeConfig) {
// 使用配置的路由
await this._executeRoutedHandlers(eventId, eventType, eventData, routeConfig);
} else {
// 默认路由到相应组件处理器
await this._executeDefaultHandler(eventId, eventType, eventData, source);
}
// 完成监控
this.executionMonitor.completeMonitoring(eventId);
eventBus.emit(GLOBAL_EVENT_TYPES.EVENT_ROUTE_SUCCESS, {
eventId,
eventType,
source,
timestamp: Date.now()
const globalEvents = Object.values(GLOBAL_EVENT_TYPES);
globalEvents.forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._onGlobalEvent, {
priority: 0, // 最高优先级
deduplication: { type: 'TTL_BASED', ttl: 50 },
componentId: 'global-event-manager'
});
this.eventListenerUnsubscribers.push(unsubscribe);
});
// 注册所有组件事件监听器
this._registerComponentEventListeners();
} catch (error) {
// 记录错误
this.executionMonitor.recordError(eventId, error);
eventBus.emit(GLOBAL_EVENT_TYPES.EVENT_ROUTE_ERROR, {
eventId,
eventType,
source,
error: error.message,
timestamp: Date.now()
});
// 触发系统错误事件
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_ERROR, {
eventId,
eventType,
source,
error,
timestamp: Date.now()
});
}
}
/**
* 执行路由的处理器
* @param {string} eventId - 事件ID
* @param {string} eventType - 事件类型
* @param {Object} eventData - 事件数据
* @param {Object} routeConfig - 路由配置
*/
async _executeRoutedHandlers(eventId, eventType, eventData, routeConfig) {
const { handlers, priority, timeout = 5000 } = routeConfig;
const handlerPromises = handlers.map(async (handlerName) => {
const startTime = Date.now();
this.executionMonitor.recordHandlerStart(eventId, handlerName);
try {
const handler = this.handlerMap[handlerName];
if (!handler) {
throw new Error(`Handler ${handlerName} not found`);
}
// 执行处理器
const result = await this._executeHandlerWithTimeout(
handler,
eventType,
eventData,
timeout
);
const duration = Date.now() - startTime;
this.executionMonitor.recordHandlerComplete(eventId, handlerName, true, duration);
return { handlerName, result, duration };
} catch (error) {
const duration = Date.now() - startTime;
this.executionMonitor.recordHandlerComplete(eventId, handlerName, false, duration, error);
throw error;
}
});
// 等待所有处理器完成
const results = await Promise.allSettled(handlerPromises);
// 检查是否有失败的处理器
const failures = results.filter(result => result.status === 'rejected');
if (failures.length > 0) {
throw new Error(`Handler execution failed: ${failures.map(f => f.reason.message).join(', ')}`);
}
return results.map(result => result.value);
}
/**
* 执行默认处理器
* @param {string} eventId - 事件ID
* @param {string} eventType - 事件类型
* @param {Object} eventData - 事件数据
* @param {string} source - 事件源
*/
async _executeDefaultHandler(eventId, eventType, eventData, source) {
const handlerName = `${source}Handler`;
const handler = this.handlerMap[handlerName];
if (!handler) {
throw new Error(`Default handler ${handlerName} not found`);
}
this.executionMonitor.recordHandlerStart(eventId, handlerName);
try {
const result = await this._executeHandlerWithTimeout(handler, eventType, eventData, 5000);
const duration = Date.now() - this.executionMonitor.getExecutionDetail(eventId).startTime;
this.executionMonitor.recordHandlerComplete(eventId, handlerName, true, duration);
return result;
} catch (error) {
const duration = Date.now() - this.executionMonitor.getExecutionDetail(eventId).startTime;
this.executionMonitor.recordHandlerComplete(eventId, handlerName, false, duration, error);
// 如果注册失败,重置标志位
this.eventListenersRegistered = false;
throw error;
}
}
/**
* 带超时的处理器执行
* @param {Object} handler - 处理器对象
* @param {string} eventType - 事件类型
* @param {Object} eventData - 事件数据
* @param {number} timeout - 超时时间
* @returns {Promise} 执行结果
* 注册组件事件监听器
* 添加初始化锁防止并发场景下的重复注册
*/
async _executeHandlerWithTimeout(handler, eventType, eventData, timeout) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error(`Handler execution timeout after ${timeout}ms`));
}, timeout);
try {
// 假设处理器有处理事件的方法
if (typeof handler._onEvent === 'function') {
const result = handler._onEvent({ eventType, ...eventData });
if (result instanceof Promise) {
result.then(resolve).catch(reject).finally(() => clearTimeout(timer));
} else {
resolve(result);
clearTimeout(timer);
}
} else {
// 如果处理器没有_onEvent方法直接解析
resolve(true);
clearTimeout(timer);
}
} catch (error) {
reject(error);
clearTimeout(timer);
}
});
_registerComponentEventListeners() {
if (this.componentListenersRegistered) {
console.warn('⚠️ 组件事件监听器已经注册,跳过重复注册');
return;
}
this.componentListenersRegistered = true;
console.log('✅ 组件事件监听器注册完成Handler自行订阅事件');
}
/**
* 处理全局事件
* @param {Object} data - 事件数据
*/
async _onGlobalEvent(data) {
const { eventType } = data;
const eventType = data.eventType;
try {
switch (eventType) {
@@ -634,18 +368,8 @@ class GlobalEventManager {
async _handleSystemInit(data) {
console.log('🚀 系统初始化开始...', data);
// 检查所有处理器是否就绪
const handlersStatus = {};
for (const [name, handler] of Object.entries(this.handlerMap)) {
handlersStatus[name] = {
ready: typeof handler === 'object',
methods: Object.getOwnPropertyNames(Object.getPrototypeOf(handler))
};
}
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_READY, {
manager: 'globalEventManager',
handlersStatus,
timestamp: Date.now()
});
}
@@ -714,37 +438,13 @@ class GlobalEventManager {
async _handleCrossComponentRequest(data) {
const { requestId, targetComponent, action, payload } = data;
try {
// 查找目标组件的处理
const handler = this.handlerMap[`${targetComponent}Handler`];
if (!handler) {
throw new Error(`Target component handler ${targetComponent}Handler not found`);
}
// 执行请求
const result = await handler[action](payload);
// 发送响应
eventBus.emit(GLOBAL_EVENT_TYPES.CROSS_COMPONENT_RESPONSE, {
requestId,
targetComponent,
action,
result,
success: true,
timestamp: Date.now()
});
} catch (error) {
// 发送错误响应
eventBus.emit(GLOBAL_EVENT_TYPES.CROSS_COMPONENT_RESPONSE, {
requestId,
targetComponent,
action,
error: error.message,
success: false,
timestamp: Date.now()
});
}
// 通过事件总线转发跨组件请求
// 目标Handler应该监听这个事件并处理
eventBus.emit(`${targetComponent}.${action}`, {
requestId,
payload,
isCrossComponent: true
});
}
/**
@@ -1032,41 +732,52 @@ class GlobalEventManager {
/**
* 销毁事件管理器
* 添加销毁锁防止重复销毁,确保正确清理所有监听器
*/
destroy() {
// 清理自己注册的所有事件监听器
this.eventListenerUnsubscribers.forEach(unsubscribe => {
try {
unsubscribe();
} catch (error) {
console.warn('清理监听器时出错:', error);
}
});
this.eventListenerUnsubscribers = [];
if (this.isDestroyed) {
console.warn('⚠️ 全局事件管理器已经被销毁,跳过重复销毁');
return;
}
// 销毁各个处理器
Object.values(this.handlerMap).forEach(handler => {
if (typeof handler.destroy === 'function') {
handler.destroy();
}
});
this.isDestroyed = true;
// 清理自己注册的所有事件监听器
if (this.eventListenerUnsubscribers.length > 0) {
this.eventListenerUnsubscribers.forEach(unsubscribe => {
try {
if (typeof unsubscribe === 'function') {
unsubscribe();
}
} catch (error) {
console.warn('清理监听器时出错:', error);
}
});
this.eventListenerUnsubscribers = [];
}
// 清理数据
this.eventHandlers.clear();
this.eventChains.clear();
this.crossComponentChannels.clear();
this.handlerMap = {};
this.eventRoutes.clear();
if (this.eventHandlers) this.eventHandlers.clear();
if (this.eventChains) this.eventChains.clear();
if (this.crossComponentChannels) this.crossComponentChannels.clear();
if (this.eventRoutes) this.eventRoutes.clear();
// 清理执行监控器
if (this.executionMonitor) {
this.executionMonitor.cleanup();
}
// 重置状态标志
this.isInitialized = false;
this.eventListenersRegistered = false;
this.componentListenersRegistered = false;
console.log('🗑️ 全局事件管理器已销毁,所有监听器已清理');
}
}
// 延迟创建单例实例
let globalEventManager = null;
// 立即创建单例实例,避免并发初始化问题
const globalEventManager = new GlobalEventManager();
// 全局便捷API
export const globalEventActions = {
@@ -1076,7 +787,6 @@ export const globalEventActions = {
* @returns {string} 监控ID
*/
startMonitor: (operation) => {
ensureInstance();
return globalEventManager.startPerformanceMonitor(operation);
},
@@ -1086,7 +796,6 @@ export const globalEventActions = {
* @param {Object} metadata - 元数据
*/
endMonitor: (monitorId, metadata = {}) => {
ensureInstance();
globalEventManager.endPerformanceMonitor(monitorId, metadata);
},
@@ -1097,7 +806,6 @@ export const globalEventActions = {
* @returns {string} 链ID
*/
createChain: (chainName, events) => {
ensureInstance();
return globalEventManager.createEventChain(chainName, events);
},
@@ -1108,7 +816,6 @@ export const globalEventActions = {
* @param {Array} targets - 目标组件
*/
broadcast: (message, data = {}, targets = null) => {
ensureInstance();
globalEventManager.broadcast(message, data, targets);
},
@@ -1120,7 +827,6 @@ export const globalEventActions = {
* @returns {Promise} 响应
*/
request: (component, action, payload) => {
ensureInstance();
return globalEventManager.request(component, action, payload);
},
@@ -1136,7 +842,6 @@ export const globalEventActions = {
* @returns {Object} 统计信息
*/
getStats: () => {
ensureInstance();
return globalEventManager.getExecutionStats();
},
@@ -1145,7 +850,6 @@ export const globalEventActions = {
* @returns {Array} 链状态
*/
getChainStatus: () => {
ensureInstance();
return globalEventManager.getEventChainStatus();
},
@@ -1153,7 +857,7 @@ export const globalEventActions = {
* 初始化事件管理器
*/
initialize: () => {
ensureInstance();
return globalEventManager;
},
/**
@@ -1162,31 +866,15 @@ export const globalEventActions = {
destroy: () => {
if (globalEventManager) {
globalEventManager.destroy();
globalEventManager = null;
}
}
};
/**
* 确保单例实例存在
*/
async function ensureInstance() {
if (!globalEventManager) {
globalEventManager = new GlobalEventManager();
// 异步初始化
await globalEventManager._initialize();
} else if (!globalEventManager.isInitialized) {
// 如果实例存在但未初始化,完成初始化
await globalEventManager._initialize();
}
return globalEventManager;
}
// 导出单例实例访问方法
export const getGlobalEventManager = ensureInstance;
export const getGlobalEventManager = () => globalEventManager;
// 导出事件管理器和相关API
export default {
getInstance: getGlobalEventManager,
getInstance: () => globalEventManager,
actions: globalEventActions
};

View File

@@ -1,5 +1,5 @@
import { emitEvent, onEvent, onceEvent, registerHandler, unregisterHandler, getHandlerSnapshot } from '../eventBus'
import { nanoid } from 'nanoid'
import { emitEvent, onEvent, onceEvent, registerHandler, unregisterHandler, getHandlerSnapshot } from '../eventBus'
// Panel事件类型常量
export const PANEL_EVENT_TYPES = {
@@ -151,9 +151,11 @@ class PanelEventHandler {
// 触发最大化事件false表示还原
await emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
panelId,
maximized: false,
source: 'PanelHandler'
}, { priority })
maximized: false
}, {
priority,
source: { component: 'PanelHandler', panelId }
})
// 如果需要同步到Area
if (syncToArea) {
@@ -171,10 +173,12 @@ class PanelEventHandler {
*/
requestClose(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.CLOSE_REQUEST, {
emitEvent(PANEL_EVENT_TYPES.CLOSE_REQUEST, {
areaId,
panelId,
timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
});
}
@@ -231,9 +235,11 @@ class PanelEventHandler {
return emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
panelId,
toolbarExpanded: panelState.toolbarExpanded,
source: 'PanelHandler'
}, { priority })
toolbarExpanded: panelState.toolbarExpanded
}, {
priority,
source: { component: 'PanelHandler', panelId }
})
}
/**
@@ -261,9 +267,11 @@ class PanelEventHandler {
return emitEvent(PANEL_EVENT_TYPES.DRAG_START, {
panelId,
event: dragEvent,
dragState,
source: 'PanelHandler'
}, { priority })
dragState
}, {
priority,
source: { component: 'PanelHandler', panelId }
})
}
/**
@@ -325,9 +333,11 @@ class PanelEventHandler {
panelId,
event: dragEvent,
dragState,
duration: dragState.endTime - dragState.startTime,
source: 'PanelHandler'
}, { priority })
duration: dragState.endTime - dragState.startTime
}, {
priority,
source: { component: 'PanelHandler', panelId }
})
// 清理拖拽状态
this.dragStates.delete(panelId)
@@ -353,10 +363,11 @@ class PanelEventHandler {
this.panelStates.set(panelId, panelState)
return emitEvent(PANEL_EVENT_TYPES.ACTIVATED, {
panelId,
source: 'PanelHandler',
timestamp: Date.now()
}, { priority })
panelId
}, {
priority,
source: { component: 'PanelHandler', panelId }
})
}
/**
@@ -377,10 +388,11 @@ class PanelEventHandler {
this.panelStates.set(panelId, panelState)
return emitEvent(PANEL_EVENT_TYPES.DEACTIVATED, {
panelId,
source: 'PanelHandler',
timestamp: Date.now()
}, { priority })
panelId
}, {
priority,
source: { component: 'PanelHandler', panelId }
})
}
/**
@@ -441,10 +453,12 @@ class PanelEventHandler {
*/
onExpand(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.EXPAND, {
emitEvent(PANEL_EVENT_TYPES.EXPAND, {
areaId,
panelId,
timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
});
}
@@ -454,10 +468,12 @@ class PanelEventHandler {
*/
onMaximize(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
areaId,
panelId,
timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
});
}
@@ -480,10 +496,12 @@ class PanelEventHandler {
*/
onToggleToolbar(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
areaId,
panelId,
timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
});
}
@@ -507,11 +525,13 @@ class PanelEventHandler {
*/
onSizeUpdate(eventData) {
const { areaId, panelId, size } = eventData;
this.emitEvent('panel.size.update', {
emitEvent('panel.size.update', {
areaId,
panelId,
size,
timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
});
}
@@ -567,8 +587,9 @@ class PanelEventHandler {
return emitEvent(PANEL_EVENT_TYPES.MAXIMIZE_SYNC, {
panelId,
maximized,
areaId: panelState.areaId,
source: 'PanelHandler'
areaId: panelState.areaId
}, {
source: { component: 'PanelHandler', panelId, areaId: panelState.areaId }
})
}

View File

@@ -188,7 +188,7 @@ class TabPageEventHandler {
* @param {string} data.eventType - 事件类型
*/
async _onTabPageEvent(data) {
const { eventType } = data;
const eventType = data.eventType;
try {
switch (eventType) {
@@ -222,7 +222,6 @@ class TabPageEventHandler {
}
} catch (error) {
console.error(`❌ TabPage事件处理错误 (${eventType}):`, error);
eventBus.recordError(`tabPageHandler_${eventType}`, error);
}
}
@@ -591,6 +590,9 @@ function ensureInstance() {
return tabPageHandler;
}
// 导出单例实例访问方法
export const getTabPageHandler = ensureInstance;
// TabPage便捷操作函数
export const tabPageActions = {
/**