Dropzone点击删除按钮多次触发XHR请求问题求助
问题原因及解决方法
你的问题核心是重复绑定了点击事件:
- 每次
complete事件触发(包括上传新文件、初始化加载已有mock文件时),你都通过$(".dz-remove").on('click', ...)给页面上所有的删除按钮绑定一次点击事件 - 当有n个文件时,每个删除按钮会被绑定n次点击事件,点击一次就会执行n次删除请求
解决思路
不要全局绑定所有删除按钮的点击事件,改用以下两种更规范的方式:
方案一:使用Dropzone原生removedfile事件(推荐)
Dropzone自带removedfile事件,当点击删除按钮时会自动触发该事件,无需手动绑定点击事件,从根源避免重复绑定问题。
修改你的Dropzone配置中的init部分:
init: function() { this.on("success", function(file, serverResponse) { var fileuploded = file.previewElement.querySelector("[data-dz-name]"); fileuploded.innerHTML = serverResponse.newfilename; // 给file对象存储图片ID,方便删除时使用 file.imageId = serverResponse.newfilename; }); this.on("addedfile", function(file) { file.previewElement.querySelector('[data-dz-name]').textContent = file.upload?.filename || file.name; }); // 替换原来的complete事件里的点击绑定,改用removedfile事件 this.on("removedfile", function(file) { // 如果是初始化加载的mock文件,从file对象取name作为imageId let imageId = file.imageId || file.name; if (!imageId) return; let uri = endpoint + `/${imageId}`; axios.delete(uri) .then(response => { console.log(`Deleted photo with ID ${imageId}`); }) .catch(error => { console.error(error); }); }); let thisDropzone = this; axios.get(endpoint) .then(response => { this.data = response.data; this.data.forEach(function(item) { let mockFile = {"name": item.name, "request": item.request, "size": item.size, "path": item.path}; // 给mock文件存储imageId mockFile.imageId = item.name; thisDropzone.options.addedfile.call(thisDropzone, mockFile); thisDropzone.options.thumbnail.call(thisDropzone, mockFile, mockFile.path); thisDropzone.emit("complete", mockFile); }); }) .catch(error => { console.error(`Error fetching request ${this.request.id}`, error) }) }
改动说明:
- 在
success事件中,把返回的serverResponse.newfilename存储到file.imageId属性中,方便删除时直接获取 - 初始化mock文件时,同样给
mockFile添加imageId属性 - 移除
complete事件中对.dz-remove的点击绑定,改用removedfile事件处理删除逻辑 - 在
removedfile事件中,直接从当前file对象获取imageId,无需通过DOM查找,更可靠
方案二:针对单个删除按钮绑定事件(避免全局重复绑定)
如果坚持手动绑定点击事件,需要确保只给当前文件对应的删除按钮绑定一次,并且先解绑再绑定:
修改complete事件的代码:
// 先在init顶部定义thisDropzone,方便内部使用 let thisDropzone = this; this.on("complete", function(file) { // 只获取当前file对应的previewElement里的删除按钮 const $removeBtn = $(file.previewElement).find(".dz-remove"); // 先解绑原有事件,再绑定新事件,避免重复绑定 $removeBtn.off('click').html("<div><span class='fa fa-trash text-danger' style='font-size: 1.5em'></span></div>").on('click', function(e) { e.preventDefault(); e.stopPropagation(); let imageId = $(this).parent().find(".dz-filename > span").text(); let uri = endpoint + `/${imageId}`; axios.delete(uri) .then(response => { console.log(`Deleted photo with ID ${imageId}`); // 手动调用Dropzone的removeFile方法,移除预览元素 thisDropzone.removeFile(file); }) .catch(error => { console.error(error); }); }); });
改动说明:
- 通过
file.previewElement定位到当前文件的预览容器,只获取该容器内的删除按钮,而不是全局所有.dz-remove - 使用
.off('click')先解绑之前可能绑定的事件,再绑定新事件,避免重复绑定 - 删除成功后调用
thisDropzone.removeFile(file),让Dropzone正确移除预览元素
内容的提问来源于stack exchange,提问作者Jchieppa
相关产品推荐
相关产品推荐

