12 de agosto de 2007

31Interface drag and drop com jQuery

Customização é um dos principais conceitos da web 2.0 — deixar o usuário participar ativamente em seu website, seja com conteúdo ou com um visual personalizado. Neste artigo você confere como montar uma interface drag and drop (arrastar & soltar) utilizando a biblioteca javascript jQuery, permitindo ao usuário montar uma página a seu gosto, escolhendo a disposição dos boxes de conteúdo disponíveis no site.

Este artigo está desatualizado. Confira a nova versão deste tutorial em
http://www.daviferreira.com/blog/post/5/interface-drag-and-drop-com-jquery-atualizado.html.

Este tutorial é voltado para quem domina HTML e CSS e tem, pelo menos, uma relativa noção de javascript.

jQuery

Antes de começar, vamos falar um pouco da jQuery. Trata-se de um framework que visa facilitar a programação em javascript, tornando o código mais simples, flexível e infinitamente mais elegante. Além de ser bem leve, a jQuery conta ainda com uma comunidade bastante ativa e uma vasta gama de plugins (seu ponto forte).

Veja a seguir um exemplo de código escrito em javascript convencional e uma versão do mesmo código com jQuery.

javascript:

document.getElementById(box).style.backgroundColor = '#ff0000';

jQuery

$('#box').css('backgroundColor', '#ff0000');

Notaram a diferença? Vamos entender o código jQuery, por partes:

$('#box') — o símbolo do dólar, seguido por parênteses, é o construtor da jQuery. Graças a ele você não precisa mais perder tempo digitando document.getElementById toda vez que precisar capturar um objeto HTML pelo id. O seletor $('#box') representa o elemento HTML de id box. Alguns outros exemplos de seletores são:

  • $('a') — pega todos os elementos a do documento html;
  • $('div.caixa') — pega todos os elementos div que possuem a classe caixa;
  • $('a[@title]') — todos os elementos a que possuem o atributo title declarado;
  • $('input[@type=checkbox]') — todos os inputs do tipo checkbox.

.css() — a propriedade .css funciona para exibir ou atribuir um valor CSS de um elemento HTML. No exemplo acima, atribuímos a cor "#ff0000" à propriedade background-color do nosso elemento de id box. Para exibir a propriedade ao invés de atribuir um valor, basta omitir o segundo parâmetro, por exemplo:

$('#box').css('backgroundColor')

Confira algumas outras propriedades dos seletores jQuery:

  • .attr() — retorna/manipula os atributos de um elemento, como title, src, rel, href etc.;
  • .val() — retorna/manipula o campo value de elementos input;
  • .html() — semelhante à propriedade innerHTML do javascript convencional;
  • .text() — retorna somente o texto, sem as tags HTML, de um elemento.

É claro que isso não cobre quase nada do que a jQuery tem a oferecer. Para conferir a lista completa de seletores, comandos, propriedades e métodos visite o wiki do projeto em docs.jquery.com.

Arquivos necessários

A interface drag an drop que iremos desenvolver aqui utiliza os plugins de interface disponíveis neste link e nosso código será baseado no módulo Sortables.

O primeiro passo é declarar os arquivos javascript no head de nosso documento HTML.

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="interface.js"></script>

Observação: neste exemplo, estamos utilizando uma versão completa do arquivo interface.js, com todos os seus módulos, mas nada impede (e eu até recomendo) que você utilize no seu projeto final uma versão compactada apenas com os módulos necessários. Você pode conferir a lista de dependências do Sortables acessando este link.

Downloads:

Elementos da interface

Agora vejamos o que é necessário, esquecendo um pouco a parte de javascript, para a construção de uma interface drag and drop. Que elementos vamos utilizar?

  • No mínimo uma área para soltar os elementos arrastados;
  • Alguns elementos que serão arrastados e soltos nas áreas disponíveis no site;
  • Uma área temporária de ajuda, para indicar onde o elemento que está sendo arrastado pode ser solto;
  • Todo elemento arrastável deve possuir um handle, ou seja, alguma área dentro do próprio elemento onde o usuário irá clicar para arrastá-lo.

Sendo assim, definiremos as seguintes classes CSS para identificar os elementos de nossa interface:

  • recebeDrag
  • itemDrag
  • dragAjuda

No caso do handle não utilizaremos uma classe, mas sim um elemento específico: a tag h2.

