308 lines
10 KiB
JavaScript
308 lines
10 KiB
JavaScript
// js/chatbot/core/chat-message-event-manager.js
|
||
|
||
/**
|
||
* 聊天消息事件管理器
|
||
*
|
||
* Phase 3: 使用事件委托(Event Delegation)处理所有消息操作
|
||
*
|
||
* 核心优势:
|
||
* 1. 内存占用减少 40-60%(从 N×8 个监听器降至 2 个)
|
||
* 2. 动态内容无需重新绑定事件
|
||
* 3. 集中管理所有事件逻辑,提升可维护性
|
||
* 4. 减少 DOM 操作,提升渲染速度
|
||
*
|
||
* @class ChatMessageEventManager
|
||
* @version 1.0.0
|
||
* @date 2025-01-12
|
||
*/
|
||
class ChatMessageEventManager {
|
||
/**
|
||
* 构造函数
|
||
* @param {string} containerSelector - 聊天消息容器的选择器
|
||
*/
|
||
constructor(containerSelector) {
|
||
this.containerSelector = containerSelector;
|
||
this.container = document.querySelector(containerSelector);
|
||
|
||
if (!this.container) {
|
||
console.warn(`[EventManager] 容器未找到: ${containerSelector},将在 DOM 加载后重试`);
|
||
// 如果容器还未加载,等待 DOM 加载完成
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', () => this._init());
|
||
}
|
||
return;
|
||
}
|
||
|
||
this._init();
|
||
}
|
||
|
||
/**
|
||
* 初始化事件管理器
|
||
* @private
|
||
*/
|
||
_init() {
|
||
this.container = document.querySelector(this.containerSelector);
|
||
if (!this.container) {
|
||
console.error(`[EventManager] 容器仍未找到: ${this.containerSelector}`);
|
||
return;
|
||
}
|
||
|
||
this._setupEventDelegation();
|
||
console.log('[EventManager] ✅ 事件委托已初始化');
|
||
}
|
||
|
||
/**
|
||
* 设置事件委托
|
||
* @private
|
||
*/
|
||
_setupEventDelegation() {
|
||
// ==========================================
|
||
// 单一点击事件监听器(所有按钮点击)
|
||
// ==========================================
|
||
this.container.addEventListener('click', (e) => {
|
||
// 查找最近的带有 data-action 的元素
|
||
const target = e.target.closest('[data-action]');
|
||
if (!target) return;
|
||
|
||
const action = target.dataset.action;
|
||
const index = target.dataset.index ? parseInt(target.dataset.index) : null;
|
||
|
||
console.log(`[EventManager] 触发操作: ${action}, 索引: ${index}`);
|
||
|
||
// 根据 action 分发到对应处理器
|
||
switch (action) {
|
||
case 'delete':
|
||
this._handleDelete(index, e);
|
||
break;
|
||
case 'resend':
|
||
this._handleResend(index, e);
|
||
break;
|
||
case 'copy':
|
||
this._handleCopy(index, e);
|
||
break;
|
||
case 'export-png':
|
||
this._handleExportPng(index, e);
|
||
break;
|
||
case 'toggle-reasoning':
|
||
this._handleToggleReasoning(index, e);
|
||
break;
|
||
case 'show-image':
|
||
this._handleShowImage(target.dataset.imageUrl, e);
|
||
break;
|
||
case 'open-mindmap':
|
||
this._handleOpenMindmap(target.dataset.mindmapUrl, e);
|
||
break;
|
||
case 'open-drawio':
|
||
this._handleOpenDrawio(target.dataset.drawioUrl, e);
|
||
break;
|
||
default:
|
||
console.warn(`[EventManager] 未知操作: ${action}`);
|
||
}
|
||
});
|
||
|
||
// ==========================================
|
||
// 键盘快捷键
|
||
// ==========================================
|
||
this.container.addEventListener('keydown', (e) => {
|
||
// Delete 键删除消息
|
||
if (e.key === 'Delete' && e.target.closest('.message-container')) {
|
||
const container = e.target.closest('.message-container');
|
||
const index = this._getMessageIndex(container);
|
||
if (index !== null) {
|
||
console.log(`[EventManager] 键盘删除消息 #${index}`);
|
||
this._handleDelete(index, e);
|
||
}
|
||
}
|
||
});
|
||
|
||
console.log('[EventManager] 事件监听器已绑定');
|
||
}
|
||
|
||
/**
|
||
* 从消息容器获取索引
|
||
* @param {HTMLElement} container - 消息容器元素
|
||
* @returns {number|null} 消息索引
|
||
* @private
|
||
*/
|
||
_getMessageIndex(container) {
|
||
const btn = container.querySelector('[data-index]');
|
||
return btn ? parseInt(btn.dataset.index) : null;
|
||
}
|
||
|
||
// ==========================================
|
||
// 事件处理器
|
||
// ==========================================
|
||
|
||
/**
|
||
* 删除消息
|
||
* @param {number} index - 消息索引
|
||
* @param {Event} event - 原始事件对象
|
||
* @private
|
||
*/
|
||
_handleDelete(index, event) {
|
||
event.stopPropagation();
|
||
console.log(`[EventManager] 🗑️ 删除消息 #${index}`);
|
||
|
||
if (window.ChatbotActions && typeof window.ChatbotActions.deleteMessage === 'function') {
|
||
window.ChatbotActions.deleteMessage(index);
|
||
} else {
|
||
console.error('[EventManager] ChatbotActions.deleteMessage 未定义');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 重新发送消息
|
||
* @param {number} index - 消息索引
|
||
* @param {Event} event - 原始事件对象
|
||
* @private
|
||
*/
|
||
_handleResend(index, event) {
|
||
event.stopPropagation();
|
||
console.log(`[EventManager] 🔄 重发消息 #${index}`);
|
||
|
||
if (window.ChatbotActions && typeof window.ChatbotActions.resendUserMessage === 'function') {
|
||
window.ChatbotActions.resendUserMessage(index);
|
||
} else {
|
||
console.error('[EventManager] ChatbotActions.resendUserMessage 未定义');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 复制消息内容
|
||
* @param {number} index - 消息索引
|
||
* @param {Event} event - 原始事件对象
|
||
* @private
|
||
*/
|
||
_handleCopy(index, event) {
|
||
event.stopPropagation();
|
||
console.log(`[EventManager] 📋 复制消息 #${index}`);
|
||
|
||
if (window.ChatbotUtils && typeof window.ChatbotUtils.copyAssistantMessage === 'function') {
|
||
window.ChatbotUtils.copyAssistantMessage(index);
|
||
} else {
|
||
console.error('[EventManager] ChatbotUtils.copyAssistantMessage 未定义');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 导出消息为 PNG
|
||
* @param {number} index - 消息索引
|
||
* @param {Event} event - 原始事件对象
|
||
* @private
|
||
*/
|
||
_handleExportPng(index, event) {
|
||
event.stopPropagation();
|
||
console.log(`[EventManager] 📸 导出消息 #${index} 为 PNG`);
|
||
|
||
if (window.ChatbotUtils && typeof window.ChatbotUtils.exportMessageAsPng === 'function') {
|
||
window.ChatbotUtils.exportMessageAsPng(index);
|
||
} else {
|
||
console.error('[EventManager] ChatbotUtils.exportMessageAsPng 未定义');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 切换思考过程显示/隐藏
|
||
* @param {number} index - 消息索引
|
||
* @param {Event} event - 原始事件对象
|
||
* @private
|
||
*/
|
||
_handleToggleReasoning(index, event) {
|
||
event.stopPropagation();
|
||
console.log(`[EventManager] 🧠 切换思考过程 #${index}`);
|
||
|
||
// 切换折叠状态
|
||
const collapseKey = `reasoningCollapsed_${index}`;
|
||
window[collapseKey] = !window[collapseKey];
|
||
|
||
// 更新 UI
|
||
if (window.ChatbotUI && typeof window.ChatbotUI.updateChatbotUI === 'function') {
|
||
window.ChatbotUI.updateChatbotUI();
|
||
} else {
|
||
console.error('[EventManager] ChatbotUI.updateChatbotUI 未定义');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 显示图片模态框
|
||
* @param {string} imageUrl - 图片 URL
|
||
* @param {Event} event - 原始事件对象
|
||
* @private
|
||
*/
|
||
_handleShowImage(imageUrl, event) {
|
||
event.stopPropagation();
|
||
console.log(`[EventManager] 🖼️ 显示图片: ${imageUrl}`);
|
||
|
||
if (window.ChatbotImageUtils && typeof window.ChatbotImageUtils.showImageModal === 'function') {
|
||
window.ChatbotImageUtils.showImageModal(imageUrl);
|
||
} else {
|
||
console.error('[EventManager] ChatbotImageUtils.showImageModal 未定义');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 打开思维导图
|
||
* @param {string} mindmapUrl - 思维导图 URL
|
||
* @param {Event} event - 原始事件对象
|
||
* @private
|
||
*/
|
||
_handleOpenMindmap(mindmapUrl, event) {
|
||
event.stopPropagation();
|
||
console.log(`[EventManager] 🗺️ 打开思维导图: ${mindmapUrl}`);
|
||
|
||
if (mindmapUrl) {
|
||
window.open(mindmapUrl, '_blank');
|
||
} else {
|
||
console.error('[EventManager] 思维导图 URL 为空');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 打开 draw.io 配图编辑器
|
||
* @param {string} drawioUrl - draw.io 视图 URL
|
||
* @param {Event} event - 原始事件对象
|
||
* @private
|
||
*/
|
||
_handleOpenDrawio(drawioUrl, event) {
|
||
event.stopPropagation();
|
||
console.log(`[EventManager] 🧩 打开配图编辑器: ${drawioUrl}`);
|
||
|
||
if (drawioUrl) {
|
||
window.open(drawioUrl, '_blank');
|
||
} else {
|
||
console.error('[EventManager] 配图编辑器 URL 为空');
|
||
}
|
||
}
|
||
|
||
// ==========================================
|
||
// 公共方法
|
||
// ==========================================
|
||
|
||
/**
|
||
* 销毁事件管理器
|
||
* (事件委托会自动清理,无需手动移除)
|
||
*/
|
||
destroy() {
|
||
console.log('[EventManager] 🧹 已销毁');
|
||
// 事件委托模式下,只需要移除容器上的监听器即可
|
||
// 由于我们在容器上绑定,GC 会自动处理
|
||
}
|
||
|
||
/**
|
||
* 重新初始化(用于动态更换容器)
|
||
* @param {string} newContainerSelector - 新容器选择器
|
||
*/
|
||
reinit(newContainerSelector) {
|
||
console.log(`[EventManager] 🔄 重新初始化: ${newContainerSelector}`);
|
||
this.containerSelector = newContainerSelector;
|
||
this._init();
|
||
}
|
||
}
|
||
|
||
// ==========================================
|
||
// 导出到全局
|
||
// ==========================================
|
||
window.ChatMessageEventManager = ChatMessageEventManager;
|
||
|
||
console.log('[ChatMessageEventManager] 类定义已加载');
|