Um seletor pode ser composto de uma ou mais classes, atributos ou expressões e sua chamada retorna um conjunto de objetos que atendem suas regras.
[cce lang=”javascript”]
No entanto, em momentos bem específicos, para evitar a repetição de código, pode ser necessário desenvolver o seu próprio seletor.
As propriedades de um seletor
O cabeçalho básico de um seletor personalizado segue o modelo abaixo:
[cce lang=”javascript”]
$.expr[‘:’].seletor = function(objNode, intStackIndex, arrProperties, arrNodeStack){
// código que deve retornar true para incluir o objeto ou false
};
[/cce]
Através da alta flexibilidade do jQuery estamos estendendo o funcionamento da expressão “:” adicionando uma função própria, desenvolvida sob medida para nosso site ou aplicação web.
Um seletor personalizado nada mais é do que uma função que retorna true para incluir o elemento na lista ou false para não incluí-lo. Essa função pode receber até quatro parâmetros:
- objNode – o objeto atual (referente ao elemento no DOM, ou seja, NÃO é um clone);
- intStackIndex – o índice do objeto no conjunto de elementos do seletor. Vamos supor que nosso seletor busque ítens (
- ) de uma lista (
- ). O primeiro ítem da lista terá o índice 0, o segundo o índice 1 e por aí vai;
-
arrProperties – esse parâmetro contém informações sobre nosso objeto atual no seletor. Só lidaremos mesmo com a posição 3, que representa o parâmetro passado no seletor, mas vejamos o que cada um representa:
[cce lang=”javascript”]meta = [
‘:seletor(argumento)’, // o seletor completo
‘seletor’, // apenas o seletor
”, // aspas utilizadas nos parâmetros
‘argumento’ // parâmetros
][/cce] - arrNodeStack – o array completo, com todos os objetos capturados pelo nosso seletor.
Nosso primeiro seletor
Hora de colocar a mão na massa. Vamos começar com um seletor bem simples que buscará todos os links da nossa aplicação que possuam “#” como atributo href:
[cce lang=”javascript”]$.expr[‘:’].sem_link = function(obj){
return ($(obj).attr(‘href’) == “#”);
};[/cce]
Reparem que só utilizamos o primeiro parâmetro: o próprio objeto. A função compara o atributo href do elemento com o link “#” e automaticamente retorna true ou false. Como exemplo de uso do nosso seletor vamos fazer com que todos os links com a tralha no href percam sua ação padrão:
[cce lang=”javascript”]$(‘a:sem_link’).click(function(e){
e.preventDefault();
});[/cce]
É claro que a mesma coisa poderia ter sido obtido com o seguinte seletor nativo:
[cce lang=”javascript”]$(‘a[href=”#”]’).click(function(e){
e.preventDefault();
});[/cce]
Esse é o grande lance dos seletores personalizados: saber a hora de usá-los. Dificilmente uma expressão ou um seletor já existente não vai atender à sua necessidade. O que você precisa pesar é se o seletor novo vai facilitar a implementação e manutenção do seu código jQuery. O seletor :sem_link, por exemplo, poderia retornar true também para elementos com o href “javascript:;” ou vazio.
Seletores com parâmetros
Seguindo a onda das tabelas vamos utilizar como exemplo para nossos próximos seletores uma tabela com os principais jogadores do Mengão. O código completo você encontra lá no GitHub.
[cce lang=”html”]
…
…
…
[/cce]
Nosso objetivo é criar um set de seletores para marcar dados específicos na tabela: jogadores em atividade, jogadores com x ou mais gols, jogadores com x ou mais jogos e jogadores de uma posição específica.
Para selecionar apenas os jogadores em atividade apenas precisamos verificar se o atributo atividade nos dados do elemento (data-atividade, ou $(‘.jogador’).data(‘atividade’)) é verdadeiro.
[cce lang=”javascript”]$.expr[‘:’].em_atividade = function(obj){
return $(obj).data(‘atividade’);
};[/cce]
Já para os próximos filtros precisamos passar um parâmetro: um valor mínimo para a quantidade de gols e jogos ou a posição desejada. Lembra quando falamos lá em cima sobre o array de propriedades dos seletores, mais especificamenteo seu terceiro parâmetro? Ele é a nossa chave para seletores com parâmetros.
[cce lang=”javascript”]$.expr[‘:’].posicao = function(obj, index, meta, stack){
if($(obj).find(‘td:last’).text() == meta[3]) return true;
else return false;
};
$(‘.jogador:posicao(“Goleiro”)’).addClass(‘selected’);
$.expr[‘:’].gols = function(obj, index, meta, stack){
var gols = parseInt($(obj).find(‘td:eq(3)’).text());
if(gols >= meta[3]) return true;
else return false;
};
$(‘.jogador:gols(43)’).addClass(‘selected’);
$.expr[‘:’].jogos = function(obj, index, meta, stack){
var jogos = parseInt($(obj).find(‘td:eq(2)’).text());
if(jogos >= meta[3]) return true;
else return false;
};
$(‘.jogador:jogos(137)’).addClass(‘selected’);[/cce]
No filtro por posições, comparamos o conteúdo da última célula da linha ($(‘td:last’)), que armazena a posição do jogador, com o conteúdo passado como parâmetro (“Goleiro”).
Os filtros de gols e jogos utilizam um outro seletor especial, o :eq. Ele representa a posição do elemento no array de objetos do seletor. Por exemplo, $(‘tr td:eq(2)’) localiza a terceira célula de uma linha (começa em 0!).
Legal, né? As possibilidades realmente são infinitas e a flexibilidade do jQuery impressiona. Mas, assim como os plugins, lembre-se que nem sempre um seletor personalizado vai ser a melhor solução.
Clique aqui para fazer o download do exemplo ou aqui para visualizar o exemplo no navegador.