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

基于ASP.Net Core MVC实现复选框联动动态Dropzone表单

问题

我正在开发ASP.NET Core MVC项目,现有如下复选框:

<div class="form-check form-check-inline">
  <input class="form-check-input" type="checkbox" id="10" value="10">
  <label class="form-check-label" for="10">10sec</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="checkbox" id="15" value="15">
  <label class="form-check-label" for="15">15sec</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="checkbox" id="30" value="30">
  <label class="form-check-label" for="30">30sec</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="checkbox" id="45" value="45">
  <label class="form-check-label" for="45">45sec</label>
</div>

我希望根据勾选的复选框动态添加带有Dropzone上传组件的卡片,目前仅能实现单个Dropzone的逻辑,想知道如何为所有复选框实现独立的动态Dropzone组件,也希望用更优的动态实现方式。

之前的单例实现示例如下:

function myFunction() {
  var checkBox = document.getElementById("10");
  var text = document.getElementById("10secs");
  if (checkBox.checked == true) {
    text.style.display = "block";
  } else {
    text.style.display = "none";
  }
}

//dropzone script
var myDropzone = new Dropzone("#mydropzone", {
  url: "/test/create",
  maxFilesize: 3.0,
  uploadMultiple: false,
  createImageThumbnails: false,
  addRemoveLinks: true,
  removedfile: function(file) {
    var name = file.name;
    file.previewElement.remove();
    $.ajax({
      type: 'POST',
      url: '/test/delete',
      data: "fileName=" + name,
      dataType: 'html'
    });
  },
  maxFiles: 1,
  maxfilesexceeded: function(file) {
    this.removeAllFiles();
    this.addFile(file);
  },
  init: function() {
    var drop = this;
    this.on('error', function(file, errorMessage) {
      if (errorMessage.indexOf('Error 404') !== -1) {
        var errorDisplay = document.querySelectorAll('[data-dz-errormessage]');
        errorDisplay[errorDisplay.length - 1].innerHTML = 'Error 404: The upload page was not found on the server';
      }
      if (errorMessage.indexOf('File is too big') !== -1) {
        alert('i remove current file');
        drop.removeFile(file);
      }
    });
  }
});
<script src="https://unpkg.com/dropzone@5.9.3/dist/dropzone.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/basic.css" rel="stylesheet" />

<div class="form-check form-check-inline">
  <input class="form-check-input" type="checkbox" id="10" value="10" onclick="myFunction()">
  <label class="form-check-label" for="10">10sec</label>
</div>

<div class="row" id="10secs" style="display: none">
  <div class="col-lg-12">
    <div class="card">
      <div class="card-header">
        <h4 class="card-title">30sec</h4>
      </div>
      <div class="card-body">
        <div>
          <div class="clsbox-1">
            <div class="dropzone clsbox" id="mydropzone">
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
解决方案

核心思路

通过数据属性关联复选框与动态卡片,用通用逻辑处理所有复选框的勾选事件,动态生成唯一ID的Dropzone容器,同时维护已初始化的Dropzone实例集合,避免重复创建。


1. 重构HTML结构

给复选框添加统一类名,准备卡片挂载容器,去掉硬编码的静态卡片:

<script src="https://unpkg.com/dropzone@5.9.3/dist/dropzone.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/basic.css" rel="stylesheet" />

<!-- 复选框组 -->
<div class="form-check-group">
  <div class="form-check form-check-inline">
    <input class="form-check-input duration-checkbox" type="checkbox" id="10" value="10">
    <label class="form-check-label" for="10">10sec</label>
  </div>
  <div class="form-check form-check-inline">
    <input class="form-check-input duration-checkbox" type="checkbox" id="15" value="15">
    <label class="form-check-label" for="15">15sec</label>
  </div>
  <div class="form-check form-check-inline">
    <input class="form-check-input duration-checkbox" type="checkbox" id="30" value="30">
    <label class="form-check-label" for="30">30sec</label>
  </div>
  <div class="form-check form-check-inline">
    <input class="form-check-input duration-checkbox" type="checkbox" id="45" value="45">
    <label class="form-check-label" for="45">45sec</label>
  </div>
</div>

