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

Laravel中Dropzone.js多图更新时请求无文件值的解决问询

Dropzone.js多图更新时无法获取文件请求值的解决方法

我使用Dropzone.js实现多图拖拽上传功能,新增(store)图片时可正常上传,但更新多图时,执行dd(request()->all())无法获取到多图文件值,仅能获取表单字段值。我已尝试设置paramName为'file',但仍无法获取文件请求值。请问如何实现多图更新并获取请求中的文件值存入数据表?

提供的edit.blade.php代码

JavaScript部分

let companyId = @json($companies);
Dropzone.autoDiscover = false;
document.addEventListener('DOMContentLoaded', function(e) {
    $(document).ready(function() {
        (function() {
            var myDropzone = new Dropzone("#multipleFileUpload", {
                url: '/admin/company/update/' + companyId,
                method: 'POST',
                paramName: 'file',
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                },
                acceptedFiles: ".jpg,.png,.jpeg",
                maxFiles: 999,
                maxFilesize: 2,
                addRemoveLinks: true,
                uploadMultiple: false,
                autoProcessQueue: false,
                parallelUploads: 999,
                dictCancelUpload: "Cancel",
                dictDefaultMessage: "Please drag & drop images here",
                timeout: 5000,
                init: function() {
                    dzClosure = this; // Makes sure that 'this' is understood inside the functions below.

                    // for Dropzone to process the queue (instead of default form behavior):
                    document.getElementById("submitButton").addEventListener(
                        "click",
                        function(e) {
                            // Make sure that the form isn't actually being sent.
                            e.preventDefault();
                            e.stopPropagation();
                            dzClosure.processQueue();
                        });

                    // send all the form data along with the files:
                    this.on("sendingmultiple", function(data, xhr, formData) {
                        formData.append("name", jQuery("#name").val());
                        formData.append("email", jQuery("#email").val());

                        formData.append("dropzone", jQuery("#multipleFileUpload").val());

                        formData.append("file", document.getElementById('multipleFileUpload'));

                        formData.append("logo", document.getElementById('companyLogo').files[0]);

                        formData.append("phone_number", jQuery("#phoneNumber").val());
                        formData.append("fax_number", jQuery("#faxNumber").val());
                        formData.append("address1", jQuery("#address1").val());
                        formData.append("address2", jQuery("#address2").val());
                        formData.append("city", jQuery("#city").val());
                        formData.append("postcode", jQuery("#postcode").val());
                        formData.append("state", jQuery("#state").val());
                        formData.append("country", jQuery("#country").val());
                        formData.append("longitude", jQuery("#longitude").val());
                        formData.append("latitude", jQuery("#latitude").val());
                    });
                },
                success: function(file, response) {
                    Swal.fire({
                        title: 'Success!',
                        text: 'Image added successfully',
                        confirmButtonText: 'Ok',
                    }).then(function() {
                        window.location.href = "{{ route('admin.company.index') }}";
                    });
                },
                error: function() {
                    return false;
                },
                init: function() {
                    var submitButton = document.querySelector("#submit");
                    myDropzone = this;
                    submitButton.addEventListener("click", function() {
                        myDropzone.processQueue();
                    });

                    this.on('complete', function() {
                        if (this.getQueuedFiles().length == 0 && this.getUploadingFiles().length == 0) {
                            var _this = this;
                            _this.removeAllFiles();
                        }
                    });
                }
            });
        })();
    });
});

HTML部分

<div class="col-12 form-group">
    <div class="card">
        <div class="card-header">Image Upload</div>
        <div class="card-body">
            <div class="dropzone" id="multipleFileUpload" name="dropzone">
                @foreach ($companies->images as $image)
                    <div class="img-wrap">
                        <a href="#" onclick="deleteImage({{ $image->id }})"
                            class="close btn-delete btn-image-delete"
                            id="btn-delete"
                            data-image-id={{ $image->id }}>&times;</a>
                        <img class="image-dropzone"
                            src="{{ asset($image->location) }}" width="100px"
                            height="100px" alt="image"
                            style="background-position: center background-attachment: fixed;"
                            data-image-id="{{ $image->id }}" name="images">
                    </div>
                @endforeach
                <input type="hidden" name="upload_image"
                    value="{{ $image->id }}">
            </div>
        </div>
    </div>
