Diego Rubin

Fullstack Developer

Entre em contato

HTML5 - File Upload utilizando Drag And Drop

Ereader icon

Introdução

Apesar do HTML 5 ainda não ter sido totalmente especificado e por isso ainda não ter sido liberado pela W3C, ele já está sendo adotado por diversos navegadores e com isso várias aplicações web estão fazendo uso destes novos recursos.

Neste artigo irei mostrar uma forma de realizar upload de arquivos utilizando a File API do HTML 5 simplesmente arrastando um arquivo do desktop em um área pré-determinada da página. Além disso, também será utilizado o FileReader que possibilita o ler o conteúdo do arquivo que é carregado do file system.

ATENÇÃO: Se você está visualizando este post através do feed, eu peço que visite a página do conteúdo no site para ver o exemplo funcionando em seu navegador.

No exemplo, um arquivo arrastado a partir do desktop é carregado pelo navegador e é exibida no frame. É um exemplo simples mas que exemplifica bem o uso desses novos recursos disponíveis pelo Html 5. Se o arquivo arrastado não for uma imagem nada será exibido.

Arraste a imagem aqui
Digite um titulo

A estrutura HTML e o Estilo

Neste exemplo iremos utilizar uma simples div para delimitarmos a área em que o arquivo será arrastado. E colocaremos um elemento span para avisarmos nosso usuário que o arquivo deve ser arrastado para este lugar.

<html>
  <head>
    <link href="html5-fileapi.css" media="all" rel="stylesheet" type="text/css" />
  </head>
  <body>

    <div id="example-content">

      <div id="frame">

        <div id="image-area">

          <span id="drop-message"> Arraste a imagem aqui </span>

        </div>

        <span id="title"> Digite um titulo </span>
      </div>

    </div>

  </body>
  <script src="html5-file-upload-code.js" type="text/javascript"></script>
</html>

O estilo utilizado no exemplo é bem simples e pode ser visto logo abaixo:

#example-content { text-align: center; }
#frame { background-color: #000; color: #fff; margin: 50px; width: 400px; height: 450px; padding: 50px; }
#image-area { width: 100%; border: 1px dotted #fff; padding-top: 50%; padding-bottom: 50%; margin-bottom: 15px; overflow:hidden; }

