Como acionar um download de arquivo ao clicar em um botão HTML ou JavaScript

434

Isso é loucura, mas não sei como fazer isso, e por causa de quão comuns são as palavras, é difícil encontrar o que eu preciso nos mecanismos de busca. Estou pensando que isso deve ser fácil de responder.

Eu quero um download de arquivo simples, que faria o mesmo que este:

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

Mas eu quero usar um botão HTML, por exemplo, um destes:

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

Da mesma forma, é possível acionar um simples download via JavaScript?

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

Definitivamente, não estou procurando uma maneira de criar uma âncora parecida com um botão, usar scripts de back-end ou mexer nos cabeçalhos do servidor ou nos tipos MIME.

brentonstrina
fonte
15
Graças a você, "como acionar um download de arquivo em javascript" daria respostas muito mais rápidas para qualquer pesquisador futuro.
Danubian Sailor

Respostas:

278

Para o botão você pode fazer

<form method="get" action="file.doc">
   <button type="submit">Download!</button>
</form>
Cfreak
fonte
Você pode salvar a tag do formulário e apenas adicionar um clique na tag do botão.
Florian Leitgeb 23/01
12
não funciona como acionador, basta redirecionar para o URL como tag 'a'.
fdrv
7
Isso funciona melhor: <a href="path_to_file" download="proposed_file_name"> Download </a>
kscius 07/07/16
11
@kscius ainda hoje o atributo de download não é suportado no IE 11 (agora é suportado no Edge) e não é suportado no Safari. Em 2012, quando a resposta foi postada originalmente, ela não era suportada em nenhum navegador principal.
Cfreak #
1
qual é a diferença entre ter uma âncora com estilo de botão e ter um formulário com um botão?
Andrei Epure 23/02
444

Você pode acionar um download com o downloadatributo HTML5 .

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

Onde:

  • path_to_fileé um caminho que resolve para um URL na mesma origem . Isso significa que a página e o arquivo devem compartilhar o mesmo domínio, subdomínio, protocolo (HTTP vs. HTTPS) e porta (se especificado). As exceções são blob:e data:(que sempre funcionam) e file:(que nunca funcionam).
  • proposed_file_nameé o nome do arquivo no qual salvar. Se estiver em branco, o navegador usará como padrão o nome do arquivo.

Documentação: MDN , HTML Standard no download , HTML Standard nodownload , CanIUse

Joe Pigott
fonte
37
Não funciona com o Safari e certas versões do IE
Mohamed Hussain
4
Usar uma combinação de downloade target="_blank"parece ser suficiente para cobrir a maioria dos casos de uso. Os navegadores que entendem o downloadtratam como um download, caso contrário, ele é aberto em uma nova guia.
MK10 16/01
10
Como isso pode ser aplicado a um objeto de botão em vez de apenas a uma tag ?
storm_m2138
8
Na verdade, isso funciona apenas para URLs da mesma origem, conforme mencionado nos documentos MDN. Esta é uma enorme limitação se nós estamos olhando para desenvolver uma solução genérica
Akshat Gupta
6
A questão está pedindo explicitamente para usar um botão em vez de um link
Quentin
86

HTML:

<button type="submit" onclick="window.open('file.doc')">Download!</button>
sonolento
fonte
8
Melhor e mais limpa solução. Mas você não precisa de nenhum Javascript extra aqui. A parte HTML com o onclick é suficiente.
Florian Leitgeb 23/01
4
E se eu quiser baixar um arquivo xml?
G07kore 12/05
2
Obrigado pelo seu código. Eu testei, ele pode trabalhar no IE, Chrome, Firefox.
Mshukumar # 22/16
6
Se você tiver um arquivo aceitável pelo navegador como um PDF, ele será aberto em uma nova guia para exibir a caixa de diálogo de download.
WindRider
1
window.open pode desencadear o bloqueio de pop-ups em um navegador e, portanto, não é recomendado. Você pode usar window.location = 'path', embora isso vá para o local na mesma janela do navegador.
Elendurwen 6/12/19
68

Com jQuery:

