Arrastar e soltar

As interfaces de Drag and Drop (arrastar e soltar) habilitam aplicações a usar funcionalidades de arrastar e soltar através do navegador. Por exemplo, com essas funcionalidades, o usuário pode selecionar elementos arrastáveis (draggable) com o mouse, arrastar elementos até um elemento soltável (droppable), e soltar o elemento ao soltar o botão do mouse. Uma representação translúcida de elementos arrastáveis (draggable) seguem o ponteiro do mouse durante a operação de arrastar (drag).

Para web sites, extensões e aplicações XUL, você pode customizar os tipos de elementos que podem se tornar arrastáveis (draggable) e o tipo de retorno que o elemento arrastável produz, assim como os elementos soltáveis (droppable).

NT: Para manter a tradução mais precisa e coesa, a partir daqui iremos manter os termos drag e drop e seus variantes conforme texto original. Sendo portanto mantidos também os termos draggable e droppable.

Este documento é uma visão geral do drag and drop no HTML. Ele inclui uma descrição de suas interfaces, funcionalidades básicas de como permitir a adesão de funcionalidades arrastar e soltar em uma aplicação e um sumário da interoperabilidade entre interfaces.

Eventos Drag

O drag and drop em HTML usa o modelo de eventos DOM e os eventos drag (en-US) são hereditários dos eventos do mouse. Uma operação típica de drag começa quando o usuário seleciona um elemento arrastável com o mouse, move o mouse até um elemento soltável (droppable) e solta o mouse. Durante as operações, diversos tipos de evento são acionados e alguns podem até ser acionados multiplas vezes (como por exemplo os tipos de evento drag (en-US) e dragover (en-US).

Todos os tipos de evento drag (en-US) são associados a um manipulador global de eventos (en-US). Cada tipo de evento drag e cada atributo drag global tem um documento de referência que o descreve. A tabela a seguir descreve brevemente os tipos de evento e um link de referência para seu documento.

Event On Event Handler Description
drag (en-US) ondrag (en-US) Acionado quando um elemento ou seleção de texto está sendo arrastado.
dragend (en-US) ondragend (en-US) Acionado quando uma operação de arrastar está terminando (por eexmplo, ao soltar o botão do mouse ou pressionar a tecla esc). (Veja Terminando um evento Drag (en-US).)
dragenter (en-US) ondragenter (en-US) Acionado quando um elemento arrastável ou seleção de texto entra em um ponto de soltura (drop target). (Veja Determinando Drop Targets (en-US).)
dragexit ondragexit (en-US) Acionado quando um elemento não é mais o ponto de seleção imediata da operação drag.
dragleave (en-US) ondragleave (en-US) Acionado quando um elemento arrastável ou seleção de texto abandona um ponto de soltura (drop target) válido.
dragover (en-US) ondragover (en-US) Acionado quando um elemento ou seleção de texto está sendo arrastado sobre um ponto de soltura válido (a cada aproximadamente 100 milisegundos).
dragstart (en-US) ondragstart (en-US) Acionado quando o usuário começa a arrastar um elemento válido ou seleção de texto. (Veja Começando uma Operação Drag (en-US).)
drop (en-US) ondrop (en-US) Acionado quando um elemento ou seleção de texto é solta em um ponto d soltura (drop target) válido. (Veja Realizando um Drop (en-US).)

Note que eventos dragstart e dragend não são acionados ao arrastar um arquivo vindo do sistema operacional para o navegador.

Interfaces

A interface HTML drag and drop é composta pelos eventos DragEvent (en-US), DataTransfer, DataTransferItem (en-US) e DataTransferItemList (en-US).

A interface DragEvent (en-US) consiste de um construtor e uma propriedade, a propriedade dataTransfer (en-US) que é um objeto DataTransfer. Os objetos DataTransfer incluem estados do evento drag como o tipo de drag sendo feito (por exemplo copy ou move), os dados do do evento drag (um ou mais itens) e o tipo de cada item drag (um MIME type). Objetos DataTransfer também contém métodos para adicionar itens aos dados do drag e remover um item. As interfaces DragEvent (en-US) e DataTransfer devem as únicas necessárias para adicionar capacidades de drag and drop para uma aplicação. Entretanto, note que o Firefox provê suporte para apenas algumas Gecko-specific extensions ao objeto DataTransfer, apesar de entretanto essas extensões funcionarem apenas no Firefox.

Cada objeto DataTransfer contém uma propriedade items (en-US) que é uma lista (en-US) dos objetos DataTransferItem (en-US). Cada objeto DataTransferItem (en-US) representa um único drag item e cada item tem uma propriedade kind (tipo) (en-US) que é o tipo(kind) de data (seja ela string ou file) e uma propriedade type (tipo) (en-US) que é o tipo de dado do item (ou seja, MIME type). O objeto DataTransferItem (en-US) também contém métodos para conseguir dados do item arrastável.

O objeto DataTransferItemList (en-US) é uma lista de objetos DataTransferItem (en-US). A lista de objetos contém métodos para: adicionar um item para uma lista, remover um item de uma lista e limpar a lista com todos os itens.

A diferença chave entre das interfaces DataTransfer e DataTransferItem (en-US) é que a primeira usa o método síncrono getData() (en-US) para acessar os dados de um item arrastável, e a segunda usa o método assíncrono getAsString() (en-US) para acessá-lo.

Note: as interfaces DragEvent (en-US) e a DataTransfer são vastamente interoperáveis com navegadores desktop. Entretanto, as interfaces DataTransferItem (en-US) e DataTransferItemList (en-US) tem suporte limitado entre navegadores. Veja Interoperabildade para mais informações.

Interfaces específicas para o Gecko

A Mozilla e o Firefox suportam algumas funcionalidades fora dos padrões do modelo drag and drop. Elas são cfunções convenientes para facilitar o arraste múltiplo de elementos e a manipulação de dados que não são strings (como arquivos). Para mais informações, veja Dragging and Dropping Multiple Items. Para mais informações, veja a página de referência DataTransfer para todas as propriedades específicas para o Gecko e Métodos específicos para o Gecko.

O básico

Esta seção dispõe de um resumo das etapas básicas para adicionar a funcionalidade drag and drop à uma aplicação. Cada seção inclui uma descrição da etapa, um breve exemplo em código, e links para informações adicionais.

Identificando o que é arrastável (draggable)

Para fazer um elemento se tornar arrastável, é necessária a adição de um atributo draggable além da adição do manipulador de eventos global ondragstart (en-US), conforme descrito no exemplo a seguir

js
function dragstart_handler(ev) {
  console.log("dragStart");
  // Adiciona o id do elemento em questão ao objeto de transferência de dados (dataTransfer)
  ev.dataTransfer.setData("text/plain", ev.target.id);
}
html
<body>
  <p id="p1" draggable="true" ondragstart="dragstart_handler(event);">
    Este elemento é arrastável.
  </p>
</body>

Veja a referência do atributo draggable (en-US) e o Guia de operações drag (en-US) para mais informações.

Defina os dados do drag

A aplicação é livre para incluir qualquer quantidade de dados do item em uma operação drag. Cada dado de um item é uma string de um tipo particular, tipicamente um MIME type como por exemplo text/html.

Cada evento drag (en-US) tem uma propriedade dataTransfer (en-US) que segura os dados do evento. Essa propridade (que é um objeto DataTransfer) também tem um método para gerenciar os dados do arraste (drag). O método setData() (en-US) é usado para adicionar um item aos dados do arraste, como demonstrado no exemplo a seguir.

js
function dragstart_handler(ev) {
  // Adiciona os dados do arraste (drag)
  ev.dataTransfer.setData("text/plain", ev.target.id);
  ev.dataTransfer.setData("text/html", "<p>Parágrafo de exemplo</p>");
  ev.dataTransfer.setData("text/uri-list", "http://developer.mozilla.org");
}

Para uma lista de tipos de dados mais comuns utilizados pelo drag and drop (como texto, HTML, links, e files), veja Tipos recomendados de Drag Types (en-US) e para mais informações sobre os dados do arraste (drag data), veja Drag Data (en-US).

Defina uma imagem de arraste (drag image)

Por padrão, o navegador provê uma imagem que aparece por trás do ponteiro do mouse durante uma operação de arraste. Entretanto, uma aplicação pode definir uma imagem customizada utilizando o método setDragImage() (en-US) como demonstrado no exemplo a seguir.

js
function dragstart_handler(ev) {
  // Cria uma imagem e então a utiliza como a "drag image".
  // NOTA: mude "example.gif" como uma imagem existente, caso contrário
  // ela não será criada e a imagem padrão será utilizada como padrão.
  var img = new Image();
  img.src = "example.gif";
  ev.dataTransfer.setDragImage(img, 10, 10);
}

Para aprender mais sobre arrastar imagens de retorno, veja Definindo a imagem de retorno do arraste (Drag) (en-US).

Defina o efeito do arraste (Drag effect)

A propriedade dropEffect (en-US) é usada para controlar o retorno (geralmente visual) que é dado ao usuário durante uma operação drag and drop. Ela afeta qual cursor o navegador irá mostrar enquanto o arraste é realizado. Por exemplo, quando o usuário passa sobre (famoso hover) o ponto de soltura (drop target), o cursor do navegador pode indicar o tipo de operação que irá acontecer.

Três efeitos podem ser definidos:

copy indica que os dados sendo arrastados podem ser copiados da localização atual para a localização de destino (localização do drop).

move indica que os dados sendo arrastados irá ser movido.

link indica que alguma forma de relação ou conexão será criada entre a localização de origem (source) e de destino (drop).

Durante a operação de arraste, os efeitos do arraste (drag) podem ser modificados para determinar que certos efeitos são permitidos em determinadas localizações. Se permitido, uma soltura (drop) pode ocorrer naquela localização.

O exemplo a seguir mostra como utilizar essa propriedade.

js
function dragstart_handler(ev) {
  // Determina o efeito de arraste para copy
  ev.dataTransfer.dropEffect = "copy";
}

Veja Efeitos do Arraste (Drag Effects) (en-US) para mais detalhes.

Defina uma zona de soltura (drop zone)

Por padrão, o navegador previne tudo que possa acontecer ao soltar alguma coisa em um elemento HTML. Para mudar esse comportamento de forma que um elemento se torne uma zona de soltura (drop zone) ou que seja soltável (droppable), o elemento precisa ter ambos os atributos ondragover (en-US) e ondrop (en-US). O exemplo a seguir mostra como utilizar esses atributos e inclui manipuladores básicos de evento para cada um.

js
function dragover_handler(ev) {
  ev.preventDefault();
  // Define o dropEffect para ser do tipo move
  ev.dataTransfer.dropEffect = "move";
}
function drop_handler(ev) {
  ev.preventDefault();
  // Pega o id do alvo e adiciona o elemento que foi movido para o DOM do alvo
  var data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
<body>
  <div
    id="target"
    ondrop="drop_handler(event);"
    ondragover="dragover_handler(event);">
    Zona de Soltura (Drop Zone)
  </div>
</body>;

Note que cada manipulador chama preventDefault() para previnir o processamento adicional de eventos (como eventos touch ou eventos pointer).

Para mais informações, veja Especificando pontos de soltura (Drop Targets) (en-US).

Manipulando o efeito de soltura (drop)

O manipulador do evento drop (en-US) é livre para processar os dados do arraste (drag) de maneira específica em uma aplicação. Tipicamente, uma aplicação usaria o método getData() (en-US) para reter os itens arrastados e processá-los de acordo. A semântica da aplicação pode ser diferente dependendo do valor do dropEffect (en-US) e/ou o estado da chave que o modifica.

O exemplo a seguir mostra o manipulador de soltura (drop handler) pegando o id do elemento de origem atráves dos dados de drag (drag data) e então usando o id para mover o elemento de sua origem para o elemento de soltura (drop element).

js
function dragstart_handler(ev) {
  // Adiciona o id do elemento alvo para o objeto de transferência de dados
  ev.dataTransfer.setData("text/plain", ev.target.id);
  ev.dropEffect = "move";
}
function dragover_handler(ev) {
  ev.preventDefault();
  // Define o dropEffect para ser do tipo move
  ev.dataTransfer.dropEffect = "move";
}
function drop_handler(ev) {
  ev.preventDefault();
  // Pega o id do alvo e adiciona o elemento que foi movido para o DOM do alvo
  var data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
<body>
  <p id="p1" draggable="true" ondragstart="dragstart_handler(event);">
    Este elemento é arrastável.
  </p>
  <div
    id="target"
    ondrop="drop_handler(event);"
    ondragover="dragover_handler(event);">
    Zona de Soltura (Drop Zone)
  </div>
</body>;

Para mais informações, veja Realizando uma soltura (Drop) (en-US).

Fim da soltura (Drag end)

No início da operação de arraste (drag), o evento dragend (en-US) é acionado no elemento de origem (source) - o elemento que foi o alvo do início do arraste (drag start). Este evento é acionado sempre quando o arraste é completado ou cancelado. O manipulador de eventos dragend (en-US) pode verificar o valor da propriedade dropEffect (en-US) para determinar se a operação de arraste foi bem sucedida ou não.

Para mais informações sobre manipular o final de uma operação de arraste, veja Finalizando um arraste (Drag) (en-US).

Interoperabilidade

Como podem ser visto no DataTransferItem interface's Browser Compatibility table (en-US), drag-and-drop a interoperabilidade é relativamente ampla emtre ps brpwsers desktop (exceto as interfaces DataTransferItem (en-US) e DataTransferItemList (en-US) que tem o menor suport). Estes dados tambem indica que o suporte ao drag and drop entre browser mobile é muito menor.

Exemplos e demonstrações

Veja também