28 de setembro de 2009
21Interface drag and drop com jQuery (atualizado)
Muita gente chega no meu blog pesquisando por "drag and drop". Em respeito a esses leitores resolvi dar uma atualizada no meu primeiro artigo sobre o tema. Na época em que foi publicado, ainda não existia a parte de interface oficial do jQuery - muitos elementos, aliás, foram incorporados dos plugins de interface não-oficiais do site eyecon.ro.
Com o lançamento oficial dos plugins ui.jQuery ficou muito mais fácil desenvolver aquela mesma interface drag and drop do primeiro artigo. Agora, com duas linhas de configuração você já consegue criar duas colunas com boxes configurados para arrastar e soltar.
$("#drop-direita").sortable({connectWith: ["#drop-esquerda"]});
$("#drop-esquerda").sortable({connectWith: ["#drop-direita"]});
UPDATE: Na verdade, precisamos de apenas uma linha. Não tinha me ligado que dá pra fazer a conexão dos sortables com uma classe. Fica assim:
$('.recebeDrag').sortable({connectWith: ['.recebeDrag']});
A diferença agora é que não necessitamos mais dos eventos Draggable and Droppable (por mais irônico que isso possa parecer). O método Sortable resolve tudo sozinho.
Para saber mais sobre a biblioteca de interface do jQuery acesse o site: ui.jquery.com. Lá você conhece outros efeitos e widgets.
Aproveitando o upgrade do artigo, vou implementar algumas funções muito solicitadas via e-mail:
- Salvar o posicionamento dos boxes em um cookie e lembrar na próxima visita.
- Minimizar e remover os boxes.
Configuração inicial