$("#fileRequest").click(function() {
    // // hope the server sets Content-Disposition: attachment!
    window.location = 'file.doc';
});
Matt Ball
fonte
1
Perfeito, obrigado. Você sabe se a maioria dos servidores definirá a disposição de conteúdo como 'anexo' por padrão?
Brentonstrine
5
Não há "mais". Depende completamente. Não confie na definição.
Matt Bola
3
Esse problema está me deixando balístico, e essa foi a única opção que funcionou (e é suportada pelo IE). Vou adicionar para qualquer n00bs como eu que para definir a Disposição de Conteúdo, tudo o que você precisa fazer é: <? Php header ('Disposição de Conteúdo: anexo; filename = "filename.here"'); ?>
user124384
3
Sem jquery. Período.
Adam Arold
1
Este trabalho fazes, se você está tentando baixar uma imagem, ela iria abrir a imagem no navegador
Dheeraj
34

Tópico antigo, mas está faltando uma solução js simples:

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
fonte
24
@NicholasKyriakides tipo de lembra-me de esta jóia: image.ibb.co/dtkUWJ/Selection_002.png
Stefanos Chrs
@BryanLarsen qual versão do FF?
Stefanos Chrs
1
@BryanLarsen Você está certo, o Firefox não permite isso sem adicionar o elemento ao corpo primeiro. Obrigado, atualizando a resposta
Stefanos Chrs 19/02/19
1
Existe uma maneira de a função javascript ser acionada quando o download terminar? Apenas tentando mostrar uma mensagem quando o download iniciar e remover a mensagem quando o download for concluído.
mohit bansal
1
@mohitbansal (un), felizmente, não como é no nível do navegador
Stefanos Chrs
23

Você pode fazer isso com "truque" com iframe invisível. Quando você define "src", o navegador reage como se você clicasse em um link com o mesmo "href". Ao contrário da solução com forma, ele permite incorporar lógica adicional, por exemplo, ativar o download após o tempo limite, quando algumas condições são atendidas etc.

Também é muito silencioso, não há novas janelas / abas piscando como no uso window.open.

HTML:

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

Javascript:

function download() {
    var iframe = document.getElementById('invisible');
    iframe.src = "file.doc";
}
Marinheiro Danubiano
fonte
Sim, pelo menos se você realmente aprovar o iframe para document.body.
Yxhuvud 27/05
1
No momento, isso não parece estar funcionando no Chrome, embora funcionasse. Gostaria de saber se meio que para de funcionar intermitentemente em diferentes versões do Chrome.
Dobes Vandermeer
Funciona no Chrome a partir da versão 61.0.3163.100 (Compilação oficial) (64 bits)
AndrewBenjamin
Não funciona com imagens no Firefox v57. Apenas renderiza a imagem no iframe.
Antony
15

Versão do Bootstrap

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

Documentado nos documentos do Bootstrap 4 e funciona também no Bootstrap 3.

Suporte CFP
fonte
9
A única coisa que isso tem a ver com o Bootstrap são os nomes das classes, é apenas o poder do HTML5.
Machado
3
A questão é perguntar explicitamente como fazer isso com um botão em vez de um link.
Quentin
2
se você soubesse alguma coisa sobre bootstrap, veria que é um botão.
John Lord
11

Eu acho que essa é a solução que você estava procurando

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

Eu tive um caso em que meu Javascript gerou um arquivo CSV. Como não há URL remota para fazer o download, uso a seguinte implementação.

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

    var blob = new Blob([data], {type: MIME_TYPE});
    window.location.href = window.URL.createObjectURL(blob);
}
Delconis
fonte
em 404 -> mudança de página para uma página de erro 404. mesmo problema indicado nas outras location.hrefsoluções.
precisa saber é o seguinte
9

A respeito:

<input type="button" value="Download Now!" onclick="window.location = 'file.doc';">
olli
fonte
5
Isso não funciona, se o seu arquivo, por exemplo, for uma imagem, pois seria apenas aberto no navegador.
camião articulado
Outro problema ocorre que é se o arquivo está faltando ele navega a página inteira para uma página 404
Hugheth
7

Você pode ocultar o link de download e clicar no botão.