<!-- 动态卡片挂载容器 -->
<div id="card-container" class="mt-3"></div>

2. 通用JavaScript逻辑

实现动态创建卡片、初始化独立Dropzone、管理实例的功能:

// 维护已创建的Dropzone实例,key为时长值
const dropzoneInstances = {};

// 监听所有复选框的勾选事件
document.querySelectorAll('.duration-checkbox').forEach(checkbox => {
  checkbox.addEventListener('change', handleCheckboxChange);
});

function handleCheckboxChange(e) {
  const duration = e.target.value;
  const isChecked = e.target.checked;
  const cardId = `card-${duration}`;
  const dropzoneId = `dropzone-${duration}`;

  if (isChecked) {
    // 动态生成卡片HTML
    const cardHtml = `
      <div class="row" id="${cardId}">
        <div class="col-lg-12">
          <div class="card">
            <div class="card-header">
              <h4 class="card-title">${duration}sec</h4>
            </div>
            <div class="card-body">
              <div class="clsbox-1">
                <div class="dropzone clsbox" id="${dropzoneId}"></div>
              </div>
            </div>
          </div>
        </div>
      </div>
    `;
    // 插入到容器中
    document.getElementById('card-container').insertAdjacentHTML('beforeend', cardHtml);
    
    // 初始化Dropzone并保存实例
    dropzoneInstances[duration] = new Dropzone(`#${dropzoneId}`, {
      url: `/test/create?duration=${duration}`, // 传递时长参数给后端
      maxFilesize: 3.0,
      uploadMultiple: false,
      createImageThumbnails: false,
      addRemoveLinks: true,
      removedfile: function(file) {
        const name = file.name;
        file.previewElement.remove();
        // 删除请求也携带时长参数
        $.ajax({
          type: 'POST',
          url: `/test/delete?duration=${duration}`,
          data: { fileName: name },
          dataType: 'html'
        });
      },
      maxFiles: 1,
      maxfilesexceeded: function(file) {
        this.removeAllFiles();
        this.addFile(file);
      },
      init: function() {
        const drop = this;
        this.on('error', function(file, errorMessage) {
          if (errorMessage.includes('Error 404')) {
            const errorDisplay = document.querySelectorAll('[data-dz-errormessage]');
            errorDisplay[errorDisplay.length - 1].textContent = 'Error 404: 服务器未找到上传页面';
          }
          if (errorMessage.includes('File is too big')) {
            alert('文件过大,已移除当前文件');
            drop.removeFile(file);
          }
        });
      }
    });
  } else {
    // 取消勾选时,销毁Dropzone实例并移除卡片
    if (dropzoneInstances[duration]) {
      dropzoneInstances[duration].destroy();
      delete dropzoneInstances[duration];
    }
    const card = document.getElementById(cardId);
    if (card) card.remove();
  }
}

3. ASP.NET Core后端适配

修改控制器接口,接收duration参数来区分不同时长的上传目录:

public class TestController : Controller
{
    // 上传接口
    [HttpPost]
    public IActionResult Create(IFormFile file, int duration)
    {
        // 根据duration指定不同的存储路径
        var uploadPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads", duration.ToString());
        if (!Directory.Exists(uploadPath))
        {
            Directory.CreateDirectory(uploadPath);
        }

        var filePath = Path.Combine(uploadPath, file.FileName);
        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            file.CopyTo(stream);
        }

        return Ok();
    }

    // 删除接口
    [HttpPost]
    public IActionResult Delete(string fileName, int duration)
    {
        var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads", duration.ToString(), fileName);
        if (System.IO.File.Exists(filePath))
        {
            System.IO.File.Delete(filePath);
        }

        return Ok();
    }
}

优势说明

  • 通用性:一套逻辑适配所有复选框,新增时长选项只需添加复选框,无需修改JS代码
  • 独立性:每个Dropzone实例完全独立,上传/删除操作互不干扰
  • 资源回收:取消勾选时销毁Dropzone实例并移除DOM,避免内存泄漏
  • 后端区分:通过duration参数实现不同时长的文件隔离存储

内容的提问来源于stack exchange,提问作者Jesus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 03:05:41