Descarga múltiples archivos con una sola acción

Resuelto Ankur asked hace 14 años • 19 respuestas

No estoy seguro de si esto es posible utilizando tecnologías web estándar.

Quiero que el usuario pueda descargar varios archivos en una sola acción. Es decir, haga clic en las casillas de verificación junto a los archivos y luego obtenga todos los archivos que se marcaron.

¿Es posible? En caso afirmativo, ¿qué estrategia básica recomienda? Sé que puedo usar la tecnología de los cometas para crear eventos del lado del servidor que activen una respuesta Http, pero espero que haya una manera más sencilla.

Ankur avatar Feb 26 '10 11:02 Ankur
Aceptado

var links = [
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.exe',
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.dmg',
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.jar'
];

function downloadAll(urls) {
  var link = document.createElement('a');

  link.setAttribute('download', null);
  link.style.display = 'none';

  document.body.appendChild(link);

  for (var i = 0; i < urls.length; i++) {
    link.setAttribute('href', urls[i]);
    link.click();
  }

  document.body.removeChild(link);
}
<button onclick="downloadAll(window.links)">Test me!</button>
Expandir fragmento

Matěj Pokorný avatar Jun 06 '2015 12:06 Matěj Pokorný

HTTP no admite la descarga de más de un archivo a la vez.

Hay dos soluciones:

  • Abra x cantidad de ventanas para iniciar la descarga de archivos (esto se haría con JavaScript)
  • La solución preferida es crear un script para comprimir los archivos.
Jacob Relkin avatar Feb 26 '2010 04:02 Jacob Relkin

Puede crear un conjunto temporal de iframes ocultos, iniciar la descarga mediante GET o POST dentro de ellos, esperar a que comiencen las descargas y eliminar iframes:

<!DOCTYPE HTML>
<html>
<body>
  <button id="download">Download</button> 

  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
  <script type="text/javascript">

     $('#download').click(function() {
       download('http://nogin.info/cv.doc','http://nogin.info/cv.doc');
     });

     var download = function() {
       for(var i=0; i<arguments.length; i++) {
         var iframe = $('<iframe style="visibility: collapse;"></iframe>');
         $('body').append(iframe);
         var content = iframe[0].contentDocument;
         var form = '<form action="' + arguments[i] + '" method="GET"></form>';
         content.write(form);
         $('form', content).submit();
         setTimeout((function(iframe) {
           return function() { 
             iframe.remove(); 
           }
         })(iframe), 2000);
       }
     }      

  </script>
</body>
</html>

O, sin jQuery:

 function download(...urls) {
    urls.forEach(url => {
      let iframe = document.createElement('iframe');
      iframe.style.visibility = 'collapse';
      document.body.append(iframe);

      iframe.contentDocument.write(
        `<form action="${url.replace(/\"/g, '"')}" method="GET"></form>`
      );
      iframe.contentDocument.forms[0].submit();

      setTimeout(() => iframe.remove(), 2000);
    });
  }
Dmitry Nogin avatar Feb 24 '2012 05:02 Dmitry Nogin

Esta solución funciona en todos los navegadores y no genera advertencias. En lugar de crear un archivo iframe, aquí creamos un enlace para cada archivo. Esto evita que aparezcan mensajes de advertencia.

Para manejar la parte del bucle, utilizamos setTimeout, que es necesario para que funcione en IE.

Actualización 2021 : Soy consciente de que el "fragmento de código de ejecución" ya no funciona, pero eso se debe a problemas con las cookies entre sitios. El código funciona bien si se implementa en su propio sitio.

/**
 * Download a list of files.
 * @author speedplane
 */
function download_files(files) {
  function download_next(i) {
    if (i >= files.length) {
      return;
    }
    var a = document.createElement('a');
    a.href = files[i].download;
    a.target = '_parent';
    // Use a.download if available, it prevents plugins from opening.
    if ('download' in a) {
      a.download = files[i].filename;
    }
    // Add a to the doc for click to work.
    (document.body || document.documentElement).appendChild(a);
    if (a.click) {
      a.click(); // The click method is supported by most browsers.
    } else {
      $(a).click(); // Backup using jquery
    }
    // Delete the temporary link.
    a.parentNode.removeChild(a);
    // Download the next file with a small timeout. The timeout is necessary
    // for IE, which will otherwise only download the first file.
    setTimeout(function() {
      download_next(i + 1);
    }, 500);
  }
  // Initiate the first download.
  download_next(0);
}
<script>
  // Here's a live example that downloads three test text files:
  function do_dl() {
    download_files([
      { download: "https://stackoverflow.com/robots.txt", filename: "robots.txt" },
      { download: "https://www.w3.org/TR/PNG/iso_8859-1.txt", filename: "standards.txt" },
      { download: "http://qiime.org/_static/Examples/File_Formats/Example_Mapping_File.txt", filename: "example.txt" },
    ]);
  };
</script>
<button onclick="do_dl();">Test downloading 3 text files.</button>
Expandir fragmento

speedplane avatar Apr 13 '2015 13:04 speedplane

El siguiente script hizo este trabajo con gracia.

var urls = [
'https://images.pexels.com/photos/432360/pexels-photo-432360.jpeg',
'https://images.pexels.com/photos/39899/rose-red-tea-rose-regatta-39899.jpeg'
];

function downloadAll(urls) {


  for (var i = 0; i < urls.length; i++) {
    forceDownload(urls[i], urls[i].substring(urls[i].lastIndexOf('/')+1,urls[i].length))
  }
}
function forceDownload(url, fileName){
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.responseType = "blob";
    xhr.onload = function(){
        var urlCreator = window.URL || window.webkitURL;
        var imageUrl = urlCreator.createObjectURL(this.response);
        var tag = document.createElement('a');
        tag.href = imageUrl;
        tag.download = fileName;
        document.body.appendChild(tag);
        tag.click();
        document.body.removeChild(tag);
    }
    xhr.send();
}
Shyam Narayan avatar Apr 29 '2020 19:04 Shyam Narayan