jQuery拖拽/点击上传音频文件旧文件被覆盖,如何修改实现文件追加?
问题原因
- 每次文件选择/拖拽触发
input的change事件时,代码先主动清空了finalFiles存储对象和#filename列表容器的内容,导致旧文件被清除 - 新增文件的索引直接用当前批次的下标,和历史存储的索引重复,会覆盖旧的存储条目
- 所有音频元素共用相同的固定ID
audioFiles,不符合DOM规范,会导致音频时长读取、元素操作异常 - 新增元素后没有重新初始化sortable拖拽功能,新添加的文件无法拖拽排序
修复后的完整JS代码
var dropZoneId = "drop-zone"; var buttonId = "clickHere"; var mouseOverClass = "mouse-over"; var dropZone = $("#" + dropZoneId); var inputFile = dropZone.find("input"); var finalFiles = {}; // Function $(function() { var ooleft = dropZone.offset().left; var ooright = dropZone.outerWidth() + ooleft; var ootop = dropZone.offset().top; var oobottom = dropZone.outerHeight() + ootop; document.getElementById(dropZoneId).addEventListener("dragover", function(e) { e.preventDefault(); e.stopPropagation(); dropZone.addClass(mouseOverClass); var x = e.pageX; var y = e.pageY; if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) { inputFile.offset({ top: y - 15, left: x - 100 }); } else { inputFile.offset({ top: -400, left: -400 }); } }, true); if (buttonId != "") { var clickZone = $("#" + buttonId); var oleft = clickZone.offset().left; var oright = clickZone.outerWidth() + oleft; var otop = clickZone.offset().top; var obottom = clickZone.outerHeight() + otop; $("#" + buttonId).mousemove(function(e) { var x = e.pageX; var y = e.pageY; if (!(x < oleft || x > oright || y < otop || y > obottom)) { inputFile.offset({ top: y - 15, left: x - 160 }); } else { inputFile.offset({ top: -400, left: -400 }); } }); } document.getElementById(dropZoneId).addEventListener("drop", function(e) { $("#" + dropZoneId).removeClass(mouseOverClass); }, true); // 初始化拖拽排序 initSortable(); // FILE inputFile.on('change', function(e) { // 移除原有清空逻辑,保留历史文件 var fileNum = this.files.length, // 索引起始值取当前已有文件数量,避免重复 startIdx = Object.keys(finalFiles).length, initial = 0; $.each(this.files, function(idx, elm) { finalFiles[startIdx + idx] = elm; }); for (initial; initial < fileNum; initial++) { var currentIdx = startIdx + initial; // Object URL var file = e.currentTarget.files[initial]; var objectUrl = URL.createObjectURL(file); // 音频ID动态生成,把资源地址存在元素属性上方便后续释放 $('#filename').append('<div class="playlist draggable" id="file_' + currentIdx + '" data-url="' + objectUrl + '"><span class="fa-stack fa-lg"><i class="fa fa-file-audio-o"></i><strong class="fa-stack-1x" style="color:#FFF; font-size:12px; margin-top:2px;"></strong></span> ' + '<audio controls controlsList="nodownload noplaybackrate" preload="auto" id="audioFiles_' + currentIdx + '" >' + '<source src="' + objectUrl + '" type="audio/mpeg" />' + '</audio>' + '<span class="fa fa-times-circle fa-lg closeBtn" onclick="removeLine(this)" title="remove"></span> ' + this.files[initial].name + '</div>'); console.log('NAME: ', this.files[initial].name); // 绑定动态ID的音频时长读取事件 $(`#audioFiles_${currentIdx}`).on("canplay", function() { console.log('THIS DURATION: ', this.duration); }); } // 新增元素后重新初始化拖拽功能 initSortable(); // Total File Count var count = $('#filename').children().length; console.log('Number of files: ', count); $('#totalFiles').css("display", "initial"); $('#totalFiles').html('<font style="color:#06a7e5">Files Uploaded: ' + '<b>' + count + '</b>' + '</font>'); // 清空input值,允许重复选择相同文件 inputFile.val(''); }); }) // 封装拖拽初始化方法 function initSortable() { $('.draggable, .droppable').sortable({ connectWith: '.playlists' }); } function removeLine(obj) { var jqObj = $(obj); var container = jqObj.closest('div'); var index = container.attr("id").split('_')[1]; // 读取元素上存储的资源地址释放,避免内存泄漏 var targetUrl = container.data('url'); container.remove(); delete finalFiles[index]; URL.revokeObjectURL(targetUrl); // Total Files var count = $('#filename').children().length; console.log('Number of files: ', count); $('#totalFiles').html('<font style="color:#06a7e5">Files Uploaded: ' + '<b>' + count + '</b>' + '</font>'); if (count == 0) { $('#totalFiles').css("display", "none"); } }
额外说明
原有CSS和HTML代码不需要修改,替换上述JS代码即可实现新添加文件追加到列表的需求,同时修复了原代码存在的拖拽功能异常、内存泄漏、音频ID重复的问题。
内容的提问来源于stack exchange,提问作者Mellow Monk
相关产品推荐
相关产品推荐

