Skip to content

Instantly share code, notes, and snippets.

@AgtLucas AgtLucas/gist:5423042
Last active Dec 16, 2015

Embed
What would you like to do?
// jQuery Avançado
// Principais design patterns utilizados:
// * Facade Pattern (principalmente para contornar diferença de browsers).
// * Factory Pattern (para gerar objetos baseados em um "template" do construtor principal).
// 1. Preparando o uso da biblioteca.
// Para garantir um bloco de código jQuery seja executado, é recomendado envolvê-lo
// em um dos blocos iniciadores abaixo.
// Isso garante que além da biblioteca, todo o DOM* esteja carregado antes de sua manipulação.
// NOTA #1:
// DOM ou Document Object Model, nada mais é do que uma representação hierárquica dos elementos
// HTML no contexto da linguagem Javascript através de uma interface de manipulação.
// Quando um programador faz qualquer interação com um elemento da página dinamicamente,
// ele está utilizando o DOM.
// 1.1 Formas de inicialização.
// Repare que para cada forma de inicialização, uma função é passada como argumento.
// Isso em JavaScript é o equivalente a um callback (um método ou função executado em alguma ocasião
// que forneça ao programador o poder de intervir e injetar novos comportamentos no contexto da chamada,
// da função 'pai'.
// Em partes, os modelos a seguir estarão descritos.
$(function() { /*Bloco de código em jQuery*/ });
// Onde:
// * $ é um construtor que aceita diversos tipos de entrada. Incluindo uma função.
// * function() {} é uma função anônima executada no disparo do evento "ready".
// * O bloco dessa função representa o código que o programador vai usar com o jQuery.
// * Internamente, jQuery interpreta essa entrada de dados e direciona para o método .ready onde o seletor é o document.
// O que cai no modelo abaixo.
// O modelo abaixo faz exatamente o mesmo que o primeiro, sua única diferença é ser mais fácil do programador compreender.
$(document).ready(function() { /*Bloco de código em jQuery*/ });
// 1.2 Evitando conflitos.
// Muitas outras bibliotecas utilizam o mesmo "$" que o jQuery em suas chamadas e isso pode acarretar em um conflito.
// Existem diversas formas de se resolver isso, mas existe também uma forma que o próprio jQuery implementa.
$.noConflict();
// A partir daqui é possível utilizar "jQuery" no lugar de "$". Ou ainda:
var jQ = $.noConflict();
// E assim utilizar "jQ" no lugar de "jQuery".
// 2. Manipulando o DOM
// o jQuery fornece diversas formas de interagir com a árvore DOM. Entre essas:
// I. Para criar um novo elemento:
var div = $("<div/>");
// II. Para inserir um elemento em um nó:
// Dentro de um nó, no final.
div.appendTo(document.body);
// Ou
$("<div/>").appendTo(document.body); // appendTo insere elementoA dentro elementoB, no final.
// Dentro um elemento, no começo.
$("<div/>").prependTo(document.body); // prependTo insere elementoA dentro elementoB, no começo.
// No mesmo nível hierárquico, antes.
var div = $("<div/>");
div.append( // Insere elementoB dentro de elementoA, no final.
$("<span/>").html("Eu estou dentro da div").before( // Insere "span" de imediato dentro de "div".
$("<span/>").html("Eu e ainda antes do outro span") // Insere "span" antes de "span" anterior.
)
);
// No mesmo nível hierárquico, depois.
div.append(
$("<span/>").html("Eu estou dentro da div").after( // Insere "span" de imediato dentro de "div".
$("<span/>").html("Eu e ainda antes do outro span") // Insere "span" depois de"span". (Epa! Não é o mesmo que fazer dois append na div?!)
)
);
// Complicado de entender a sintáxe? Imagina=e isso inline!
// III. Para atribuir valores ao elemento:
// a. Em CSS (atributo style):
div.css({
border: "1px solid black",
marginTop: "-1em" // ou "margin-top": "-1em"
});
// Ou
div.css("border", "1px solid green");
// b. Em atributo e propriedade:
$("<input/>").attr("type", "checkbox").prop("checked", true);
// IV. Para buscar um elemento
// A busca de um elemento pode ser feita tanto pelos seletores quanto por métodos, mas isso nos leva a um macete.
// * Para todo e qualquer acesso ao DOM, este deve ser evitado quando pode ser evitado.
// O que isso significa? Que o ideal é sempre armazenar em cache um elemento que vá ser utilizado diversas vezes.
// O jQuery implementa isso internamente MAS SE utilizar uma busca por métodos.
// Analise o caso:
// a. Vamos supor que queremos buscar o último elemento "li" dentro de um "ul".
// Da forma NÃO recomendada:
$("ul li:last"); // Busca do descendente direto "li" que esteja na última posição.
// E a forma recomendada (cache interno):
$("ul").children("li:last");
// Isso não explica muita coisa. Então, vamos ao teardown:
// Cada vez que o construtor é chamado, onde uma seletor CSS é passado, uma busca na árvore DOM é feita.
// No segundo caso, uma busca pelo ul é realizada, para então buscar o elemento "li" a partir do resultado em cache gerado pelo construtor.
// Além disso, o jQuery também implementa uma série de algoritmos que agilizam a busca se em comparação com o a forma nativa que os navegadores utilizam para
// interpretar um seletor.
// Pra finalizar essa parte. Segue os métodos de busca mais comuns:
$(seletor).children(filho); // Busca elemento filho dentro de pai.
$(seletor).parent(filho); // Busca elemento pai em que o filho está.
$(seletor).next(vizinho); // Busca elemento com nível hierárquico equivalente, mas antes dos elementos do seletor.
$(seletor).prev(vizinho); // Busca elemento com nível hierárquico equivalente, mas antes dos elementos do seletor.
$(seletor).prevAll(vizinho); // Busca todos os elementos que estejam antes do seletor no mesmo nível hierárquico.
$(seletor).nextAll(vizinho); // Busca todos os elementos que estejam depois do seletor no mesmo nível hierárquico.
$(seletor).prevUntil(criterio); // Busca todos os elementos que estejam antes do seletor no mesmo nível hierárquico que não equivale critério.
$(seletor).nextAll(criterio); // Busca todos os elementos que estejam depois do seletor no mesmo nível hierárquico que não equivale ao critério.
$(seletor).find(filho); // Realiza uma busca profunda na árvore para encontrar o filho. A partir do pai que seria o seletor.
$(seletor).closest(criterio); // Busca e retorno o primeiro elemento a conferir com o criterio. A partir do pai.
$(seletor).siblings(criterio); // Busca todos os vizinhos que estejam no mesmo nível hierárquico que o seletor e conferem com o criterio (retorna todos se criterio nulo).
// Existem outros ainda mais específicos que por hora não precisam ser abordados.
// V. Interagindo em cada elemento jQuery
// Para cada seletor, se seguido por um método que altere o comportamento. Esse é aplicado para todos os resultados do seletor.
// Mas e se esse método não for exatamente o que buscamos? Para isso existe o $(seletor).each.
// Repare agora:
$("li").each(indice, function() { // Para cada li encontrado.
if (this.innerHTML === "Vermelho") { // Se este tiver "Vermelho" como conteúdo.
$(this).css("color", "red"); // Este vai ser vermelho.
}
});
// Esse resultado não seria possível sem o uso do .each. Por ter condições ou critérios que simplesmente não foram implementados pelo jQuery.
// 3. Adição de eventos.
// O jQuery suporta adição de eventos a não um mas muitos seletores de uma vez. Graças ao poder expressivo deles.
// Tenha um seletor cujo critério "a" confere com n elementos, para esses o evento vai ser atribuído. Veja:
$("ul").find("li").on("click", function() {
alert(this.id || this.name || this.nodeType); // Tenta mostrar id, se falhar tenta buscar name e se falhar de novo mostra qual a tag.
});
// Ótimo, funciona! Mas e se o programador se encontrar em uma situação cujo 1000 elementos filhos do mesmo tipo são inseridos e removidos dinâmicamente?
// É impossível manter um controle tão grande de forma eficiente. E por isso o jQuery da suporte a uma técnica chamada "Delegação de Eventos".
// Nessa técnica, apenas uma atribuição de evento é passada, e essa atribuição vai diretamente para o pai.
// Pela natureza padrão dos eventos no DOM, estes explodem até chegar no pai. Isso é chamado de event bubbling.
// Ainda existe outra expressão conheciada como "event propagation", que apesar de similar ao "event bubbling", este inclui a captura do evento. Não confunda.
// Essa reação em cadeia é muitas vezes indesejada pelo webdeveloper, mas no caso da delegação ela é bem vinda.
// Veja sua aplicação no caso anterior:
$("ul").on("click", "li", function() {
alert(this.id || this.name || this.nodeType); // Mesmo resultado anterior. Mas como?
});
// Repare que agora o evento está no pai, e temos a adição de um terceiro argumento no método .on.
// De forma explicita, isso significa:
// "Atribua um evento de click no elemento ul. Mas observe o comportamento do objeto de evento do ul, que caso o alvo do click for um "li",
// dispare a função do evento".
// Em JavaScript puro:
document.querySelector("ul").addEventListener("click", function(e) {
if (e.target &&& e.target.nodeName === "li") {
// Bloco de execução.
}
});
// 4. Métodos não prototipados.
// I. A diferença entre $(seletor).each e $.each.
// Como foi visto. O primeiro caso, se aplica exclusivamente para objetos encapsulados pela biblioteca.
// Para outros casos, o jQuery fornece um método de contexto global e independente de seletores.
// Veja abaixo:
var obj = { x: 1, y: 2, z: 3 }; // Criamos um objeto.
// E agora vamos percorrer ele com o $.each. Dessa forma:
$.each(obj, function(chave, valor) {
if (chave === "x" || valor === 1) {
alert("1 pode ser um valor boolean");
}
});
// Como visto, é o mesmo resultado que $(seletor).each, porém para objetos que não pertençam a coleção do jQuery.
// II. AJAX
// Toda e qualquer chamada AJAX é feita através de $.ajax internamente. Mesmo que utilize uma de suas variações.
// Por uma chamada AJAX ser algo assíncrono. Não é possível retornar um valor de sua chamada. Isto é, sem utilizar $.deferred ou um callback.
// $.deferred no jQuery se refere a uma técnica chamada Promises.
// Uma Promise é um objeto que tem a função de definir um comportamento ao ter seu critério cumprido.
// Dessa forma é possível definir medidas ao: obter sucesso, estar em progresso ou falhar sem que seus comportamentos sejam comprometidos ou sobrepostos.
// Tendo o caso:
$.ajax({
url: "test.html",
context: document.body, // URL de onde será feita a requisição
}).done(function() { // Completou? Então adiciona a classe.
$(this).addClass("done"); // Onde this é uma referência para o valor de context.
});
// Ou ainda:
$.ajax({
url: "test.html", //
success: function(data) {
alert(data);
}
});
// III. Compatibilidade de recursos
// Todo webdeveloper precisa ter em mente que testar um browser pelo seu tipo não é efetivo e pode ser burlado.
// Para isso utiliza-se outra técnica chamada detecção de funcionalidade.
// Os browsers em suas diversas versões tem recursos tanto adicionados e quanto removidos.
// A Detecção de Funcionalidade contorna esse problema indo diretamente ao ponto de interesse: "Tem suporte a recurso X?"
// Como não poderia faltar. O jQuery implementa uma forma prática de testar se um recurso existe.
// Através do:
$.support;
// Esse objeto é utilizado internamente pela biblioteca ao fim de testar os recursos e causar fallbacks se necessários.
// Ele é composto por um grupo de propriedades cujo seus valores são na maior parte das vezes true ou false.
// Por ex:
$.support.leadingWhitespace; // True no Mozilla, Chrome, Safari e false no IE.
// IV. Extendendo um objeto.
// Dado um objeto A, seja ele independente do jQuery ou não, é possível copiar conteúdo do objeto B para A.
// Isso é feito pelo método abaixo:
var objB = {
foo: function() {
alert("bar!");
}
};
$.extend($, objB);
$.foo(); // bar!
// No caso abaixo:
$.extend($, objB, objC); // Mescla o conteúdo de objC com objB para então adicionar ao $.
// E se:
$.extend(true, $, objB); // Realiza uma cópia profunda de forma recursiva.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.