Plugin.before拦截文件发送异步交互失效及files读取报错修复求助
问题解决:拦截文件发送并等待用户确认
问题背景
我通过Plugin.before("Service.sendFile")拦截文件发送流程,需求是在发送前弹出带「发送」「取消」按钮的对话框,必须等用户点击按钮后再处理:点击发送则返回原数据继续发送,点击取消则终止流程。
当前遇到两个问题:
- 初始同步方案:选择图片后直接返回
null,根本没等到用户点击按钮就执行了返回逻辑 - Promise+async/await方案:报错「无法读取files未定义属性」
问题分析
- 初始方案失效原因:代码是同步执行的,用户点击按钮的回调是异步触发的,但主函数已经先执行到
return s ? data : null,此时s是undefined,直接返回null,完全没等待用户操作。 - Promise方案报错原因:通过
document.getElementById("cx_browse_file")从DOM取文件的方式不可靠——要么元素不存在,要么元素不是文件输入框,导致.files属性未定义;另外还存在弹窗重复创建、取消逻辑不明确的问题。
修正后的代码方案
1. 自定义确认弹窗函数
function showFileConfirmDialog(file) { // 清理已有弹窗,避免重复创建 const existingDialog = document.getElementById('myDialog'); if (existingDialog) { existingDialog.remove(); } return new Promise((resolve) => { // 创建弹窗(内置基础样式,可根据实际场景调整) const dialogHTML = ` <div id="myDialog" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 9999;"> <h3 style="margin-top: 0; font-size: 16px;">确认发送图片</h3> <img id="selectedImage" width="250" height="250" style="object-fit: contain; margin: 16px 0; border-radius: 4px;" /> <div style="display: flex; gap: 12px; justify-content: flex-end;"> <button id="cancel_button" style="padding: 8px 16px; border: 1px solid #ddd; border-radius: 4px; cursor: pointer;">取消</button> <button id="send_button" style="padding: 8px 16px; border: none; border-radius: 4px; background: #2563eb; color: #fff; cursor: pointer;">发送</button> </div> </div> `; document.body.insertAdjacentHTML('beforeend', dialogHTML); // 设置图片预览,并在弹窗销毁时释放URL对象 const imageUrl = URL.createObjectURL(file); document.getElementById('selectedImage').src = imageUrl; // 绑定按钮事件 document.getElementById('send_button').addEventListener('click', () => { document.getElementById('myDialog').remove(); URL.revokeObjectURL(imageUrl); resolve(true); }); document.getElementById('cancel_button').addEventListener('click', () => { document.getElementById('myDialog').remove(); URL.revokeObjectURL(imageUrl); resolve(false); }); }); }
2. 异步拦截器代码
Plugin.before("Service.sendFile", async function(data) { // 从拦截的data中获取文件对象(根据实际Service.sendFile的参数结构调整,这里假设data包含file或files数组) const targetFile = data.file || (data.files?.length > 0 ? data.files[0] : null); if (!targetFile) { // 无文件时直接终止流程 return null; } // 等待用户确认 const userConfirmed = await showFileConfirmDialog(targetFile); // 根据用户操作返回结果 return userConfirmed ? data : null; });
关键优化点
- 异步等待逻辑:利用async/await配合Promise,拦截器返回Promise,让插件等待用户操作完成后再继续流程(需确保插件支持异步拦截)
- 可靠获取文件:直接从拦截到的
data参数中取文件,避免操作DOM带来的元素不存在风险 - 弹窗管理:每次创建弹窗前清理旧弹窗,避免重复叠加
- 内存优化:使用
URL.revokeObjectURL释放预览图的临时URL,防止内存泄漏 - 明确终止逻辑:用户取消时返回
null,明确告知插件终止发送流程
内容的提问来源于stack exchange,提问作者Kamesh
相关产品推荐
相关产品推荐

