Uma aula prática de jQuery
Nomenclatura
Durante o texto vou me referir à função $ como função jQuery, pois na verdade elas são a mesma coisa. A diferença é que a função $ não estará disponível se você optar por utilizá-la sem conflitos.
Como começar
Antes de escrever qualquer código JavaScript, faço questão de utilizar aquela técnica clássica onde o nosso código JS começa a ser executado apenas quando o DOM terminou de ser carregado:
$(document).ready(function() {
// aqui vai o código específico da sua aplicação
});
Esse código eu deixo em um arquivo externo, e o referencio a partir da tag <script> presente no meu template HTML (independente do framework que você estiver – ou não – utilizando, manter o código JS fora do seu template HTML é uma forma simples de separar apresentação e comportamento).
Deste ponto em diante passo a omitir essas linhas de inicialização. Todo o código que for exibido pode ser posicionado na linha 2 da listagem de código acima.
Encontrando elementos
Cedo ou tarde você precisará encontrar elementos do seu documento e manipulá-los. Na verdade, boa parte da minha programação JavaScript consiste disso. Com o jQuery, qualquer ação começa com uma chamada à função jQuery, e com esta não poderia ser diferente. Para encontrar um elemento você pode passar uma string que atenda a especificação da biblioteca para seletores. Alguns exemplos:
// todos os parágrafos contendo a classe "warning"
$('p.warning');
// todas as checkboxes dentro do elemento de id "users_list"
$('#users_list input[type=checkbox]');
Fazendo alguma coisa com os elementos
Encontrar os elementos e não fazer nada com eles não serve pra muita coisa. Por exemplo, vamos imaginar que você queira fazer a seguinte operação: quando o usuário clicar em um link com a classe help, vamos mostrar a ele um alerta. É algo bem estúpido, e como esperado, simples de fazer:
$('a.help').click(function() {
alert('Você clicou num parágrafo de ajuda!');
});
A função jQuery, quando recebe uma string, irá retornar um outro objeto jQuery, contendo internamente uma lista de todos os elementos encontrados no documento que satisfazem a sua consulta. Como esse retorno é um outro objeto jQuery, você já pode realizar uma chamada de função sobre esse objeto (neste caso, click). Veremos mais adiante como levar esse conceito ao extremo.
Parando eventos
Quando definimos o evento para cliques sobre links com a classe help, não evitamos que a URL especificada no atributo href do link fosse seguida pelo navegador. Se esse link tinha como href o símbolo #, então após o clique a barra de rolagem vertical (se existia) foi movida para o topo do documento.
Para evitar esse comportamento, precisamos utilizar o objeto de tipo Event que o jQuery envia para a nossa função de processamento de eventos. Veja como:
$('a.help').click(function(e) {
// o link não será seguido pelo navegador
e.preventDefault();
});
Caso você esteja observando a submissão de um formulário, pode utilizar a mesma técnica para evitar que o formulário seja submetido.
$('form#create_user').submit(function(e) {
// o formulário não será enviado
e.preventDefault();
});
Esses são apenas alguns dos eventos disponíveis, aqui você pode encontrar todos eles.
Manipulando as classes de um elemento
Você tem à disposição 3 métodos básicos para manipular as classes de elementos. Aprenda a utilizá-los com exemplos:
// adiciona a classe "teste" ao parágrafo
$('p:first').addClass('teste')
// remove a classe "teste" ao parágrafo
$('p:first').removeClass('teste')
// adiciona (se não existir) ou remove (se existir) a classe "teste" ao parágrafo
$('p:first').toggleClass('teste')
Acessando atributos
Acessar atributos é algo trivial com jQuery:
// recupera o "href" do link
var id = $('a#add_another_row').attr('id');
// define o "href" do link
var id = $('a#add_another_row').attr('href', '#');
Note que attr atua apenas sobre o primeiro elemento interno a um objeto jQuery. Por atributos, nesse caso, entende-se as propriedades de um elemento HTML (diferente de suas propriedades de estilo).
Definindo estilos de elementos
Sempre que possível procuro manter todos os estilos associados ao documento dentro das minhas definições CSS. Assim, se quero modificar o visual do sistema, sei que é apenas lá que devo mexer. Mas em algumas situações me vi obrigado a quebrar essa regra. São casos onde você precisará manipular propriedades CSS específicas de elementos.
$('a#do_something_crazy').click(function(e) {
e.preventDefault();
// vamos recuperar a cor do link
alert("Agora o link tem cor " + $(this).css('color'));
// agora vamos alterar apenas a cor do link
$(this).css('color', 'blue');
// agora vamos alterar as propriedades CSS "color" e "background-color" do link
$(this).css({
color: 'green',
backgroundColor: 'red'
});
});
Na listagem acima apresentei as 3 formas de utilizar a função css:
css(propriedade): recupera o valor de “propriedade”css(propriedade, valor): define o valor de “propriedade” como “valor”css(objeto): define diversos pares de “propriedade/valor”
Encontrando elementos ancestrais
Imagine que você está definindo um tratador de evento sobre um link. Esse link está dentro de uma célula de tabela (td), que por sua vez está dentro de uma linha de tabela (tr). No contexto do tratamento desse evento, seu objeto atual, associado à variável this, é esse link. Nesse momento você percebe que precisa, por algum motivo, do id da linha onde está link (isso acontece bastante comigo). Para esses casos utilize a função parents, que retorna todos os ancentrais do elementos do objeto jQuery atual.
$('a#do_something').click(function(e) {
var rowId = $(this).parents('tr:first').attr('id');
});
Como parents retorna todos os ancestrais, passamos à função um seletor jQuery, indicando que queremos apenas a primeira linha. Simples, rápido e indolor.
Encontrando elementos filhos
Já vimos como encontrar ancestrais. Quando você quer fazer o caminho inverso, é só utilizar a função find. Por exemplo, imagine que você está processando a submissão de um formulário e precisa encontrar vários campos desse formulário, para validá-los. Se eles não possuem id’s associados, o find será uma mão na roda.
$('form#authentication').submit(function(e) {
e.preventDefault();
var username = $(this).find('input[name=username]').val();
var password = $(this).find('input[name=password]').val();
});
Valores de elementos
Utilize a função val para descobrir o conteúdo de determinados elementos (como o conteúdo de uma caixa de texto, por exemplo):
$('#username').val();
Funções semelhantes são text e html.
Realizando tarefas de acordo com o navegador do usuário
Como avisar ao seu usuário que você, por exemplo, está utilizando uma biblioteca baseada no elemento canvas, e que a experiência desse usuário no Internet Explorer não será tão boa (baixa performance)? Verifique que navegador ele está utilizando:
if ($.browser.msie) {
alert('Experimente o Firefox!');
}
Você pode realizar testes para outros navegadores também, é claro. Dê uma olhada na documentação dos utilitários da biblioteca.
Inserindo elementos no documento
Volta e meia crio pequenos frameworks baseados em classes de elementos, de forma a evitar a repetição de código HTML. Nesses casos sempre é bom poder inserir código HTML arbitrário após a carga do documento. Eis como fazer isso com jQuery:
$('<p>Este parágrafo foi inserido dinamicamente!</p>').appendTo('body');
$('<p>Este parágrafo também foi inserido dinamicamente!</p>').prependTo('body');
Como podemos ver, quando a string enviada à função jQuery não é reconhecida como um seletor, ela é reconhecida como um elemento a ser criado (não sei se é exatamente essa a implementação interna, mas se você pensar assim não terá problemas para entender a diferença entre enviar uma string como seletor ou um novo elemento HTML).
As funções appendTo e prependTo são muito úteis nesses casos. Com elas você indica que quer inserir um elemento como último ou como primeiro filho do elemento passado como parâmetro.
Sendo honesto: muitas vezes preciso inserir muito mais HTML do que uma linhazinha dessas. Em situações reais já precisei inserir grandes trechos de formulário, por exemplo. Não tenha medo: insira uma contra-barra ao fim de cada linha e prolongue sua string HTML por diversas linhas:
$('<p class="input_row"> \
<input id="username" type="text" /> \
</p> \
...'
)
.prependTo($('form#auth'));
Criando um cache
Quando você precisa fazer 2 operações diferentes utilizando o mesmo seletor, mas em pontos diferentes do código, é interessante atribuir o objeto jQuery que contém o resultado da consulta a uma variável, para evitar o custo de processamento de uma nova consulta.
Portanto, isto não é legal:
$('a.special').click(function() {
//
});
// muitas linhas depois...
$('a.special').hover(function() {
//
});
Isto é legal:
var $specialLinks = $('a.special');
$specialLinks.click(function() {
//
});
// muitas linhas depois...
$specialLinks.hover(function() {
//
});
Note que utilizei um cifrão como prefixo para a variável $specialLinks. Considero isso uma boa prática dentro de código JS que utilize jQuery, pois deixa bem claro quais variáveis são objetos jQuery e quais não são. Se você for estudar o código de plugins é provável que encontre essa mesma convenção sendo seguida.
Encadeando funções
Como disse anteriormente, toda função jQuery que você invoca a partir de um objeto jQuery retorna o próprio objeto jQuery. Isso significa que em vez de fazer isto:
var $newP = $('<p class="warning"></p>');
$newP.css('width', '100%');
$newP.appendTo('body');
Você pode fazer isto:
$('<p class="warning"></p>')
.css('width', '100%')
.appendTo('body');
Sim, você pode encadear quantas chamadas quiser.
Em inglês o termo para esse encadeamento de chamadas é chaining. Quando vi o código disposto dessa forma pela primeira vez não gostei nenhum pouco, pensei: “nunca vou fazer isso!”. Mas hoje, se você abrir meus arquivos JS verá encadeamento de chamadas por todo lado. Acho que isso vicia, simplesmente.
Se você for utilizar aquele parágrafo em algum outro ponto do código, crie um cache para ele no momento da criação:
var $warningP = $('<p class="warning"></p>')
.css('width', '100%')
.appendTo('body');
Utilizando plugins
Sem plugins o jQuery já teria sido uma grande idéia, mas com a possibilidade de definir novas funções para o objeto jQuery, fica difícil reclamar dessa biblioteca. Em geral um plugin jQuery tem um nome bastante sugestivo (como tablesorter), e o nome dele indica exatamente qual o nome da função que corresponde ao plugin.
Para utilizar qualquer plugin jQuery basta incluir no seu cabeçalho HTML uma referência (tag <script>) ao código-fonte do plugin após ter referenciado o código-fonte do jQuery. Digamos que estejamos utilizando o plugin tablesorter, capaz de dar à tabelas HTML poderes de ordenação de colunas. Eu utilizaria o plugin da seguinte forma:
// primeiro verifique se o plugin foi carregado
if ($.fn.tablesorter) {
$('table.record_list').tablesorter();
}
Com o código acima aplicamos o comportamento oferecido pelo plugin a todas as tabelas de classe record_list do documento.
Note que a grande maioria dos plugins opta pela simplicidade: eles funcionam sem que você passe parâmetros para a função principal. Se você precisar passar parâmetros, em geral você irá passar um objeto literal, o qual sobrescreverá as opções padrão do plugin.
jQuery e Firebug
Dentro de um projeto que utiliza o jQuery, tire o máximo de proveito da biblioteca. Se aquele seletor jQuery que você escreveu não está funcionando, copie e cole o código no console do Firebug e veja a resposta. Se a resposta do console for simplesmente um array vazio, quer dizer que seu seletor não casou com nenhum elemento. Caso contrário, você verá uma representação dos elementos que casaram.
Além de fazer consultas no documento, gosto de manipular os elementos que encontro via Firebug. Por exemplo:
$('p.warning:first').css('background-color', 'red');
Acho mais fácil que utilizar o editor de CSS embutido no Firebug.
Um exemplo completo
Nosso documento contém uma tabela com a classe record_list, a qual está envolvida por uma div#table_panel. Após o carregamento da página, vamos adicionar um link abaixo dessa tabela. Esse link, quando clicado, adiciona uma nova linha à tabela. Este exemplo sozinho não serve para nada, mas utilizei a mesma idéia aqui no meu projeto para criar uma tabela que exibia todas as curvas de um gráfico. Para adicionar mais uma curva ao gráfico, eu utilizava essa mesma abordagem: primeiro adicionava a nova linha, e em seguida gerava o gráfico novamente, via Ajax.
$(document).ready(function() {
$('<a href="#" id="create_new_line">Criar nova linha</a>')
.click(function(e) {
e.preventDefault();
$('<tr> \
<td>...</td> \
<td>...</td> \
<td>...</td> \
</tr>'
)
.appendTo('table.record_list:first');
})
.appendTo('#table_panel');
});
Comments
Tell me what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!
