【问题标题】:Append Files in Input Type File with Multiple Before Uploading上传前在输入类型文件中附加多个文件
【发布时间】:2020-08-19 10:40:29
【问题描述】:

我的 laravel 网站上有一个表单,其中有一个部分允许用户上传多个图像文件(带有所选图像的预览)。如果用户只选择了多个图像一次,一切正常,并且所选图像被上传。但是,如果用户在提交表单之前在两个不同的场合选择了多张图片,则只会上传最后一组选择的图片。

例如;用户选择 4 张图片,然后填写表单上的其他一些字段,然后他们决定在提交表单之前在之前选择的 4 张图片之上再添加 3 张图片。图片预览框将包含他们选择的所有 7 张图片,但一旦提交表单,只会上传他们选择的最后 3 张图片。

HTML 多文件输入:

<input id="gphotos" type="file" name="gphotos[]" multiple>
<div class="preview"></div>

JavaScript:

function gphoto(input, ImagePreview) {
    if (input.files) {
        var fileAmount = input.files.length;

        for (i = 0; i < fileAmount; i++) {
            var reader = new FileReader();

            reader.onload = function(e) {
                $('.preview').css('margin-top', '4px');
                $($.parseHTML('<img class="gphoto">')).attr('src', e.target.result).appendTo(ImagePreview);
            }

            reader.readAsDataURL(input.files[i]);
        }
    }
};

$('#gphotos').change(function() {
    gphoto(this, 'div.preview');
});

控制器:

if (request('gphotos')) {
        $imageArray['gphotos'] = array();

        foreach (request()->gphotos as $gphoto) {
            $gphotoPath = $gphoto->store('gphotos', 'public');

            $imageArray['gphotos'][] =  $gphotoPath;
        }

        $imageArray['gphotos'] = json_encode($imageArray['gphotos']);
    }

我希望用户能够在提交表单之前在多个不同的场合选择多张图片,然后上传他们的所有图片。我已经尝试在整个互联网上搜索,但是对于这个看似简单的问题,没有人有一个简单的解决方案。如果有人能帮我解决这个问题,我将不胜感激。

【问题讨论】:

  • 如何提交文件。是通过 AJAX 还是不使用 JavaScript?
  • 没有 JavaScript
  • 好吧,当您更改表单的默认行为时,这种情况需要 JavaScript。您需要将上传的图像存储在容器中以收集它们。当您提交它们时,通过 AJAX 发送容器而不是实际发送表单。这样可以控制发送的内容。
  • 您能给我一个代码示例,说明如何实现这一目标吗?

标签: javascript html jquery laravel forms


【解决方案1】:

HTML 多文件输入:

<input id="gphotos" type="file" name="gphotos[]" multiple>
<div class="store"></div>
<div class="preview"></div>

JavaScript:

function gphoto(input, ImagePreview) {
        var files = input.files;
        var filesArr = Array.prototype.slice.call(files);

        filesArr.forEach(function(f) {
            if (!f.type.match("image.*")) {
                return;
            }
            var reader = new FileReader();
            reader.onload = function(e) {
                $('.preview').css('margin-top', '4px');
                $($.parseHTML('<img class="gphoto">')).attr('src', e.target.result).appendTo(ImagePreview);
                $($.parseHTML('<input type="hidden" name="photos[]">')).attr('value', e.target.result).appendTo($('.store'));
            };
            reader.readAsDataURL(f);
        });
    }

    $('#gphotos').change(function() {
        gphoto(this, 'div.preview');
    });

控制器:

if (request('photos')) {
            $imageArray['gphotos'] = array();

            foreach (request()->photos as $gphoto) {
                $base64_str = substr($gphoto, strpos($gphoto, ",")+1);
                $gphotoPath = 'gphotos/'.\Str::random(11) . '.jpg';
                $gphoto = base64_decode($base64_str);
                \Storage::disk('public')->put($gphotoPath, $gphoto);

               $imageArray['gphotos'][] =  $gphotoPath;
            }

            $imageArray['gphotos'] = json_encode($imageArray['gphotos']);
        }

