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

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>

问题分析

  1. 预览容器每次通过empty()清空,导致之前的预览丢失
  2. 文件输入框的files对象为只读,每次选择会直接替换原有内容,无法保留历史选中文件
  3. 按钮文本仅显示当前选择的文件数量,未统计总选中数
  4. 后端模型若为单个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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 05:01:36