.hover { border: 1px solid #fff !important; }

O Código Javascript

Abaixo irei colocar o código comentado que será utilizado neste exemplo. Há bastante comentários no código, mas como de costume, quero reforçar que qualquer dúvida utilize o sistema de comentários do site.

// Criação da nossa "classe" de controle.
// Não entrarei neste detalhe aqui, mas por favor,
// se você ouvir alguém falar que javascript é uma
// linguagem orientada a objetos, no mínimo, não
// acredite nele. Javascript é uma linguagem prototipada.
// Essa maneira de programar javascript é uma preferencia
// minha. Prefiro este estilo a criar várias funções perdidas.
function FileFrame(fileArea, fileTitle) {
  var self = this;

  this.fileArea = fileArea;
  this.fileTitle = fileTitle;

  this.init = function() {
    // Registrando eventos de drag and drop
    self.fileArea.addEventListener("dragleave", self.dragHover, false);
    self.fileArea.addEventListener("dragover", self.dragHover, false);
    self.fileArea.addEventListener("drop", self.drop, false);
 
  };

  this.dragHover = function(e) {
    // Impede possíveis tratamentos dos arquivos
    // arrastados pelo navegador, por exemplo, exibir
    // o conteudo do mesmo.
    e.stopPropagation();  
    e.preventDefault();  

    // Quando o arquivo está sobre área alteramos o seu estilo
    self.fileArea.className = (e.type == "dragover" ? "hover" : "");  
  };

  this.drop = function(e) {
    self.dragHover(e);  

    // Volta um array com os arquivos arratados,
    // porém neste exemplo iremos tratar apenas
    // o primeiro arquivo
    self.file = e.dataTransfer.files[0];  
   
    // Recupera nome do arquivo
    self.fileTitle.innerHTML = self.file.name;


    self.read(self.file);
    
    // Neste ponto podemos implementar uma função para
    // enviar os arquivos via ajax.
    // Irei deixar um exemplo, qualquer dúvida eu peço
    // que utilize o sistema de comentários do site.
    /*
    self.sendFile(self.file);
    */
  };

  // Esse método irá ler o arquivo na memória,
  // depois iremos mostrá-lo no nosso frame
  this.read = function(file) {
    // Iremos ler apenas imagens nesse exemplo
    // e iremos exibi-lo no frame
    if (file.type.match('image.*')) {
      var reader = new FileReader();

      // Callback que será executado após a leitura do arquivo
      reader.onload = function(f) {
        self.fileArea.innerHTML = "";
        self.fileArea.setAttribute("style", "padding: 0px !important;");
        
        // Criação do elemento que será utilizado para exibir a imagem
        var img = document.createElement("img");
        img.setAttribute("src", f.target.result);
        img.setAttribute("height", "350");

        self.fileArea.appendChild(img);
      }

      // Irá ler o arquivo para ser acessado através de uma url
      reader.readAsDataURL(file);
    }
  }

  // Essa função pode ser utilizada como 
  this.sendFile = function(file) {

    // Criaremos um formulário
    var f = new FormData();
    // Passando o arquivo para o formulário
    f.append("file", file);

    // Chamada async para realizar o upload da imagem
    var request = new XMLHttpRequest();
    request.open("POST", "", true);
    request.send(f);
    request.onreadystatechange=function(){
      // Término do envio do formulário
      if(request.readyState==4) {
      }
    }
  };

}

// Recupera a div que conterá a imagem
// e o span com o título de nosso arquivo
var area = document.getElementById("image-area");
var title = document.getElementById("title");

var fileFrameArea = new FileFrame(area, title);
fileFrameArea.init();

Conclusão

Infelizmente o uso deste tipo de recurso em produção ainda dever ser utilizado em aplicações bastante especificas ou devemos também criar alternativas a elas já que uma bela parcela de usuários ainda estão utilizando navegadores que não suportam esse tipo de recurso. Mas é legal ver o que está por vir.

Os arquivos utilizados neste exemplo podem ser encontrados no repositório do blog no github.

Novo Comentário

Comentários

Jefferson Giovani

A parte do JS ficou bem comentada, ótimo artigo.

Caro, otimo exemplo, porem como eu consigo receber essa foto dentro de um post?

Você sabe se o HTML5 implementa no javascript uma forma de abrir a janela de carregamento de arquivo, aquela que aparace quando clicamos em um input file? Eu vi com o firebug que o facebook faz uma gambiarra homérica pra criar um link pra upload de fotos... deve ter outro jeito.

Daniel,

Algo genérico, que funcione em qualquer browser, não sei te dizer agora. Já fiz algo do tipo mas que funciona somente no firefox.

Não vou poder pesquisar algo agora pois estou extremamente enrolado com meu trampo e com a faculdade.

Desculpe não poder ajudar agora.

[]'s

Muito legal o exemplo, bem útil e fácil de entender! Tenho pouco conhecimento em Javascript, e gostaria de saber como faço para salvar a imagem arrastada numa pasta do servidor... Podes me ajudar, por gentileza?

Olá Heloisa,

Para você salvar a imagem em um servidor você precisará utilizar uma linguagem server-side, como Ruby, Php, Python, etc...

Eu tenho um exemplo fácil com utilizando Ruby on Rails, com outras linguagens eu não tenho nada pronto para enviar.

Ótimo post ! Obrigado.

Olá Diego! Primeiramente, muito bom seu post! Ficou bem comentado!!

Estou com uma dúvida: numa operação ajax "normal" eu uso:

$.ajax({

url: "meu_arquivo.php",

type: "POST",

data: {

variavel1: "valor 1"

},

})

como seria o upload do arquivo para o servidor? Digo... como defino a URL do arquivo php que será chamado?

Obrigado!!

Olá Lucas,

Eu costumo fazer o seguinte:

var data = new FormData();

jQuery.each(self.new_form.find('#photo_image')[0].files, function(i, file) {

data.append('image', file);

});

$.ajax({

type: "POST",

url: 'arquivo.php',

data: data,

contentType: false,

processData: false,

success: function(data) {

},

error: function() {

}

});

[]s

parabéns pelo post, muito bom! util e didatico.

estou precisando adaptar este upload pra um sisteminha que consiga "ver" varios arquivos da web, como JPG, GIF e SWF, depois retornar o widht, height e size, numa versão posterior ainda comparar com os valores pre-cadastrados.

Tem ideia por onde posso começar?

cara teu post fico muito bom mesmo.

ficou claro e simples a partir daki podemos criar muitas aplicações

más só pra eu saber eu consigo identificar outros arquivos também ou ele é restrito a imagens?

parabéns pelo post

Boas

Excelente post, gostava de adaptar este código para upload para servidor de músicas(.mp3 principalmente). Se puder dar uma ajuda ficaria muito a agradecido.

Saudações

Everton Francisco

Ótimo tutorial, muito bem comentado. Parabens!!!

Arno Roldão Junior

Passei seu codigo para dentro de do jsbin.com

http://jsbin.com/fepoxi

Assim da para brincar lá também... Belo artigo!

Muito bom o artigo! Foi util para mim.

Como posso recuperar o caminho completo do arquivo? Tipo fullname ao inves de apenas o name?

Em qual div boto a tag name pra poder fazer upload da imagem pro banco?

Post muito bom mesmo. Vi seu exemplo para o ajax de persistência. Teria aí um exemplo de como fazer essa persistência no PHP? pq só com esse html eu não vi no que eu vou dar request na página de execução.

Obrigado.

Artigo do caralho! Ótimo!

Consegui entender o código JS logo de cara, é como eu estivesse lendo um bom livro rsrs'

Diego, obrigado pelo conteúdo.

Abraço!