Todos os elementos com a classe recebeDrag servirão de base para os elementos arrastáveis. Estes, por sua vez, virão acompanhados da classe itemDrag. O elemento de ajuda (dragAjuda) não precisa ser declarado no documento HTML — o plugin de interface da jQuery se encarrega de fazer isso, apenas o CSS precisa ser criado. Todo itemDrag deve ainda possuir um elemento H2 para arrastá-lo. Nossa estrutura ficou assim:

Elementos da interface drag and drop

E o CSS:

div.recebeDrag {
	min-height: 50px;
}
div.itemDrag {
	margin: 7px;
	border: 1px solid #ccc;
	padding: 7px;
}
div.itemDrag h2 {
	cursor: move;
	background-color: #ff3300;
	color: #fff;
	padding: 3px;
}
.dragAjuda {
	border: 3px dashed #0066cc;
	width: auto !important;
}

Monte um documento HTML com o CSS acima e inclua quantas áreas e ítens quiser para efetuarmos nosso teste.

document.ready

Com nosso HTML pronto, agora resta apenas instanciar o elemento Sortable da jQuery. Ao invés de utilizar o bom e velho onload no body, vamos adotar uma abordagem mais elegante e garantida, já que espera todo o DOM ser carregado antes de ser executada. Ao final de nosso HTML, antes de fecharmos o , utilizaremos o seguinte código javascript:

$(document).ready(
	function () {
		$('div.recebeDrag').Sortable(
			{
				accept			: 'itemDrag',
				helperclass		: 'dragAjuda',
				activeclass 	: 'dragAtivo',
				hoverclass 		: 'dragHover',
				opacity			: 0.7,
				handle			: 'h2',
				onChange 		: function()
				{	    			 
					serialEsq = $.SortSerialize('drop-esquerda');
					serialDir = $.SortSerialize('drop-direita');
				},
				onStart : function()
				{
					$.iAutoscroller.start(this, $('body'));
				},
				onStop : function()
				{
					$.iAutoscroller.stop();
				}
			}
		);
	}
);
  

O comando/seletor $(document).ready funciona, de certa forma, como o . Estamos solicitando que, ao carregar o documento, os elementos div com a classe recebeDrag sejam inicializados como objetos Sortables. Logo em seguida declaramos os parâmetros aceitos na nossa interface drag and drop, bem como as ações a serem executadas quando o elemento é mudado de lugar, quando tem início a ação de arrastar e quanto termina esta mesma ação.

O bloco dos parâmetros é bem simples. Primeiro, utilizando o parâmetro accept, definimos que os divs com a classe recebeDrag aceitarão apenas elementos com a classe itemDrag arrastados dentro deles. Os quatro parâmetros seguintes são referentes às classes e estilos CSS. helperclass define a classe do elemento que demarca áreas em que os divs itemDrag podem ser soltos. hoverclass e activeclass são as classes de estado active e hover para o elemento recebeDrag. Já o parâmetro opacity define o nível de transparência de um elemento, podendo variar de 0 a 1.

handle, conforme explicado anteriormente, define o elemento HTML que servirá como "link" para arrastar os divs itemDrag.

E, por fim, as ações:

  • onChange — qualquer função declarada neste parâmetro será executada quando um elemento for arrastado e solto, e sua posição inicial for alterada. É ideal para executar comandos AJAX para gravar a posição em banco de dados ou arquivo, ou simplesmente setar um cookie ou uma variável de sessão. No nosso exemplo estamos apenas executando a função nativa $.SortSerialize, que retorna as posições de cada elemento do recebeDrag, sem gravar nada.
  • onStart — é executada quando tem início o movimento de arrastar o div. Em nossa interface estamos executando o plugin de autoscroll da jQuery, para que o movimento de arrastar e soltar não fique limitado a área visível do navegador.
  • onStop — executada quando o movimento de arrastar é interrompido.

Interface em ação

Clique aqui para conferir um exemplo bem simples da nossa interface drag and drop. O CSS e o javascript foram todos declarados no arquivo, basta exibir o código-fonte para entender melhor o funcionamento do nosso exemplo.

Para visualizar a versão final deste teste, visite o site beta do Democracia.

Sugestões de funcionalidades

  • Opção para fechar e minimizar as janelas arrastáveis;
  • Possibilidade para adicionar ou remover boxes de conteúdo da interface.

Referências

Atualização [06/12/2008]

Muita gente me pergunta sobre isso, então aí vai um exemplo utilizando cookies para salvar o posicionamento e ordenação definidos pelo usuário.

Exemplo com cookies

Os cookies estão sendo gerenciados diretamente via javascript, através do plugin jCookie: http://plugins.jquery.com/project/cookie.

Confira o que mudou no código. Na propriedade onchange do elemento sortable adicionamos o método $.cookie() para criar um cookie relacionado à cada coluna:

