Cómo activar una descarga de archivo al hacer clic en un botón HTML o JavaScript

434

Esto es una locura, pero no sé cómo hacerlo, y debido a lo comunes que son las palabras, es difícil encontrar lo que necesito en los motores de búsqueda. Estoy pensando que esto debería ser fácil de responder.

Quiero una descarga de archivo simple, que haría lo mismo que esto:

<a href="file.doc">Download!</a>

Pero quiero usar un botón HTML, por ejemplo, cualquiera de estos:

<input type="button" value="Download!">
<button>Download!</button>

Del mismo modo, ¿es posible activar una descarga simple a través de JavaScript?

$("#fileRequest").click(function(){ /* code to download? */ });

Definitivamente no estoy buscando una manera de crear un ancla que se parezca a un botón, usar scripts de back-end o jugar con encabezados de servidor o tipos mime.

brentonstrina
fuente
15
Gracias a usted "cómo activar la descarga de un archivo en javascript" daría respuestas mucho más rápidas para cualquier buscador futuro.
Danubian Sailor

Respuestas:

278

Para el botón que puedes hacer

<form method="get" action="file.doc">
   <button type="submit">Download!</button>
</form>
Cfreak
fuente
Puede guardar la etiqueta del formulario y simplemente agregar un clic en la etiqueta del botón.
Florian Leitgeb
12
no funciona como desencadenante, solo redirige a la url como etiqueta 'a'.
fdrv
77
Esto funciona mejor: <a href="path_to_file" download="proposed_file_name"> Descargar </a>
kscius
11
@kscius incluso hoy el atributo de descarga no es compatible con IE 11 (ahora es compatible con Edge) y no es compatible con Safari. En 2012, cuando la respuesta se publicó originalmente, no era compatible con ningún navegador importante.
Cfreak
1
¿Cuál es la diferencia entre tener un ancla con estilo de botón y tener un formulario con un botón?
Andrei Epure
444

Puede activar una descarga con el downloadatributo HTML5 .

<a href="path_to_file" download="proposed_file_name">Download</a>

Dónde:

  • path_to_filees una ruta que se resuelve en una URL en el mismo origen . Eso significa que la página y el archivo deben compartir el mismo dominio, subdominio, protocolo (HTTP frente a HTTPS) y puerto (si se especifica). Las excepciones son blob:y data:(que siempre funcionan) y file:(que nunca funciona).
  • proposed_file_namees el nombre de archivo para guardar. Si está en blanco, el navegador usa de manera predeterminada el nombre del archivo.

Documentación: MDN , HTML Standard en la descarga , HTML Standard endownload , CanIUse

Joe Pigott
fuente
37
No funciona con Safari y ciertas versiones de IE
Mohamed Hussain
44
Usar una combinación de downloady target="_blank"parece ser suficiente para cubrir la mayoría de los casos de uso. Los navegadores que entienden lo downloadtratan como una descarga, de lo contrario se abre en una nueva pestaña.
MK10
10
¿Cómo se puede aplicar esto a un objeto de botón en lugar de solo una etiqueta ?
storm_m2138
8
En realidad, esto solo funciona para las URL del mismo origen que se menciona en los documentos MDN. Esta es una gran limitación si estamos buscando desarrollar una solución genérica
Akshat Gupta
66
La pregunta es pedir explícitamente usar un botón en lugar de un enlace
Quentin
87

HTML:

<button type="submit" onclick="window.open('file.doc')">Download!</button>
sueño
fuente
8
La mejor y más limpia solución. Pero no necesita ningún Javascript adicional aquí. La parte HTML con el onclick es suficiente.
Florian Leitgeb
44
¿Que pasa si quiero descargar un archivo xml?
g07kore
2
Gracias por tu codigo. Lo he probado, puede funcionar en IE, Chrome, Firefox.
muthukumar
66
Si tiene un archivo aceptable para el navegador como un PDF, se abrirá en una nueva pestaña para mostrar el diálogo de descarga.
WindRider
1
window.open puede activar el bloqueo de ventanas emergentes en un navegador y, por lo tanto, no se recomienda. Podría usar window.location = 'ruta', aunque eso iría a la ubicación en la misma ventana del navegador.
Elendurwen
68

Con jQuery:

