You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

jQuery拖拽/点击上传音频文件旧文件被覆盖,如何修改实现文件追加?

问题原因
  • 每次文件选择/拖拽触发input的change事件时,代码先主动清空了finalFiles存储对象和#filename列表容器的内容,导致旧文件被清除
  • 新增文件的索引直接用当前批次的下标,和历史存储的索引重复,会覆盖旧的存储条目
  • 所有音频元素共用相同的固定IDaudioFiles,不符合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>&nbsp;' + 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 12:09:02