使用全局事件总线

This commit is contained in:
zqm
2025-12-24 16:40:17 +08:00
parent 6096b0099d
commit 8c8ce2f8ce
4 changed files with 377 additions and 45 deletions

View File

@@ -1,5 +1,6 @@
<template>
<div
ref="areaRef"
class="vs-area select-none"
:class="{ 'is-maximized': isMaximized, 'is-normal': !isMaximized }"
:style="areaStyle"
@@ -133,7 +134,7 @@
<script setup>
import { defineProps, computed, ref, onMounted, onUnmounted, watch, defineExpose } from 'vue'
import { emitEvent, EVENT_TYPES } from './eventBus.js'
import { emitEvent, EVENT_TYPES, globalEventListenerManager } from './eventBus.js'
import TabPage from './TabPage.vue'
import Panel from './Panel.vue'
import { zIndexManager, Z_INDEX_LAYERS } from './dockLayers.js'
@@ -155,6 +156,8 @@ const props = defineProps({
draggable: { type: Boolean, default: true }
})
// 使用全局事件总线和拖拽管理器
// 本地状态
const localState = ref(props.windowState)
// 保存原始位置和大小信息
@@ -170,6 +173,9 @@ const maximizedFromPosition = ref(null)
// 存储接收到的外部Area内容
const receivedContent = ref([])
// 组件引用
const areaRef = ref(null)
// 拖拽相关状态
const isDragging = ref(false)
const dragStartPos = ref({ x: 0, y: 0 })
@@ -301,18 +307,21 @@ const onDragStart = (e) => {
y: originalPosition.value.top || 0
}
// 通知父组件拖拽开始
// 使用事件总线通知拖拽开始
emitEvent(EVENT_TYPES.AREA_DRAG_START, {
areaId: props.id,
event: e,
element: areaRef.value,
position: { x: e.clientX, y: e.clientY },
clientX: e.clientX,
clientY: e.clientY,
startLeft: originalPosition.value.left || 0,
startTop: originalPosition.value.top || 0
})
// 添加全局事件监听
document.addEventListener('mousemove', onDragMove)
document.addEventListener('mouseup', onDragEnd)
// 使用全局事件管理器添加事件监听
globalEventListenerManager.addGlobalListener('mousemove', onDragMove)
globalEventListenerManager.addGlobalListener('mouseup', onDragEnd)
// 防止文本选择
e.preventDefault()
@@ -345,32 +354,39 @@ const onDragMove = (e) => {
originalPosition.value.left = newLeft
originalPosition.value.top = newTop
// 通知父组件拖拽移动
// 使用事件总线通知拖拽移动
emitEvent(EVENT_TYPES.AREA_DRAG_MOVE, {
areaId: props.id,
event: e,
element: areaRef.value,
position: { x: e.clientX, y: e.clientY },
clientX: e.clientX,
clientY: e.clientY,
left: newLeft,
top: newTop
})
// 通知父组件位置变化
// 使用事件总线通知位置变化
emitEvent(EVENT_TYPES.AREA_POSITION_UPDATE, { areaId: props.id, left: newLeft, top: newTop })
}
// 拖拽结束
const onDragEnd = () => {
// 通知父组件拖拽结束
// 使用事件总线通知拖拽结束
emitEvent(EVENT_TYPES.AREA_DRAG_END, {
areaId: props.id,
finalPosition: {
x: originalPosition.value.left,
y: originalPosition.value.top
},
left: originalPosition.value.left,
top: originalPosition.value.top
})
isDragging.value = false
// 移除全局事件监听
document.removeEventListener('mousemove', onDragMove)
document.removeEventListener('mouseup', onDragEnd)
// 使用全局事件管理器移除事件监听
globalEventListenerManager.removeGlobalListener('mousemove', onDragMove)
globalEventListenerManager.removeGlobalListener('mouseup', onDragEnd)
}
// 调整大小开始
@@ -392,10 +408,10 @@ const onResizeStart = (direction, e) => {
top: originalPosition.value.top
}
// 添加全局事件监听
document.addEventListener('mousemove', onResizeMove)
document.addEventListener('mouseup', onResizeEnd)
document.addEventListener('mouseleave', onResizeEnd)
// 使用全局事件管理器添加事件监听
globalEventListenerManager.addGlobalListener('mousemove', onResizeMove)
globalEventListenerManager.addGlobalListener('mouseup', onResizeEnd)
globalEventListenerManager.addGlobalListener('mouseleave', onResizeEnd)
// 防止文本选择
e.preventDefault()
@@ -486,7 +502,7 @@ const onResizeStart = (direction, e) => {
originalPosition.value.left = newLeft
originalPosition.value.top = newTop
// 通知父组件位置变化
// 使用事件总线通知位置变化
emitEvent(EVENT_TYPES.AREA_POSITION_UPDATE, {
areaId: props.id,
left: newLeft,
@@ -501,10 +517,10 @@ const onResizeStart = (direction, e) => {
const onResizeEnd = () => {
isResizing.value = false
resizeDirection.value = null
// 移除全局事件监听
document.removeEventListener('mousemove', onResizeMove)
document.removeEventListener('mouseup', onResizeEnd)
document.removeEventListener('mouseleave', onResizeEnd)
// 使用全局事件管理器移除事件监听
globalEventListenerManager.removeGlobalListener('mousemove', onResizeMove)
globalEventListenerManager.removeGlobalListener('mouseup', onResizeEnd)
globalEventListenerManager.removeGlobalListener('mouseleave', onResizeEnd)
}
const onToggleMaximize = () => {
@@ -580,13 +596,13 @@ onMounted(() => {
// 组件卸载时清理全局事件监听器
onUnmounted(() => {
// 清理拖拽相关的全局事件监听器
document.removeEventListener('mousemove', onDragMove)
document.removeEventListener('mouseup', onDragEnd)
globalEventListenerManager.removeGlobalListener('mousemove', onDragMove)
globalEventListenerManager.removeGlobalListener('mouseup', onDragEnd)
// 清理调整大小相关的全局事件监听器
document.removeEventListener('mousemove', onResizeMove)
document.removeEventListener('mouseup', onResizeEnd)
document.removeEventListener('mouseleave', onResizeEnd)
globalEventListenerManager.removeGlobalListener('mousemove', onResizeMove)
globalEventListenerManager.removeGlobalListener('mouseup', onResizeEnd)
globalEventListenerManager.removeGlobalListener('mouseleave', onResizeEnd)
})

View File

@@ -118,11 +118,11 @@ const onPanelDragEnd = () => {
};
const onPanelDragStartFromTabPage = (event) => {
dragStateActions.onPanelDragStartFromTabPage(event.areaId, event);
dragStateActions.onPanelDragStartFromTabPage(event);
};
const onPanelDragMoveFromTabPage = (event) => {
dragStateActions.onPanelDragMoveFromTabPage(event.areaId, event);
dragStateActions.onPanelDragMoveFromTabPage(event);
};
const onPanelDragEndFromTabPage = () => {
@@ -130,23 +130,23 @@ const onPanelDragEndFromTabPage = () => {
};
const onAreaDragStart = (event) => {
dragStateActions.onAreaDragStart(event.areaId, event);
dragStateActions.onAreaDragStart(event);
};
const onAreaDragMove = (event) => {
dragStateActions.onAreaDragMove(event.areaId, event);
dragStateActions.onAreaDragMove(event);
};
const onAreaDragEnd = (event) => {
dragStateActions.onAreaDragEnd(event.areaId, event);
dragStateActions.onAreaDragEnd(event);
};
const onTabDragStart = (event) => {
dragStateActions.onTabDragStart(event.areaId, event);
dragStateActions.onTabDragStart(event);
};
const onTabDragMove = (event) => {
dragStateActions.onTabDragMove(event.areaId, event);
dragStateActions.onTabDragMove(event);
};
const onTabDragEnd = () => {

View File

@@ -213,17 +213,10 @@ class PriorityEventQueue {
}
return priorityMap[priority] || 'UNKNOWN'
}
/**
* 清除所有队列
*/
clear() {
for (const queue of Object.values(this.queues)) {
queue.length = 0
}
}
}
// 增强的事件总线类
class EnhancedEventBus {
constructor() {
@@ -1079,3 +1072,109 @@ export const unregisterHandler = (handlerName) => {
export const getHandlerSnapshot = () => {
return handlerRegistry.getSnapshot()
}
// 全局事件监听管理器
class GlobalEventListenerManager {
constructor() {
this.listeners = new Map()
}
/**
* 添加全局事件监听
* @param {string} eventType 事件类型
* @param {Function} handler 事件处理函数
*/
addGlobalListener(eventType, handler) {
if (!this.listeners.has(eventType)) {
this.listeners.set(eventType, new Map())
}
const eventHandlers = this.listeners.get(eventType)
const handlerId = handler.toString()
// 如果是第一次添加这个处理函数,实际添加到文档
if (!eventHandlers.has(handlerId)) {
document.addEventListener(eventType, handler)
eventHandlers.set(handlerId, {
handler,
count: 0
})
}
// 增加这个处理函数的引用计数
eventHandlers.get(handlerId).count++
return handlerId
}
/**
* 移除全局事件监听
* @param {string} eventType 事件类型
* @param {Function} handler 事件处理函数
*/
removeGlobalListener(eventType, handler) {
if (!this.listeners.has(eventType)) {
return false
}
const eventHandlers = this.listeners.get(eventType)
const handlerId = handler.toString()
if (!eventHandlers.has(handlerId)) {
return false
}
const handlerInfo = eventHandlers.get(handlerId)
// 减少这个处理函数的引用计数
if (handlerInfo.count > 0) {
handlerInfo.count--
// 如果计数器减到0实际从文档移除
if (handlerInfo.count === 0) {
document.removeEventListener(eventType, handler)
eventHandlers.delete(handlerId)
// 如果这个事件类型没有处理函数了,清理该事件类型的映射
if (eventHandlers.size === 0) {
this.listeners.delete(eventType)
}
}
}
return true
}
/**
* 获取全局事件监听统计
*/
getStats() {
const stats = {}
for (const [eventType, eventHandlers] of this.listeners.entries()) {
let totalCount = 0
for (const handlerInfo of eventHandlers.values()) {
totalCount += handlerInfo.count
}
stats[eventType] = {
count: totalCount,
handlerCount: eventHandlers.size
}
}
return stats
}
/**
* 清除所有全局事件监听
*/
clearAll() {
for (const [eventType, eventHandlers] of this.listeners.entries()) {
for (const [handlerId, handlerInfo] of eventHandlers.entries()) {
document.removeEventListener(eventType, handlerInfo.handler)
}
}
this.listeners.clear()
}
}
// 导出全局事件管理器实例
export const globalEventListenerManager = new GlobalEventListenerManager()

View File

@@ -1572,6 +1572,29 @@ class DragStateManager {
return null;
}
/**
* 根据ID或Area ID查找拖拽状态
* @private
* @param {string} dragId - 拖拽ID
* @param {string} areaId - Area ID
* @returns {Object|null} 拖拽状态
*/
_findDragByIdOrAreaId(dragId, areaId) {
// 首先尝试通过dragId查找
if (dragId && this.activeDrags.has(dragId)) {
return { dragId, dragState: this.activeDrags.get(dragId) };
}
// 如果找不到尝试通过areaId查找
for (const [id, dragState] of this.activeDrags.entries()) {
if (dragState.options.areaId === areaId) {
return { dragId: id, dragState };
}
}
return null;
}
/**
* 检测拖拽目标
* @private
@@ -1624,6 +1647,200 @@ class DragStateManager {
this.isEnabled = false;
console.log('🗑️ 拖拽状态管理器已销毁');
}
/**
* Area拖拽开始
* @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID
*/
onAreaDragStart(eventData) {
try {
const {
event,
areaId,
element,
type = 'area',
position = { x: 0, y: 0 },
...options
} = eventData;
// 检查是否有其他活跃拖拽
if (this.activeDrags.size > 0) {
console.warn('检测到其他活跃拖拽,暂停之前的拖拽');
this.cancelAllDrags();
}
// 创建拖拽ID
const dragId = `area-${areaId}-${Date.now()}`;
// 创建拖拽状态
const dragState = new DragState(dragId, DRAG_AREA_TYPES.AREA, element, {
areaId,
sourceType: type,
...options
});
// 设置起始位置
const clientX = event?.clientX || eventData.clientX;
const clientY = event?.clientY || eventData.clientY;
const startX = position.x || clientX;
const startY = position.y || clientY;
dragState.startPosition = { x: startX, y: startY };
dragState.updatePosition(startX, startY);
// 设置状态为活跃
dragState.status = 'active';
this.activeDrags.set(dragId, dragState);
// 触发拖拽开始事件
eventBus.emit(DRAG_STATE_TYPES.DRAG_START, {
dragId,
dragState: dragState.getSummary(),
source: 'onAreaDragStart',
timestamp: Date.now()
});
console.log(`🎯 区域拖拽开始: ${areaId}, dragId: ${dragId}`);
return dragId;
} catch (error) {
console.error('区域拖拽开始时出错:', error);
eventBus.emit(DRAG_STATE_TYPES.DRAG_PERFORMANCE_MONITOR, {
operation: 'onAreaDragStart',
error: error.message,
timestamp: Date.now()
});
return null;
}
}
/**
* Area拖拽移动
* @param {Object} eventData - 拖拽事件数据
*/
onAreaDragMove(eventData) {
try {
const {
event,
dragId,
areaId,
element,
type = 'area',
position = { x: 0, y: 0 },
...options
} = eventData;
// 查找拖拽状态
const activeDrag = this._findDragByIdOrAreaId(dragId, areaId);
if (!activeDrag) {
console.warn('找不到区域拖拽状态:', areaId);
return false;
}
const dragState = activeDrag.dragState;
if (dragState.status !== 'active') {
console.warn('拖拽状态不活跃:', dragId);
return false;
}
// 更新位置
const clientX = event?.clientX || eventData.clientX;
const clientY = event?.clientY || eventData.clientY;
const currentX = position.x || clientX;
const currentY = position.y || clientY;
dragState.updatePosition(currentX, currentY);
// 检测目标区域
const targetElement = this._detectDragTarget(currentX, currentY);
if (targetElement) {
dragState.setTarget(targetElement.element, targetElement.area);
}
// 触发拖拽移动事件
eventBus.emit(DRAG_STATE_TYPES.DRAG_MOVE, {
dragId,
dragState: dragState.getSummary(),
position: { x: currentX, y: currentY },
target: targetElement,
source: 'onAreaDragMove',
timestamp: Date.now()
});
return true;
} catch (error) {
console.error('区域拖拽移动时出错:', error);
eventBus.emit(DRAG_STATE_TYPES.DRAG_PERFORMANCE_MONITOR, {
operation: 'onAreaDragMove',
error: error.message,
timestamp: Date.now()
});
return false;
}
}
/**
* Area拖拽结束
* @param {Object} eventData - 拖拽事件数据
*/
onAreaDragEnd(eventData) {
try {
const {
event,
dragId,
areaId,
type = 'area',
finalPosition = { x: 0, y: 0 },
dropTarget,
...options
} = eventData;
// 查找拖拽状态
const activeDrag = this._findDragByIdOrAreaId(dragId, areaId);
if (!activeDrag) {
console.warn('找不到区域拖拽状态:', areaId);
return false;
}
const dragState = activeDrag.dragState;
// 更新最终位置
const clientX = event?.clientX || eventData.clientX;
const clientY = event?.clientY || eventData.clientY;
const finalX = finalPosition.x || clientX;
const finalY = finalPosition.y || clientY;
dragState.updatePosition(finalX, finalY);
// 设置最终状态
dragState.status = 'completed';
dragState.setTarget(dropTarget?.element || null, dropTarget?.area || null);
// 触发拖拽结束事件
eventBus.emit(DRAG_STATE_TYPES.DRAG_END, {
dragId,
dragState: dragState.getSummary(),
finalPosition: { x: finalX, y: finalY },
dropTarget,
source: 'onAreaDragEnd',
timestamp: Date.now()
});
// 移动到历史记录
this.dragHistory.push(dragState.getSummary());
this.activeDrags.delete(activeDrag.dragId);
console.log(`✅ 区域拖拽结束: ${areaId}, dragId: ${dragId}`);
return true;
} catch (error) {
console.error('区域拖拽结束时出错:', error);
eventBus.emit(DRAG_STATE_TYPES.DRAG_PERFORMANCE_MONITOR, {
operation: 'onAreaDragEnd',
error: error.message,
timestamp: Date.now()
});
return false;
}
}
}
// 延迟创建单例实例
@@ -1731,21 +1948,21 @@ export const dragStateActions = {
* @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID
*/
onAreaDragStart: (eventData) => ensureDragStateManagerInstance().onPanelDragStart(eventData),
onAreaDragStart: (eventData) => ensureDragStateManagerInstance().onAreaDragStart(eventData),
/**
* Area拖拽移动
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onAreaDragMove: (eventData) => ensureDragStateManagerInstance().onPanelDragMove(eventData),
onAreaDragMove: (eventData) => ensureDragStateManagerInstance().onAreaDragMove(eventData),
/**
* Area拖拽结束
* @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功
*/
onAreaDragEnd: (eventData) => ensureDragStateManagerInstance().onPanelDragEnd(eventData),
onAreaDragEnd: (eventData) => ensureDragStateManagerInstance().onAreaDragEnd(eventData),
/**
* Tab拖拽开始