$("#fileRequest").click(function() {
    // // hope the server sets Content-Disposition: attachment!
    window.location = 'file.doc';
});
Matt Ball
fuente
1
Perfecto gracias. ¿Sabes si la mayoría de los servidores establecerán la Disposición de contenido en 'archivo adjunto' de forma predeterminada?
brentonstrine
55
No hay "la mayoría". Depende completamente. No confíes en que se establezca.
Matt Ball
3
Este problema me ha estado volviendo loco, y esta fue la única opción que funcionó (y es compatible con IE). Agregaré para cualquier n00bs como yo que para establecer la Disposición de contenido, todo lo que tiene que hacer es: <? Encabezado php ('Disposición de contenido: archivo adjunto; filename = "filename.here"'); ?>
user124384
3
No jquery Período.
Adam Arold
1
Este trabajo funciona si estás intentando descargar una imagen, abriría la imagen en el navegador
Dheeraj
34

Hilo antiguo pero le falta una solución js simple:

let a = document.createElement('a')
a.href = item.url
a.download = item.url.split('/').pop()
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
Stefanos Chrs
fuente
24
@NicholasKyriakides Me recuerda a esta gema: image.ibb.co/dtkUWJ/Selection_002.png
Stefanos
@BryanLarsen, ¿qué versión de FF?
Stefanos Chrs
1
@BryanLarsen Tienes razón, Firefox no permite esto sin agregar primero el elemento al cuerpo. Gracias, actualizando la respuesta
Stefanos Chrs
1
¿Hay alguna manera de que la función de JavaScript se active una vez que finalice la descarga? Solo intento mostrar un mensaje una vez que comienzan las descargas y eliminar el mensaje una vez que se completa la descarga.
Mohit Bansal
1
@mohitbansal (un) afortunadamente no, ya que está en el nivel del navegador
Stefanos Chrs
23

Puede hacerlo con "truco" con iframe invisible. Cuando configura "src", el navegador reacciona como si hiciera clic en un enlace con el mismo "href". A diferencia de la solución con formulario, le permite incrustar lógica adicional, por ejemplo, activar la descarga después del tiempo de espera, cuando se cumplen algunas condiciones, etc.

También es muy ingenioso, no hay una nueva ventana / pestaña parpadeante como cuando se usa window.open.

HTML:

<iframe id="invisible" style="display:none;"></iframe>

Javascript:

function download() {
    var iframe = document.getElementById('invisible');
    iframe.src = "file.doc";
}
Marinero danubiano
fuente
Lo hace, al menos si realmente aplica el iframe a document.body.
yxhuvud
1
Esto no parece estar funcionando en Chrome en este momento, aunque solía funcionar. Me pregunto si deja de funcionar de forma intermitente en diferentes versiones de Chrome.
Dobes Vandermeer
Funciona en Chrome a partir de la versión 61.0.3163.100 (versión oficial) (64 bits)
AndrewBenjamin
No funciona con imágenes en Firefox v57. Simplemente representa la imagen en el iframe.
Antony
15

Versión Bootstrap

<a class="btn btn-danger" role="button" href="path_to_file"
   download="proposed_file_name">
  Download
</a>

Documentado en Bootstrap 4 docs , y funciona en Bootstrap 3 también.

Soporte CFP
fuente
99
Lo único que tiene que ver con Bootstrap son los nombres de clase, es solo el poder de HTML5.
Machado
3
La pregunta es explícitamente cómo hacer esto con un botón en lugar de un enlace.
Quentin
2
si supieras algo sobre bootstrap, verías que ES un botón.
John Lord
11

Creo que esta es la solución que estabas buscando

<button type="submit" onclick="window.location.href='file.doc'">Download!</button>

Tengo un caso en el que mi Javascript genera un archivo CSV. Como no hay una URL remota para descargarlo, uso la siguiente implementación.

downloadCSV: function(data){
    var MIME_TYPE = "text/csv";

    var blob = new Blob([data], {type: MIME_TYPE});
    window.location.href = window.URL.createObjectURL(blob);
}
Delconis
fuente
en 404 -> cambio de página a una página de error 404. mismo problema que se indica en las otras location.hrefsoluciones.
BananaAcid
9

Qué pasa:

<input type="button" value="Download Now!" onclick="window.location = 'file.doc';">
olli
fuente
55
Esto no funciona si su archivo, por ejemplo, es una imagen, ya que solo se abriría en el navegador.
Juggernaut
Ocurre otro problema que es que si falta el archivo, navega por toda la página a una página 404
Hugheth
7

Puede ocultar el enlace de descarga y hacer que el botón haga clic en él.

<button onclick="document.getElementById('link').click()">Download!</button>
<a id="link" href="file.doc" download hidden></a>
Starwarswii
fuente
Para que esto funcione en Firefox, el recurso debe estar en el mismo dominio que el documento. Establecer encabezados CORS no ayuda.
Antony
2
Nunca hagas esto
Wannes
@Wannes, ¿por qué no?
Starwarswii
4

Si está buscando una solución vainilla de JavaScript (sin jQuery) y sin usar el atributo HTML5, puede intentarlo.