Vamos manter a mesma estrutura do artigo anterior, com elementos DIV da classe 'recebeDrag' servindo de base para os DIVs com a classe itemDrag. O pulo do gato aqui é a opção 'connectWith' do sortable. Com este parâmetro ligamos dois ou mais elementos para funcionarem como objetos que permitam ordenação entre si. Está feito nosso drag and drop.
Caso adicionássemos uma terceira coluna, #drop-meio, por exemplo, nosso código ficaria assim:
$("#drop-esquerda").sortable({connectWith: ["#drop-direita","#drop-meio"]});
$("#drop-meio").sortable({connectWith: ["#drop-direita","#drop-esquerda"]});
$("#drop-direita").sortable({connectWith: ["#drop-esquerda","#drop-meio"]});
No arquivo final do exemplo, utlizei alguns métodos do sortable para melhorar o visual e os efeitos do nosso drag and drop. São eles:
- placeholder: aqui definimos que a classe 'dragHelper' vai servir para indicar a área vazia que estará recebendo o elemento arrastado.
- scroll: marcando a opção scroll como true, obrigamos a barra de rolagem do navegador a ir até a posição do mouse.
- revert: essa é firula total, apenas adiciona um efeito de transição quando um elemento é liberado.
Nossa chamada fica assim:
$('.recebeDrag').sortable({
connectWith: ['.recebeDrag'],
placeholder: 'dragHelper',
scroll: true,
revert: true,
stop: function( e, ui ) {
salvaCookie();
}
});
Cookie de posicionamento
Sim, no código acima já deixei preparado a função para salvar nosso cookie. Pra ela funcionar direitinho, precisamos primeiro do plugin jquery.cookie.
Quando termina o movimento de arrastar e soltar, através da opção 'stop', executamos a função salvaCookie(). A função grava em dois índices de um array a sequência de IDs dos elementos de cada box (esquerda e direita) utilizando o método toArray.
var salvaCookie = function() {
var ordem = $('#drop-esquerda').sortable('toArray');
ordem += '|' + $('#drop-direita').sortable('toArray');
$.cookie('df_draganddrop', ordem);
};
E, toda vez que a página é carregada, o jQuery busca pelo cookie 'df_draganddrop' (pode ser o nome que você quiser) e configura o posicionamento dos boxes. O ideal é fazer isso via PHP (ou qualquer linguagem de programação que você esteja utilizando), desenvolvi em javascript só para ter um exemplo mais básico.
if( $.cookie('df_draganddrop') ) {
var ordem = $.cookie('df_draganddrop').split('|');
// posiciona boxes nos containers certos
$('#drop-esquerda div.itemDrag').each(function(){
if( ordem[0].search( $(this).attr('id') ) == -1 ) $('#drop-direita').append($(this));
});
$('#drop-direita div.itemDrag').each(function(){
if( ordem[1].search( $(this).attr('id') ) == -1 ) $('#drop-esquerda').append($(this));
});
// ordena containers
var esquerda = ordem[0].split(',');
for( i = 0; i< = esquerda.length; i++ ) $('#drop-esquerda').append($('#'+esquerda[i]));
var direita = ordem[1].split(',');
for( i = 0; i<= direita.length; i++ ) $('#drop-direita').append($('#'+direita[i]));
} else {
$.cookie('df_draganddrop', '', { expires: 7, path: '/' });
}
Primeiro verificamos se o cookie já existe. Se não existir, criamos um novo cookie com validade de uma semana.
Minimizando e removendo
Outro funcionamento muito legal é minimizar e remover boxes, personalizando totalmente uma listagem de conteúdos. Por ser um exemplo bem básico, não vamos salvar nada disso em nosso cookie de posicionamento. O ideal seria, para poder excluir no cookie, ter uma opção de adicionar boxes. Fica aí como dever de casa!
Para minimizar utilizaremos o efeito slideUp nativo do jQuery, mas nada impede você de utilizar fade ou animate. A opção de remover utiliza o fadeOut. Determinamos através do método bind que os links com as classes 'lnk-minimizar' e 'lnk-remover', nos seus respectivos cliques, minimizam e removem boxes de nossa interface drag and drop.
$('.lnk-minimizar').click(function(){
var ul = $(this).parent().parent().parent().find('ul');
if( $(ul).is(':visible') ) {
$(ul).slideUp();
$(this).html('[ + ]');
} else {
$(ul).slideDown();
$(this).html('[ - ]');
}
return false;
});
$('.lnk-remover').click(function(){
$(this).parent().parent().parent().fadeOut();
return false;
});
Código javascript final
Segue abaixo o javascript completo. Não deixe de fazer o download dos arquivos de exemplo, com todo o HTML/CSS e Javascript necessário. E se publicar um site com essa interface não deixe de mandar o link nos comentários!
$(function(){
// configura drag and drop
$('.recebeDrag').sortable({
connectWith: ['.recebeDrag'],
placeholder: 'dragHelper',
scroll: true,
revert: true,
stop: function( e, ui ) {
salvaCookie();
}
});
// minimizar boxes
$('.lnk-minimizar').click(function(){
var ul = $(this).parent().parent().parent().find('ul');
if( $(ul).is(':visible') ) {
$(ul).slideUp();
$(this).html('[ + ]');
} else {
$(ul).slideDown();
$(this).html('[ - ]');
}
return false;
});
// remover box
$('.lnk-remover').click(function(){
$(this).parent().parent().parent().fadeOut();
return false;
});
// configuração inicial do cookie
if( $.cookie('df_draganddrop') ) {
var ordem = $.cookie('df_draganddrop').split('|');
// posiciona boxes nos containers certos
$('#drop-esquerda div.itemDrag').each(function(){
if( ordem[0].search( $(this).attr('id') ) == -1 ) $('#drop-direita').append($(this));
});
$('#drop-direita div.itemDrag').each(function(){
if( ordem[1].search( $(this).attr('id') ) == -1 ) $('#drop-esquerda').append($(this));
});
// ordena containers
var esquerda = ordem[0].split(',');
for( i = 0; i< = esquerda.length; i++ ) $('#drop-esquerda').append($('#'+esquerda[i]));
var direita = ordem[1].split(',');
for( i = 0; i<= direita.length; i++ ) $('#drop-direita').append($('#'+direita[i]));
} else {
$.cookie('df_draganddrop', '', { expires: 7, path: '/' });
}
});
// salva cookie
var salvaCookie = function() {
var ordem = $('#drop-esquerda').sortable('toArray');
ordem += '|' + $('#drop-direita').sortable('toArray');
$.cookie('df_draganddrop', ordem);
};
21 leitores comentaram este artigo
29/09/2009
11:30
Everton escreveu:
Parabéns Davi!
Essa atualização chegou em boa hora.
Código perfeito, explicação clara... exatamente o que eu precisava. Valeu mesmo!!!
Abraço
Responder
04/10/2009
00:26
Marcio escreveu:
Parabens pelo excelente tutorial, so fiquei voando pra fazer com tres colunas utilizando a opção de salvar cookie, tem como dar um help??
Responder
05/10/2009
15:11
Davi Ferreira escreveu:
Fala Marcio, é só adicionar na hora de posicionar e ordenar. Se você utilizar o ID #drop-meio, ele seria o ordem[2] no array depois do split. Tem que replicar as funções que tem pro drop-esquerda/drop-diretia pra esse drop-meio.
Mas, pensando bem, dá pra fazer mais fácil com CSS, depois reformulo e publico no post.
Valeu!
Responder
02/11/2009
14:36
William Bauch escreveu:
Davi boa tarde, vc conhece algum artigo que mostre como salvar a posição usando um banco de dados (MySql)? obrigado
Responder
04/11/2009
08:12
Davi Ferreira escreveu:
Fala aí, William!
Cara, é só adaptar a função salvaCookie (ou criar uma salvaMysql :)). Toda vez que você define a ordem, faz uma chamada com $.post ou $.get do jQuery pra salvar no banco via AJAX.
Se tiver dificuldades me dá um toque que te mostro um exemplo. Ou se conseguir colocar em prática compartilha aí com a galera.
Valeu!
Responder
17/02/2010
06:38
Bruno escreveu:
Coloca ai pra gente como se faz. Estou tentando fazer mais não consigo.
Responder
04/11/2009
21:37
AsSuStAdO escreveu:
Cara! Muito bonito esse site hein! Parabéns.
Só passei pra dizer isso mesmo! ehehhe
Responder
05/11/2009
08:21
Isaque Siqueira escreveu:
Bom dia! Não consegui baixar os arquivos de exemplo .zip, se puder me disponibilizar agradeço. Parabéns muito bom o código.
Responder
05/11/2009
09:28
Davi Ferreira escreveu:
Fala, Isaque.
Corrigi lá o link, tenta agora. Valeu pelo toque!
Responder
05/11/2009
22:32
Sergio escreveu:
Primeiramente gostaria de parabenizar.
Estou precisando adicionar mais duas colunas, porém na hora de ordenar fica complicado pois no caso de duas colunas apenas se o box não estiver em um container vai estar no outro, mas no caso de quatro colunas é mais complicado. Obrigado desde já. Um Abraço!
Responder
17/11/2009
17:47
Fernando Vulcano escreveu:
E Aí Davi Belezera? eu tô com a mesma dúvida do William. Tem como vc colocar um exemplo pra gravar no mysql? abração
Responder
01/12/2009
09:20
Davi Ferreira escreveu:
Galera, é só ler o cookie e salvar as posições da forma que você achar melhor. O cookie criado fica acessível pra qualquer linguagem, php, asp etc.
O nome no exemplo é: 'df_draganddrop'.
Você pode salvar com AJAX via jQuery, ou toda vez que atualizar a página lê o cookie, ou criar um botão salvar etc. Existem diversos métodos.
Responder
17/11/2009
17:48
Sergio escreveu:
Sugestão para um melhor efeito:
$(".recebeDrag").sortable({
connectWith: ['.recebeDrag'], placeholder: 'dragHelper', forcePlaceholderSize: true,
scroll: false,
revert: true,
stop: function( e, ui ) {
salvaCookie();
}
});
Responder
17/11/2009
17:55
Fernando Vulcano escreveu:
Sérgio, vc ja fez gravar no bd de alguma vez?
Responder
30/11/2009
21:27
Righi escreveu:
Meu problema é o seguinte:
Tenho algumas áreas que são 'sortables', como janelas. Dentro dessas áreas tenho vários objetos que também são 'sortables'. Quero mover esse objetos de uma janela para outra, ou ainda movê-los para fora dessas áreas, no mesmo nível das mesmas.
Já tentei de várias formas, porém quando pego algum objeto fora das áreas o jQuery entende que estou posicionando o objeto relativamente a área, e reposiciona a mesma pra mim. A questão é que se eu 'soltar' o objeto em cima da área, gostaria que o objeto passasse a fazer parte da 'sub-lista' que está dentro da área, e não fosse posicionado acima ou abaixo, reposicionando a área.
Alguém tem alguma dica?
Valeu!
Responder
01/12/2009
09:18
Davi Ferreira escreveu:
Fala Righi,
acho que não entendi muito bem sua dúvida. Tem como disponibilizar um HTML de exemplo?
Abraços!
Responder
03/12/2009
06:37
Righi escreveu:
Olá Davi,
Na realidade eu já consegui resolver. Apenas utilizei o parâmetro 'items: ...' que eu não havia utilizado.
O que estava tentando fazer era colocar um sortable dentro de outro (nested), mas ele estava se perdendo, e utilizando este parâmetro ele passou a funcionar.
O problema agora é que com nested sortables o Internet Exploder não funciona corretamente.
Abraços.
Responder
20/02/2010
07:54
Emerson Brôga escreveu:
Muito bom o tutorial cara ....gostei mesmo ...Valeu!!!
Responder
24/02/2010
12:31
Alessandro Gonzalez escreveu:
Muito bom Post Davi...
Parabéns.
Responder
Deixe seu comentário