// 消息操作处理模块
import { customAlert, customConfirm } from './modal.js';
export function initMessageActions() {
document.addEventListener('click', async (e) => {
// 复制功能
const btn = e.target.closest('.btn-copy-markdown');
if (btn) {
e.stopPropagation();
const rawContentEl = btn.nextElementSibling;
if (rawContentEl && rawContentEl.classList.contains('raw-markdown')) {
const text = rawContentEl.textContent;
navigator.clipboard.writeText(text).then(() => {
const originalHTML = btn.innerHTML;
btn.innerHTML = '✅';
setTimeout(() => btn.innerHTML = originalHTML, 2000);
}).catch(async err => {
console.error('复制失败:', err);
await customAlert('复制失败');
});
}
}
// 删除消息
const delBtn = e.target.closest('.btn-delete-message');
if (delBtn) {
e.stopPropagation();
const messageEl = delBtn.closest('.message');
if (!messageEl) return;
const confirmed = await customConfirm('确定要删除这条消息吗?');
if (!confirmed) return;
const messageId = messageEl.dataset.messageId;
if (!messageId) {
await customAlert('无法删除未同步的消息,请刷新页面后重试。');
return;
}
try {
const res = await fetch(`/AiChat/DeleteMessage?messageId=${messageId}`, {
method: 'DELETE'
});
const result = await res.json();
if (result.success) {
messageEl.remove();
} else {
await customAlert(result.msg || '删除失败');
}
} catch (err) {
console.error('删除消息失败:', err);
await customAlert('删除失败: ' + err.message);
}
}
});
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
总体功能
- 这是一个消息操作处理模块,导出了一个初始化函数 initMessageActions()。调用该函数后,会在文档上添加一个全局点击事件监听器,负责处理“复制 Markdown 原文”和“删除消息”两类交互。
代码逐行功能说明
import 行
- 从
./modal.js导入customAlert和customConfirm,用于替代浏览器默认的 alert/confirm(通常是自定义弹窗)。
- 从
initMessageActions()
- 注册 document 的 click 事件(事件委托),在单个监听器中根据点击目标决定执行哪个操作。
复制功能(复制 Markdown 原文)
- 查找最近的匹配元素:
e.target.closest('.btn-copy-markdown')。如果存在该按钮,说明触发了复制操作。 - 调用
e.stopPropagation()阻止事件继续向上传播(避免其它点击处理器也响应)。 - 获取按钮的下一个兄弟元素
btn.nextElementSibling,并检查其是否具有raw-markdown类(假定该元素包含要复制的原始文本)。 - 读取其
textContent,调用navigator.clipboard.writeText(text)将文本写入剪贴板(返回 Promise)。 - 成功时用简单的视觉反馈:把按钮的
innerHTML改为 "✅",2 秒后还原为原始内容。 - 失败时打印错误并调用
customAlert('复制失败')弹窗提示用户。
- 查找最近的匹配元素:
删除消息
- 查找最近的匹配元素:
e.target.closest('.btn-delete-message')。如果存在该按钮,说明触发了删除操作。 - 调用
e.stopPropagation()。 - 找到包含该按钮的消息容器元素:
delBtn.closest('.message')。如果没有找到就直接返回。 - 弹出自定义确认框
customConfirm('确定要删除这条消息吗?'),用户拒绝则直接返回。 - 读取消息元素的
data-message-id(messageEl.dataset.messageId),若不存在则提示“无法删除未同步的消息,请刷新页面后重试。”并返回。 - 使用 fetch 发起 DELETE 请求到
/AiChat/DeleteMessage?messageId=${messageId},等待返回并解析为 JSON。 - 期待后端返回一个 JSON 对象,包含
success字段(布尔)和可选的msg文本:- 如果
result.success为 true,则从 DOM 中移除该消息元素messageEl.remove()。 - 否则弹出
customAlert(result.msg || '删除失败')。
- 如果
- 网络或解析异常时在控制台打印错误并弹出错误信息。
- 查找最近的匹配元素:
需要的 HTML/DOM 约束(代码假定的结构)
- 复制按钮:存在类名为
btn-copy-markdown的元素,其后紧跟一个类名为raw-markdown的兄弟元素,且该元素的 textContent 为要复制的文本。 - 删除按钮:存在类名为
btn-delete-message的元素,且其祖先中有一个类名为message的元素,并且该元素包含data-message-id属性用作标识。
涉及的浏览器 API 与行为
- navigator.clipboard.writeText:异步写剪贴板,某些环境(http vs https、权限)可能受限。
- Element.closest / nextElementSibling / classList:用于 DOM 查找和判断。
- fetch:异步网络请求,使用 DELETE 方法并期望 JSON 响应。
- 自定义弹窗:通过导入的 customAlert/customConfirm 控制用户提示与确认。
可能的注意点与改进建议(可选)
- clipboard API 在部分浏览器或非安全上下文(非 HTTPS)可能不可用,建议提供回退方案(比如临时 textarea 选中复制)。
- fetch URL 直接把 messageId 放在查询字符串里,注意编码(可用 encodeURIComponent)。
- 删除请求没有发送 CSRF token;如果后端需要防 CSRF,需要在请求头或 body 中携带相应 token。
- 对请求失败的提示信息可以更友好(例如针对网络超时和 4xx/5xx 分别处理)。
- 使用 innerHTML 修改按钮内容可能带来 XSS 风险或破坏子元素结构,若按钮包含复杂结构可改用 textContent 或专门的状态类来控制样式/图标变更。
如果需要,我可以帮你把这段代码改写为更健壮的版本(添加 clipboard 回退、CSRF 支持、错误级别区分等)。
评论加载中...