ASP.NET Core MVC表单实现多次选择图片不覆盖原有选择
ASP.NET Core MVC 实现可多次选择不覆盖的图片上传预览
问题场景
需要实现一个图片上传表单,要求点击选择按钮可单张/批量选图,再次点击时能继续选择,不会覆盖之前已选的图片。但当前代码每次选图都会清空之前的预览,且提交时只能传递最后一次选择的文件。
原代码
<div class="row"> <input type="file" name="imge1" id="file" asp-for="imge1" class="hidden" multiple> <button type="button" class="btn btn-primary" id="filebutton"><span id="filetext">Select File</span></button> <div id="preview" style="column-gap: 25px;"></div> </div> <div id="image_preview"></div> <script> $(document).ready(function () { $('#filebutton').click(function () { $('#file').click(); }); $('#file').change(function () { var name = $(this).val().split('\\').pop(); var file = $(this)[0].files; if (name != '') { if (file.length >= 2) { $('#filetext').html(file.length + ' files ready to upload'); } else { $('#filetext').html(name); } } }); $('#file').on("change", previewImages); }); function previewImages() { var $preview = $('#preview').empty(); if (this.files) $.each(this.files, readAndPreview); function readAndPreview(i, file) { if (!/\.(jpe?g|png|gif)$/i.test(file.name)) { return alert(file.name + " is not an image"); } var reader = new FileReader(); $(reader).on("load", function () { $preview.append($("<img>", { src: this.result, height: 80, })); }); reader.readAsDataURL(file); } } </script>
问题分析
- 预览容器每次通过
empty()清空,导致之前的预览丢失 - 文件输入框的
files对象为只读,每次选择会直接替换原有内容,无法保留历史选中文件 - 按钮文本仅显示当前选择的文件数量,未统计总选中数
- 后端模型若为单个
IFormFile类型,无法接收批量文件
解决方案
1. 核心修改思路
- 用全局数组存储所有选中的有效文件,避免每次选择覆盖原有内容
- 修改预览逻辑,仅追加新选择的图片预览,保留历史预览
- 动态更新按钮文本为总选中文件数
- 后端模型改用
List<IFormFile>类型接收批量文件
2. 修改后完整代码
HTML 部分(调整绑定属性与文件格式限制)
<div class="row"> <input type="file" name="Images" id="file" asp-for="Images" class="hidden" multiple accept="image/jpeg,image/png,image/gif"> <button type="button" class="btn btn-primary" id="filebutton"><span id="filetext">Select File</span></button> <div id="preview" style="column-gap: 25px; margin-top: 10px;"></div> </div>
JavaScript 部分(新增全局文件管理与增量预览)
$(document).ready(function () { // 全局数组存储所有选中的有效文件 let selectedFiles = []; $('#filebutton').click(function () { $('#file').click(); }); $('#file').change(function () { const newFiles = Array.from(this.files); // 过滤重复文件(可选,按文件名判断) const uniqueFiles = newFiles.filter(file => !selectedFiles.some(f => f.name === file.name)); // 将新文件追加到全局数组 selectedFiles = [...selectedFiles, ...uniqueFiles]; // 更新按钮文本 updateButtonText(); // 仅预览新选择的文件 previewNewImages(uniqueFiles); }); // 更新按钮显示文本 function updateButtonText() { if (selectedFiles.length === 0) { $('#filetext').text('Select File'); } else if (selectedFiles.length === 1) { $('#filetext').text(selectedFiles[0].name); } else { $('#filetext').text(`${selectedFiles.length} files ready to upload`); } } // 预览新选中的图片 function previewNewImages(files) { const $preview = $('#preview'); if (files) $.each(files, readAndPreview); function readAndPreview(i, file) { // 验证图片格式 if (!/\.(jpe?g|png|gif)$/i.test(file.name)) { alert(`${file.name} 不是有效的图片文件`); // 从全局数组移除无效文件 selectedFiles = selectedFiles.filter(f => f.name !== file.name); updateButtonText(); return; } const reader = new FileReader(); $(reader).on("load", function () { $preview.append($("<img>", { src: this.result, height: 80, style: "margin-bottom: 10px;" })); }); reader.readAsDataURL(file); } } });
后端模型与控制器示例
// 上传视图模型 public class UploadViewModel { [Display(Name = "Images")] public List<IFormFile> Images { get; set; } } // 控制器方法 [HttpPost] public async Task<IActionResult> Upload(UploadViewModel model) { if (model.Images != null && model.Images.Count > 0) { var uploadPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/uploads"); // 确保上传目录存在 if (!Directory.Exists(uploadPath)) { Directory.CreateDirectory(uploadPath); } foreach (var file in model.Images) { if (file.Length > 0) { var filePath = Path.Combine(uploadPath, file.FileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } } } } return RedirectToAction("Index"); }
内容的提问来源于stack exchange,提问作者Creative Things
相关产品推荐
相关产品推荐