<button onclick="document.getElementById('link').click()">Download!</button>
<a id="link" href="file.doc" download hidden></a>
Starwarswii
fonte
Para que isso funcione no Firefox, o recurso deve estar no mesmo domínio que o documento. Definir cabeçalhos CORS não ajuda.
Antony
2
Nunca mais faça isso
Wannes
@Wannes porque não?
Starwarswii
4

Se você está procurando uma solução de baunilha JavaScript (sem jQuery) e sem usar o atributo HTML5, pode tentar isso.

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
fonte
1

Foi o que finalmente funcionou para mim, uma vez que o arquivo a ser baixado foi determinado quando a página é carregada.

JS para atualizar o atributo de ação do formulário:

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

Chamando JS para atualizar o atributo de ação do formulário:

<body onLoad="setFormAction();">

Etiqueta de formulário com o botão enviar:

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

O seguinte NÃO funcionou:

<form method="get" id="myDownloadButtonForm" action="javascript:someFunctionToReturnFileName();">
slayernoah
fonte
provavelmente porque se você tiver o arquivo no tempo de carregamento, não poderá simplesmente executar a ação no servidor usando um mecanismo de modelo? por que a necessidade de código js?
Andrei Epure 23/02
1

Se você não pode usar o formulário, outra abordagem com o downloadjs é adequada. O Downloadjs usa a API de arquivos blob e html 5 sob o capô:

{downloadjs (url, nome do arquivo)}) />

* é sintaxe jsx / react, mas pode ser usado em html puro

Gleb Dolzikov
fonte
Para evitar problemas de CORS para imagens em outros domínios, coloque crossorigin = "anonymous" na tag img, da seguinte forma: <img src = "image.png" crossorigin = "anonymous" />
Jonathan Harris
0

Em qualquer lugar entre as tags <body>e e </body>, coloque um botão usando o código abaixo:

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

Isso com certeza funcionará!

Ronaldo
fonte
1
Para Chrome é uma grande solução
Hayk Aramyan
1
Não funciona no Safari ou: W3 Escolas
Alex
2
Não funcionar nos navegadores MS é um grande problema, e nem sempre o Chrome será a resposta.
SudoKid
Você não pode colocar um link dentro de um botão em HTML
Quentin
0

Outra maneira de fazer, caso você tenha um URL complexo, como file.doc?foo=bar&jon=doeadicionar campo oculto ao formulário

<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 na resposta @Cfreak que não está completa

Bellash
fonte
0

você pode adicionar tags sem nenhum texto, mas com o link. e quando você clicar no botão como no código, basta executar a função $ ("yourlinkclass"). click ().

ThisisFish
fonte
-1

atributo de download faça

 <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
fonte
2
Eu gosto da sua resposta
George C.
2
A questão é perguntar explicitamente como fazer isso com um botão em vez de um link.
Quentin
-6

Se você usar a <a>tag, não se esqueça de usar o URL inteiro que leva ao arquivo - ou seja:

<a href="http://www.example.com/folder1/file.doc">Download</a>
Marca
fonte
Eu não acho que esse seja o problema aqui. Além disso, o caminho "absoluto" não é necessário se o link estiver no mesmo caminho que o arquivo.
Rocket Hazmat
@Rocket - você está, é claro, correto sobre o caminho absoluto; no entanto, é a melhor maneira de garantir que ele esteja certo. Deixarei ao OP decidir se foi útil - #
237 Mark Mark
A questão é perguntar explicitamente como fazer isso com um botão em vez de um link.
Quentin
o atributo de download está ausente nesta solução. Mesmo depois de adicionar atributos de download, ele não funcionará em vários domínios.
S sharif
-6

Para mim, adicionar um botão ao invés de um texto âncora funciona muito bem.

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

Pode não ser bom para a maioria das regras, mas parece muito bom.

Brana
fonte
5
Isso funciona apenas porque o seu navegador não suporta arquivos .doc.
Design by Adrian
Seu HTML é inválido. <a>elementos não podem conter <button>elementos.
Quentin
sempre foi assim? Esta resposta tinha dois anos quando você comentou isso.
John Lord