【讨论】:

    【解决方案2】:

    您可以在上传之前的文件后添加一个新的&lt;input type="file"&gt; 并隐藏之前的输入。这样您就可以在每次想要添加更多文件时不断添加新输入,并防止之前的输入被覆盖。

    而且它不需要你使用 AJAX。

    <form id="gphotos-form" enctype="multipart/form-data">
      <div class="gphotos-upload">
        <input class="gphotos" type="file" name="gphotos[]" multiple>
      </div>
      <div class="preview"></div>
      <button type="submit">Submit</button>
    </form>
    
    .ghpotos[hidden] {
      display: none;
    }
    
    let $uploads = $('.gphotos-upload');
    let $preview = $('div.preview');
    
    $('#gphotos-form').on('change', function(event) {
    
      let $currentInput = $(event.target);
      let $newInput = $('<input class="gphotos" type="file" name="gphotos[]" multiple>');
    
      for (const file of event.target.files) {
        const image = new Image();
        image.classList.add('gphoto');
        image.src = URL.createObjectURL(file);
        image.onload = event => {
          $preview.append(image);
          URL.revokeObjectURL(event.target.src);
        };
      }
    
      // Disabled and hide current input.
      $currentInput.attr('hidden', '');
    
      // Add new input to do another upload.
      $uploads.append($newInput);
    
    });
    

    【讨论】:

    • 现在图像预览不起作用,它不会追加新的输入
    • 确保您的 HTML 与此处的示例相同。
    • 是的,我确定是
    • 啊,我明白了。我在预览 div 选择器中打错了字。我删除了所用输入的disabled 属性,以便将它们发送到服务器。再试一次。
    • Uncaught ReferenceError: hidden is not defined
    【解决方案3】:

    与其让表单自己处理提交,不如自己创建。监听表单上的submit 事件,每当您提交时,取消默认行为并使用 AJAX 发送您的数据。在这种情况下,jQuery ajax 函数。将其发送到处理传入请求的 PHP 文件。

    您可以将文件(例如图像)存储在 FormData 对象中。它是一个设置键/值对以随 HTTP 请求一起发送的容器。所以创建一个。

    在您的change 事件侦听器中,您需要将每个选定的图像添加到此FormData 容器中,以便将图像存储在那里。这样,您每次都可以选择新图像并将它们添加到容器中。当您提交时,您只需提交包含图像的容器。

    然后,当图像上传成功后,循环遍历容器并删除其中的每个键,以便用户重新启动整个过程。

    <form id="gphotos-form" enctype="multipart/form-data">
      <input id="gphotos" type="file" name="gphotos[]" multiple>
      <div class="preview"></div>
      <button type="submit">Submit</button>
    </form>
    
    // Container for the images.
    const selectedImages = new FormData();
    
    function gphoto(input, imagePreview) {
      for (const file of input.files) {
        const image = new Image();
        image.classList.add('gphoto');
        image.src = URL.createObjectURL(file);
        image.onload = event => {
          $(imagePreview).append(image);
          URL.revokeObjectURL(event.target.src);
        };
    
        // Image is added here.
        selectedImages.append('gphotos', file);
    
      }
    }
    
    $('#gphotos').on('change', function() {
      gphoto(this, 'div.preview');
    });
    
    $('#gphotos-form').on('submit', function(event) {
    
      // Get the data from the form, but remove the gphotos[] one,
      // because we want to use our own collection of images.
      const formData = new FormData(event.target);
      formData.delete('gphotos[]');
      for (const file of selectedImages.values()) {
        formData.append('gphotos', file);
      }
    
      // Send container to your server.
      // Change the url: value to your PHP script.
      $.ajax({
        url: 'http://example.com/script.php',
        data: formData,
        processData: false,
        contentType: false,
        type: 'POST',
        success: function(data){
          console.log(data);
    
          // Delete all the images from the container.
          for (let key of selectedImages.keys()) {
            selectedImages.delete(key)
          });
    
          // Clear the preview.
          $('div.preview').html('');
    
        }
      });
    
      event.preventDefault();
    
    });
    

    【讨论】:

    • 这也会提交其他表单数据吗?该表单还具有其他单个图像字段和文本字段。
    • 顺便谢谢你的回答。在等待您的回复期间,我仍会尝试此方法。
    • 嗯,不,它没有。但是您可以通过在提交事件中创建另一个FormData 对象并将两者结合起来。我将它添加到示例中。
    • 可以在没有 AJAX 或 FormData() 的情况下完成吗?有没有办法可以将选定的图像附加到 FileReader() 中?
    • 恐怕不行。 FileReader 旨在读取文件并在文档中使用它,但不提供发送文件的方法。另一方面,FormData 用于收集数据并将其以一个包的形式发送到服务器。问题在于不能将新文件添加到相同 &lt;input type="file"&gt; 中的旧文件中。但是,在每次上传后动态添加新输入可能是一种解决方法。我会试试看。
    猜你喜欢
    • 2014-05-15
    • 1970-01-01
    • 2013-12-24
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    相关资源
    最近更新 更多