onChange 		: function()
{	    			 
	serialEsq = $.SortSerialize('drop-esquerda');
	serialDir = $.SortSerialize('drop-direita');
	// salva cookie com posicionamento
	$.cookie('coluna1', serialEsq.hash, {expires: 7});
	$.cookie('coluna2', serialDir.hash, {expires: 7});
}

E, após carregar o documento, verificamos se o cookie existe e definimos o posicionamento dos boxes nas colunas:

$(document).ready(
	function () {
		if ($.cookie('coluna1') != null) {
			// formata string do cookie
			var coluna1 = $.cookie('coluna1').replace(/drop-esquerda[]=/g, '');
			var coluna1 = coluna1.split('&');
			var div_id = '';
			for (var x = 0; x < = coluna1.length; x++) {
				div_id = coluna1[x];
				$('#drop-esquerda').append($('#'+div_id)); 
			}
		}
		if ($.cookie('coluna2') != null) {
			// formata string do cookie
			var coluna2 = $.cookie('coluna2').replace(/drop-direita[]=/g, '');
			var coluna2 = coluna2.split('&');
			var div_id = '';
			for (var x = 0; x <= coluna2.length; x++) {
				div_id = coluna2[x];
				$('#drop-direita').append($('#'+div_id)); 
			}
		}
	}
);

Simples, não? :)

