解决事件泄漏问题

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

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