</div>

问题分析与解决方案

核心问题

  1. 重复定义init方法:代码中写了两个init,后一个会覆盖前一个,导致sendingmultiple事件未被绑定,同时提交按钮的逻辑冲突。
  2. 错误手动添加file字段:在sendingmultiple里手动追加formData.append("file", document.getElementById('multipleFileUpload'));,传入的是DOM元素而非实际上传的文件,干扰了Dropzone的自动文件处理。
  3. uploadMultiple配置关闭:当前设置uploadMultiple: false,Dropzone会逐个上传文件,而非批量提交,导致后端无法一次性获取所有文件。

修复步骤

  1. 合并init方法:将两个init里的逻辑整合到一个方法中,避免覆盖。
  2. 移除手动添加的file字段:Dropzone会自动处理选中的文件,无需手动追加。
  3. 开启多文件上传模式:设置uploadMultiple: true,让Dropzone批量提交文件数组。
  4. 添加删除图片的标记逻辑:给已有图片的删除按钮绑定事件,将待删除的图片ID存入隐藏字段,后端更新时处理删除操作。
  5. 后端正确接收文件:后端通过request()->file('file')获取文件数组,循环处理每个文件的上传。

修改后的关键代码示例

JavaScript部分(合并后的init)

init: function() {
    const dzClosure = this;
    // 绑定提交按钮事件
    const submitButton = document.querySelector("#submit");
    submitButton.addEventListener("click", function(e) {
        e.preventDefault();
        e.stopPropagation();
        dzClosure.processQueue();
    });

    // 绑定sendingmultiple事件,追加表单数据
    this.on("sendingmultiple", function(data, xhr, formData) {
        // 追加表单字段
        formData.append("name", jQuery("#name").val());
        formData.append("email", jQuery("#email").val());
        formData.append("logo", document.getElementById('companyLogo').files[0]);
        formData.append("phone_number", jQuery("#phoneNumber").val());
        // ... 其他表单字段省略
        // 追加待删除的图片ID
        formData.append("delete_images", JSON.stringify(window.deleteImageIds || []));
    });

    // 上传完成后清空队列
    this.on('complete', function() {
        if (this.getQueuedFiles().length === 0 && this.getUploadingFiles().length === 0) {
            this.removeAllFiles();
        }
    });
},
uploadMultiple: true, // 开启多文件上传

删除图片的JS逻辑(新增)

// 全局存储待删除的图片ID
window.deleteImageIds = [];
function deleteImage(imageId) {
    // 确认删除
    if (confirm("确定要删除这张图片吗?")) {
        // 将ID加入待删除数组
        window.deleteImageIds.push(imageId);
        // 移除页面上的图片元素
        document.querySelector(`[data-image-id="${imageId}"]`).closest('.img-wrap').remove();
    }
}

后端处理示例(Laravel)

public function update(Request $request, $id)
{
    $company = Company::findOrFail($id);
    
    // 处理表单字段更新
    $company->update($request->only(['name', 'email', 'phone_number', ...]));
    
    // 处理新上传的图片
    if ($request->hasFile('file')) {
        foreach ($request->file('file') as $file) {
            // 上传文件到存储
            $path = $file->store('company_images', 'public');
            // 保存到关联表
            $company->images()->create(['location' => $path]);
        }
    }
    
    // 处理待删除的图片
    if ($request->has('delete_images')) {
        $deleteIds = json_decode($request->delete_images);
        Image::whereIn('id', $deleteIds)->where('company_id', $company->id)->delete();
    }
    
    return redirect()->route('admin.company.index')->with('success', '更新成功');
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 08:27:11