31 leitores comentaram este artigo

  • 13/12/2007
    22:09

    Daniel escreveu:

    Olá!
    Consegui seguir os passos acima. Porém, seria importante salvar essas alterações, tipo cookies temporários.. mas não entendo nada de JS.. Jquerry.. teria algum tutorial explicando como fazer esta integração com este código do tutorial?

    abs!

    Responder

  • 16/12/2007
    23:26

    Davi Ferreira escreveu:

    E aí, Daniel. Estou preparando um post com essa segunda etapa. Mas o segredo está na propriedade onChange do Sortable, é ali que você deve salvar o cookie.

    O próprio jquery tem um plugin para cookies:
    http://www.stilbuero.de/2006/09/17/cookie-plugin-for-jquery/

    Abraços!

    Responder

  • 03/01/2008
    21:59

    Eduardo Ferreira Leite escreveu:

    Ola Davi estou precisando de alguém que faça um código deste p/ que eu possa implementar em um site,com 14 box destes tipo somente 2 colunas uma maior e outra menor.Sou webdesigner...preciso do valor que vc cobraria p/ desenvolver ou se tem alguém para indicar...valeu

    Responder

  • 30/01/2008
    19:05

    Ramon escreveu:

    Valeu cara, era disso que eu tava precisando!! Eu to tentando adaptar isso pro joomla e to conseguindo =D VALEU MESMO!!!

    PS: Como colocar uma opção pra desaparecer a div e outra pra ocultar e só deixar o h2?

    Responder

  • 12/11/2008
    10:37

    rodrigo escreveu:

    Olá amigo, muito bom o post, só que to tendo alguns problemas, veja esse site aqui como exemplo: http://beta.democracia.com.br/# , as divs simplesmente depois de movimentar-se 2 vezes no IE7, não movimenta mais, enquanto no FF funfa na boa... eu estou implementando a jquery e o interface em um site e está dando o mesmo problema, será que poderia me ajudar a ver o erro??? Obrigado desde já

    Responder

  • 13/11/2008
    00:08

    Davi Ferreira escreveu:

    @rodrigo
    Realmente tá com esse bug no democracia no IE7, valeu o toque, vou dar uma conferida e depois te falo. Talvez seja porque lá usa uma versão antiga ainda do jquery. O próprio drag and drop já tem uma versão mais atual do que a deste post, no http://ui.jquery.com.

    O exemplo do artigo funciona na boa no IE7. Tem um link ali no último parágrafo. Se quiser me mandar uma URL de teste do teu site pra eu dar uma conferida, fique a vontade, manda ali pelo form de contato.

    Responder

  • 11/12/2008
    11:33

    rodrigo escreveu:

    opa. eu aki denovo, conseguiu ver ql o problema? eu ja tentei usar a versão mais nova da jquery e msm assim naum to conseguindo, não tenho o link pois o site ainda não está no ar.

    Responder

  • 12/12/2008
    02:41

    Davi Ferreira escreveu:

    @Rodrigo: é problema de versão do jQuery sim, só não pode ser a mais nova mesmo :( Só consegui fazer funfar no IE7 com a 1.1.2. Se quiser baixa daqui, usei no exemplo dos cookies: http://www.daviferreira.com/blog/exemplos/draganddrop/jquery.js.

    Vou ver depois se consigo fazer com a versão mais nova, mas provavelmente vou ter que migrar tudo pro interface.js novo.

    Responder

  • 12/12/2008
    14:16

    Rodrigo escreveu:

    Vlw cara. Funcionou na boa!!! Mas acho q naum vai funfar na versão nova não pq era com ela q eu tava, e o interface tb... :S

    Qlqr coisa me dá um tok.

    Forte abraço!

    Responder

  • 16/12/2008
    10:17

    Rodrigo escreveu:

    Olha eu aqui denovo, ¬¬ ^^, é q no site do democracia eu achei interessante tb o fato de poder minimizar e maximizar as divs, até to tentando implementar isso, mas gostaria de saber se tem um idéia de como ficaria o script para o estado inicial dela ser display none, tipo so abre qnd o usuario clicar... tem alguma idéia??? vlw! Abraço!

    Responder

  • 18/12/2008
    23:54

    Davi Ferreira escreveu:

    Fala Rodrigo!

    Não sei bem se entendi sua dúvida, mas não seria só colocar o CSS inicial do elemento com 'display:none;'?

    Responder

  • 30/12/2008
    17:47

    kirotawa escreveu:

    Opa, gostei do teu tutorial. Mas tipo eu fiz um controlC, controlV aqui e funfou legal, mas não to conseguindo salvar as posições com o cookie. to fazendo algo errado:

    $(document).ready(
    function () {
    if ($.cookie('coluna1') != null) {
    // formata string do cookie
    var coluna1 = $.cookie('coluna1').replace(/drop-esquerda[]=/g, '');
    var coluna1 = coluna1.split('&');
    var div_id = '';
    for (var x = 0; x < = coluna1.length; x++) {
    div_id = coluna1[x];
    $('#drop-esquerda').append($('#'+div_id));
    }
    }
    if ($.cookie('coluna2') != null) {
    // formata string do cookie
    var coluna2 = $.cookie('coluna2').replace(/drop-direita[]=/g, '');
    var coluna2 = coluna2.split('&');
    var div_id = '';
    for (var x = 0; x <= coluna2.length; x++) {
    div_id = coluna2[x];
    $('#drop-direita').append($('#'+div_id));
    }
    }
    }


    $('div.recebeDrag').Sortable(
    {
    accept : 'itemDrag',
    helperclass : 'dragAjuda',
    activeclass : 'dragAtivo',
    hoverclass : 'dragHover',
    handle : 'h2',
    opacity : 0.7,
    onChange : function()
    {
    serialEsq = $.SortSerialize('drop-esquerda');
    serialDir = $.SortSerialize('drop-direita');
    $.cookie('coluna1', serialEsq.hash, {expires: 7});
    $.cookie('coluna2', serialDir.hash, {expires: 7});
    $('#ser-e').val(serialEsq.hash);
    $('#ser-d').val(serialDir.hash);
    },
    onStart : function()
    {
    $.iAutoscroller.start(this, document.getElementsByTagName('body'));
    },
    onStop : function()
    {
    $.iAutoscroller.stop();
    }
    }
    );
    }
    );

    Responder

  • 30/12/2008
    18:08

    kirotawa escreveu:

    Opa eu denovo, esquece aí. Nesse negócio de ControlC controlV, esqueci do jquery.cookie.js :P. Agora funfou, vlws.

    Responder

  • 03/03/2009
    13:16

    Reginaldo escreveu:

    Opa, muito bom seu tutorial cara
    Só estou com um problema na hora de criar o cookie e armazenar as posições. Ele cria o cookie, porem cria vazio...nao armazena nada.
    Sabe me dizer o pq ou desconfia de algo??

    Grato

    Responder

  • 04/04/2009
    19:19

    Eder Santana escreveu:

    Excelente tutorial! Só tô com uma dúvida: como eu faço para aumentar a quantidade de colunas? Gostaria de utilizar 4 colunas. Obrigado!

    Responder

  • 08/05/2009
    15:25

    Ezequiel escreveu:

    Parabéns pela extensão, porém eu não sei se o problema é com a versão que acabei de baixar ou se é no meu css, pois quando eu arrasto o item ele não se posiciona no lugar que o .dragAjuda marcou, ele fica posicionado no lugar que arrastei, ou seja ele fica desalinhado se eu jogar mais pra esquerda, ele vai, se colocar mais pra direita, também.

    Responder

  • 08/05/2009
    16:20

    Ezequiel escreveu:

    eu consegui arrumar aplicando
    position: static !important;
    no item. Porém creio que não seja a forma certa de arrumar. Abraço.

    Responder

  • 08/05/2009
    16:27

    Ezequiel escreveu:

    Não tem como disponibilizar uma versão descriptografada, porque estou tendo uma incompatibilidade com o plugin scrollTo do jQuery. Se eu pudesse verificar o código poderia tentar contornar essa incompatibilidade. Abraço.

    Responder

  • 08/05/2009
    17:23

    Ezequiel escreveu:

    o endereço do plugin é:
    http://plugins.jquery.com/project/ScrollTo
    Ele não ta mais dando scroll quando coloco o js de interface.

    Responder

  • 09/05/2009
    00:15

    Ezequiel escreveu:

    Eu experimentei usar o sortable do jQuery UI porém tive melhor flexibilidade com o seu, o único problema que tive com o interface é mesmo o já citado problema do IE e a incompatibilidade com o scrollTo. Consertando isso seu plugin estaria 100% ;). Abraço.

    Responder

  • 15/05/2009
    12:06

    Phillipp M. Oliveira escreveu:

    Foi um excelente post, muito bom mesmo. Só tive um problema... quando eu coloco as 4 divs em apenas um lado, ao dar F5 não consigo mais movimentá-las (com e sem cookies).

    Abrços =)

    Responder

  • 03/06/2009
    18:46

    Drag and Drop com jQuery | Links Web escreveu:

    [...] Site: http://www.daviferreira.com/blog/2007/08/12/interface-drag-and-drop-com-jquery.html [...]

    Responder

  • 02/07/2009
    17:26

    Daniel Schultz escreveu:

    Gostei. No momento estou desenvolvendo um sistema de assentos para onibus que usará o conceito de drag'n drop com jquery.

    Responder

  • 31/08/2009
    21:32

    Beto escreveu:

    Estou usando com 3 colunas a inicial, mais 2 que vão receber, não teria como eu arrastar um ter outro embaixo escondido? tipo "Item 1"... arrasto ele para a coluna 1, e já ficaria outro "Item 1" no mesmo lugar que eu puxei o primeiro para eu poder arrastar para a coluna 2, e uma opção para excluir se necessário

    Responder

  • 28/09/2009
    20:40

    Interface drag and drop com jQuery (atualizado) | Davi Ferreira blog! escreveu:

    [...] 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 [...]

    Responder

  • 15/03/2010
    13:37

    Paulo Junior escreveu:

    Fala David,

    Como eu poderia colocar as DIV para Maximizar na Tela toda ou seja se eu clicar no [+] eu queria maximizar a tela toda e não somente Expandir para baixo a mesma. É complicado realizar isto?
    Abs.,

    Responder

  • 15/03/2010
    17:18

    Davi Ferreira escreveu:

    Fala, Paulo!

    Na verdade é bem simples, é só utilizar os métodos width e height nativos do jquery, pra pegar o tamanho do viewport (window):


    $(window).height();
    $(window).width();


    Se tiver muita dificuldade me fala que eu mostro uma função de exemplo.

    Valeu!

    Responder

  • 16/03/2010
    07:02

    Paulo Junior escreveu:

    Gostaria muito de um exemplo, pois sou novato na questão de JQuery, se fosse possível me mande sim este exemplo. Desde já agradeço pela sua ajuda e rapidez. Gostei muito do Blog e já indiquei para várias outras pessoas, parabéns pelo trabalho.

    abs.,

    Responder

  • 16/03/2010
    15:13

    Davi Ferreira escreveu:

    Beleza, Paulo.

    Atualizei o meu segundo artigo sobre drag and drop com o exemplo que você pediu, dá um confere no final dele!

    Abrá!

    Responder

  • 17/03/2010
    06:59

    Paulo Junior escreveu:

    Falow Davi,

    Muito Show!! Era o que eu queria mesmo, obrigado pela ajuda e espero alguma hora contribuir com algo para o seu blog, que esta muito bom.

    Abs.,
    Junior

    Responder

  • 26/03/2010
    08:15

    Benjamim Alves escreveu:

    Ora boas Davi,

    Sou novo em JQuery e gostaria de saber como é que gravo no cookie quais são as minhas div's que têm o slide aberto e fechado?

    Cumprimentos.

    Responder

Deixe seu comentário

Todos os campos são obrigatórios.

(Seu e-mail não será divulgado - serve apenas para validação e gravatar.)

(Tags HTML permitidas: <strong> <em> <code> <a>)

Opções

Ordenar por

Modo de exibição