const download = document.getElementById("fileRequest");

download.addEventListener('click', request);

function request() {
    window.location = 'document.docx';
}
.dwnld-cta {
    border-radius: 15px 15px;
    width: 100px;
    line-height: 22px
}
<h1>Download File</h1>
<button id="fileRequest" class="dwnld-cta">Download</button>

David Willhite
fuente
1

Esto es lo que finalmente funcionó para mí, ya que el archivo a descargar se determinó cuando se cargó la página.

JS para actualizar el atributo de acción del formulario:

function setFormAction() {
    document.getElementById("myDownloadButtonForm").action = //some code to get the filename;
}

Llamando a JS para actualizar el atributo de acción del formulario:

<body onLoad="setFormAction();">

Etiqueta de formulario con el botón de enviar:

<form method="get" id="myDownloadButtonForm" action="">
    Click to open document:  
    <button type="submit">Open Document</button>
</form>

Lo siguiente NO funcionó:

<form method="get" id="myDownloadButtonForm" action="javascript:someFunctionToReturnFileName();">
Slayernoah
fuente
probablemente porque si tiene el archivo en el momento de la carga, ¿no puede simplemente representar la acción en el servidor utilizando un motor de plantillas? ¿Por qué la necesidad de código js?
Andrei Epure
1

Si no puede usar el formulario, otro enfoque con downloadjs encaja bien. Downloadjs usa blob y html 5 file API bajo el capó:

{downloadjs (url, nombre de archivo)}) />

* es la sintaxis jsx / react, pero se puede usar en html puro

Gleb Dolzikov
fuente
Para evitar problemas CORS para imágenes en otros dominios, ponga crossorigin = "anonymous" en la etiqueta img, así: <img src = "image.png" crossorigin = "anonymous" />
Jonathan Harris
0

En cualquier lugar entre sus etiquetas <body>y </body>, coloque un botón con el siguiente código:

<button>
    <a href="file.doc" download>Click to Download!</a>
</button>

¡Esto seguramente funcionará!

Ronaldo
fuente
1
Para Chrome es una gran solución
Hayk Aramyan,
1
Tampoco funciona en Safari: Escuelas W3
Alex
2
No funcionar en los navegadores MS es un problema bastante grande y Chrome no siempre será la respuesta.
SudoKid
No puedes poner un enlace dentro de un botón en HTML
Quentin
0

Otra forma de hacerlo en caso de que tenga una URL compleja como file.doc?foo=bar&jon=doeagregar campo oculto dentro del formulario

<form method="get" action="file.doc">
  <input type="hidden" name="foo" value="bar" />
  <input type="hidden" name="john" value="doe" />
  <button type="submit">Download Now</button>
</form>

inspirado en la respuesta @Cfreak que no está completa

Bellash
fuente
0

puedes agregar etiquetas sin texto pero con enlace. y cuando hace clic en el botón como lo tiene en el código, simplemente ejecute la función $ ("yourlinkclass"). click ().

ThisisFish
fuente
-1

atributo de descarga hacerlo

 <a class="btn btn-success btn-sm" href="/file_path/file.type" download>
     <span>download </span>&nbsp;<i class="fa fa-download"></i>
 </a>
Rohallah Hatami
fuente
2
Me gusta tu respuesta
George C.
2
La pregunta es explícitamente cómo hacer esto con un botón en lugar de un enlace.
Quentin
-6

Si usa la <a>etiqueta, no olvide usar la URL completa que conduce al archivo, es decir:

<a href="http://www.example.com/folder1/file.doc">Download</a>
marca
fuente
No creo que ese sea el problema aquí. Además, la ruta "absoluta" no es necesaria si el enlace está en la misma ruta que el archivo.
Rocket Hazmat
@Rocket: por supuesto, tiene razón sobre la ruta absoluta, sin embargo, es la mejor manera de asegurarse de hacerlo bien. Dejaré que el OP decida si fue útil ...
Mark
La pregunta es explícitamente cómo hacer esto con un botón en lugar de un enlace.
Quentin
falta el atributo de descarga en esta solución. Incluso después de agregar atributos de descarga, no funcionará para dominios cruzados.
s sharif
-6

Para mí, el botón de anuncios en lugar del texto de anclaje funciona muy bien.

<a href="file.doc"><button>Download!</button></a>

Puede que no esté bien según la mayoría de las reglas, pero se ve bastante bien.

Brana
fuente
55
Esto solo funciona porque su navegador no admite archivos .doc.
Diseño de Adrian el
Tu HTML no es válido. <a>Los elementos no pueden contener <button>elementos.
Quentin
¿siempre fue así? Esta respuesta tenía dos años cuando comentaste eso.
John Lord