Scaricare file usando Javascript/jQuery

Ho un requisito molto simile specificato qui.

Ho bisogno che il browser dell'utente avvii un download manualmente quando $('a#someID').click();

Ma non posso usare il metodo window.href, poiché sostituisce il contenuto corrente della pagina con il file che si sta cercando di scaricare.

Invece voglio aprire il download in una nuova finestra/tab. Come è possibile?

Soluzione

Usa un <iframe> invisibile:


<script>
function Download(url) {
    document.getElementById('my_iframe').src = url;
};
</script>

Per forzare il browser a scaricare un file che altrimenti sarebbe in grado di rendere (come HTML o file di testo), è necessario che il server imposti il MIME Type del file ad un valore insensato, come application/x-please-download-me o in alternativa application/octet-stream, che è usato per dati binari arbitrari.

Se vuoi solo aprirlo in una nuova scheda, l'unico modo per farlo è che l'utente clicchi su un link con il suo attributo target impostato su _blank.

In jQuery:

$('a#someID').attr({target: '_blank', 
                    href  : 'http://localhost/directory/file.pdf'});

Ogni volta che quel link viene cliccato, scaricherà il file in una nuova scheda/finestra.

Commentari (21)

2019 aggiornamento dei browser moderni

Questo è l'approccio che raccomando ora, con alcune avvertenze:

  • È richiesto un browser relativamente moderno
  • Se ci si aspetta che il file sia molto grande si dovrebbe probabilmente fare qualcosa di simile all'approccio originale (iframe e cookie) perché alcune delle operazioni sottostanti potrebbero probabilmente consumare memoria di sistema grande almeno quanto il file da scaricare e/o altri interessanti effetti collaterali della CPU.
fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(resp => resp.blob())
  .then(blob => {
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    // the filename you want
    a.download = 'todo-1.json';
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
    alert('your file has downloaded!'); // or you know, something with better UX...
  })
  .catch(() => alert('oh no!'));

2012 approccio originale basato su jQuery/iframe/cookie

Ho creato il jQuery File Download plugin (Demo) (GitHub) che potrebbe anche aiutare nella tua situazione. Funziona abbastanza similmente con un iframe ma ha alcune caratteristiche interessanti che ho trovato abbastanza utili:

  • Molto facile da configurare con belle immagini (jQuery UI Dialog, ma non richiesto), tutto è anche testato

  • L'utente non lascia mai la stessa pagina da cui ha iniziato il download di un file. Questa caratteristica sta diventando cruciale per le moderne applicazioni web

  • Le funzioni successCallback e failCallback permettono di essere espliciti su ciò che l'utente vede in ogni situazione

  • In combinazione con jQuery UI uno sviluppatore può facilmente mostrare una modale per dire all'utente che si sta verificando un download di file, sciogliere la modale dopo l'inizio del download o anche informare l'utente in modo amichevole che si è verificato un errore. Vedi la Demo per un esempio di questo. Spero che questo aiuti qualcuno!

Ecco un semplice caso d'uso demo che utilizza il plugin source con le promesse. La pagina demo include anche molti altri esempi di UX migliori.

$.fileDownload('some/file.pdf')
    .done(function () { alert('File download a success!'); })
    .fail(function () { alert('File download failed!'); });
Commentari (10)

Se stai già usando jQuery, potresti approfittarne per produrre uno snippet più piccolo Una versione jQuery della risposta di Andrew:

var $idown;  // Keep it outside of the function, so it's initialized once.
downloadURL : function(url) {
  if ($idown) {
    $idown.attr('src',url);
  } else {
    $idown = $('<iframe>', { id:'idown', src:url }).hide().appendTo('body');
  }
},
//... How to use it:
downloadURL('http://whatever.com/file.pdf');
Commentari (7)