DevTools

Cheatsheet jQuery

Biblioteca JavaScript para manipulação DOM

Volver a los lenguajes
jQuery
112 tarjetas encontradas
Categorías:
Versiones:

Seletores


12 cards
Documento listo
// Forma completa:
$(document).ready(function() {
  // DOM cargado y seguro
});

// Forma corta (recomendada):
$(function() {
  // equivalente a ready
});

// Múltiples ready (todos se ejecutan):
$(function() { console.log("módulo A"); });
$(function() { console.log("módulo B"); });

Garantiza que el DOM está totalmente parseado antes de ejecutar código. La forma corta $(fn) es idéntica a $(document).ready(). Múltiples handlers se ejecutan en orden de registro. A diferencia de window.onload, no espera imágenes/CSS.

Filtros de posición
$("li:first")     // primer li de la página
$("li:last")      // último li
$("li:eq(2)")     // índice 2 (tercero)
$("li:gt(3)")     // índice mayor que 3
$("li:lt(3)")     // índice menor que 3
$("li:even")      // índices pares (0, 2, 4...)
$("li:odd")       // índices impares (1, 3, 5...)

// Equivalente con método (más rápido):
$("li").first()
$("li").last()
$("li").eq(2)

Los pseudo-selectores de posición filtran por el índice en la colección. :eq(n) es zero-based. Las versiones método (.first(), .eq()) son más rápidas que los pseudo-selectores porque filtran después de la selección CSS. :even/:odd útiles para hacer zebra en tablas.

find() y filter()
// find(): búsqueda DENTRO de los seleccionados
$("ul").find("li.activo")    // li dentro de ul
$("#form").find("input")    // inputs dentro del form

// filter(): reduce la selección actual
$("li").filter(".activo")    // solo los que tienen la class
$("li").filter(function(i) {
  return $(this).data("tipo") === "especial";
});

// Diferencia:
$("div").find("p")   // p DENTRO de div
$("div").filter("p") // divs que TAMBIÉN son p (nada)

find() búsqueda descendientes de los elementos seleccionados. filter() reduce la colección actual por selector o función. find() desciende en el árbol; filter() evalúa los propios elementos. Ambos aceptan una función callback para lógica compleja.

Selector de elemento
$("p")       // todos los párrafos
$("div")     // todas las divs
$("li")      // todos los ítems de lista
$("h1, h2")  // múltiples tipos (coma = O)

// Retorna un objeto jQuery (array-like):
var paragrafos = $("p");
paragrafos.length;  // cantidad encontrada
paragrafos[0];      // primer elemento DOM (raw)

Selecciona todos los elementos del tipo indicado. Retorna un objeto jQuery (colección), no un elemento DOM. La propiedad .length indica cuántos encontró. Acceder a [0] retorna el elemento nativo (sin métodos jQuery).

Filtros de estado
$(":button")       // todos los botones
$(":checkbox")     // checkboxes
$(":radio")        // radio buttons
$(":checked")      // marcados (checkbox/radio)
$(":selected")     // option seleccionada
$(":disabled")     // campos desactivados
$(":enabled")      // campos activos
$(":focus")        // elemento con foco
$(":hidden")       // invisibles (display:none)
$(":visible")      // visibles

Los filtros de estado seleccionan por la condición actual del elemento. :checked y :selected cambian según la interacción del usuario. :hidden incluye display:none, visibility:hidden y elementos con ancho/alto cero. Se reevalúan en cada llamada (no usar en loops).

Contexto y ámbito
// Segundo parámetro = contexto (limita la búsqueda):
$("li", document.getElementById("menu"))
// equivalente a:
$("#menu").find("li")

// this dentro de handlers:
$(".btn").click(function() {
  $(this)          // elemento clicado (jQuery)
  this             // elemento clicado (DOM raw)
  this.textContent // sin jQuery
});

// each() con contexto:
$("li").each(function() {
  $(this).addClass("visto");  // cada li
});

El segundo parámetro de $() limita el contexto de la búsqueda (más rápido en sub-árboles). Dentro de handlers, this refiere al elemento DOM nativo; $(this) lo envuelve en jQuery para usar métodos. En .each(), this cambia en cada iteración. Las arrow functions pierden el this — usar function().

Clase e ID
$(".menu")       // class="menu"
$("#encabezado")       // id="encabezado"
$(".card.activo") // card Y activo (ambas)
$("div.caja")   // div con class="caja"

// El ID es más rápido (usa getElementById):
$("#unico")      // muy rápido
$(".muitos")     // usa querySelectorAll

El punto (.) selecciona por class, la almohadilla (#) por id. Combinar como en CSS: .card.activo exige ambas clases. Los IDs son más performantes porque usan el getElementById nativo. Las clases usan querySelectorAll internamente.

Selector de atributo
$("[href]")              // tiene atributo href
$("[type='text']")       // type exacto
$("[href^='https']")     // empieza con
$("[href$='.pdf']")      // termina con
$("[class*='btn']")      // contiene substring
$("[data-id]")           // tiene data-attribute
$("input[name='email']") // input con name

// Combinar:
$("a[target='_blank'][rel='noopener']")

Los corchetes [] filtran por atributo. ^= prefijo, $= sufijo, *= contiene, = exacto. Combinables entre sí y con otros selectores. Útiles para data-attributes personalizados. Más lentos que clase/ID — preferir esos cuando sea posible.

Selectores personalizados
// jQuery añade selectores no-CSS:
$(":input")     // input, textarea, select, button
$(":text")      // input[type=text]
$(":password")  // input[type=password]
$(":file")      // input[type=file]
$(":image")     // input[type=image]
$(":submit")    // input/button submit
$(":reset")     // input/button reset
$(":header")    // h1, h2, h3, h4, h5, h6
$(":animated")  // elementos en animación
$(":button")    // button e input[type=button]

El selector :input y sus derivados son exclusivos de jQuery (no existen en CSS). :input selecciona todos los campos de formulario de una vez. :header selecciona todos los headings. :animated detecta elementos con animación activa. Útiles pero más lentos — usar con moderación.

Selectores combinados
$("ul li")       // descendiente (cualquier nivel)
$("ul > li")     // hijo directo (solo 1 nivel)
$("h2 + p")      // hermano siguiente (adyacente)
$("h2 ~ p")      // todos los hermanos p siguientes

// Ejemplo práctico:
$("nav > ul > li > a")  // enlaces directos en el menú

Espacio = descendiente (cualquier profundidad). > = hijo directo. + = hermano inmediatamente siguiente. ~ = todos los hermanos siguientes del mismo tipo. Cuanto más específico, más rápida la selección.

Selector de contenido
$("p:contains('error')")   // el texto contiene "error"
$("td:empty")             // celdas vacías
$("div:has(img)")         // divs que contienen img
$("p:parent")             // elementos con hijos

// :has() es poderoso:
$("li:has(> a.activo)")   // li con enlace activo directo
$("form:has(input:visible)") // forms con campos visibles

:contains() filtra por texto (case-sensitive). :has() selecciona los padres que contienen un determinado hijo — muy versátil. :empty no tiene hijos ni texto. :parent es lo opuesto de :empty. Estos son selectores jQuery (no CSS nativo), por lo tanto más lentos.

Performance de selectores
// RÁPIDO → LENTO:
$("#id")              // 1. getElementById
$(".clase")          // 2. getElementsByClassName
$("div.clase")       // 3. tag + clase
$("[data-x]")         // 4. atributo
$("div:visible")      // 5. pseudo-selector

// Consejos de performance:
var $lista = $("#lista");       // cache!
$lista.find("li.activo");        // contexto
$lista.children(".item");       // hijos directos

// Evitar:
$("div .item")          // demasiado genérico
$("*")                  // todos los elementos
$("li:eq(0):visible")   // múltiples filtros

El orden de performance: #id > .clase > tag.clase > [attr] > :pseudo. Hacer cache de selecciones repetidas en variables (prefijo $ por convención). Usar .find() con contexto en vez de selectores anchos. Evitar $("*") y pseudo-selectores encadenados.

Eventos


11 cards
on() — vinculación de eventos
// Método recomendado (jQuery 1.7+):
$("#btn").on("click", function() {
  alert("clicado!");
});

// Múltiples eventos:
$("#campo").on("focus blur", function() {
  $(this).toggleClass("activo");
});

// Objeto de eventos:
$("#form").on({
  submit: function(e) { e.preventDefault(); },
  reset: function() { limpiar(); }
});

on() es el método universal de eventos (sustituye a bind(), live(), delegate()). Acepta un string con eventos separados por espacio o un objeto. El handler recibe el objeto event con los detalles. Siempre preferir on() sobre atajos como .click().

Eventos de teclado
$("input").on("keydown", function(e) {
  console.log(e.key);       // "a", "Enter", "Escape"
  console.log(e.code);      // "KeyA", "Enter"
  console.log(e.which);     // código numérico

  // Detectar teclas especiales:
  if (e.key === "Enter") { enviar(); }
  if (e.key === "Escape") { cerrar(); }
  if (e.ctrlKey && e.key === "s") {
    e.preventDefault();
    guardar();
  }
});

// keypress (solo caracteres imprimibles):
$("input").on("keypress", fn);

keydown dispara al pulsar cualquier tecla (incluidas las especiales). e.key da el valor legible, e.code la tecla física. e.ctrlKey, e.shiftKey, e.altKey detectan modificadores. keypress está deprecated — usar keydown. preventDefault() cancela la acción nativa (ej: Ctrl+S).

trigger() — disparar eventos
// Disparar un evento programáticamente:
$("#btn").trigger("click");
$("#form").trigger("submit");

// Forma corta:
$("#btn").click();     // dispara click
$("#form").submit();   // dispara submit

// Con datos extra:
$("#btn").trigger("click", ["extra1", "extra2"]);

// El handler recibe:
$("#btn").on("click", function(e, extra1, extra2) {
  console.log(extra1); // "extra1"
});

// Evento custom:
$("#app").trigger("datos:carregados", [datos]);
$("#app").on("datos:carregados", function(e, datos) {
  renderizar(datos);
});

trigger() dispara eventos programáticamente (como si el usuario hiciera clic). Acepta datos extra como array en el segundo parámetro. Los eventos custom (con namespace) crean comunicación entre módulos. La forma corta .click() sin argumentos dispara el evento. Útil para tests y coordinación de componentes.

off() — quitar eventos
// Quitar todos los clicks:
$("#btn").off("click");

// Quitar TODOS los eventos:
$("#btn").off();

// Handler específico (función nombrada):
function handler() { console.log("oi"); }
$("#btn").on("click", handler);
$("#btn").off("click", handler);

// Namespaces:
$("#btn").on("click.app", fn1);
$("#btn").on("click.modal", fn2);
$("#btn").off("click.app");  // solo quita fn1

off() quita handlers previamente vinculados con on(). Sin argumentos quita todo. Los Namespaces (.app, .modal) permiten quitar grupos específicos sin afectar a otros. Esencial para evitar memory leaks al destruir componentes. Las funciones anónimas no pueden quitarse selectivamente.

Eventos de formulario
$("form").on("submit", function(e) {
  e.preventDefault();
  var datos = $(this).serialize();
  // enviar vía AJAX
});

$("input").on("change", function() {
  // el valor cambió Y perdió el foco
  console.log($(this).val());
});

$("input").on("input", function() {
  // dispara en CADA tecla (tiempo real)
  filtrar($(this).val());
});

$("select").on("change", function() {
  cargar($(this).val());
});

submit intercepta el envío del formulario. change dispara cuando el valor cambia y el campo pierde el foco. input dispara en cada tecla (ideal para búsqueda en tiempo real). serialize() convierte el form en una query string. Siempre preventDefault() en el submit para evitar la recarga de la página.

Event object
$("#caja").on("click", function(event) {
  event.type;        // "click"
  event.target;      // elemento clicado (DOM)
  event.currentTarget; // elemento con el handler (= this)
  event.pageX;       // posición X (documento)
  event.pageY;       // posición Y (documento)
  event.timeStamp;   // cuándo ocurrió

  // Qué botón del ratón:
  event.which;       // 1=izq, 2=medio, 3=der

  // Teclas modificadoras:
  event.ctrlKey;     // Ctrl pulsado?
  event.shiftKey;    // Shift pulsado?
  event.altKey;      // Alt pulsado?
  event.metaKey;     // Cmd (Mac) pulsado?
});

El objeto event contiene todos los detalles de la interacción. target es quien lo originó; currentTarget es quien tiene el handler. pageX/pageY para la posición del ratón. which identifica el botón del ratón o la tecla. Propiedades booleanas (ctrlKey, shiftKey) para combinaciones. Normalizado por jQuery (cross-browser).

Delegación de eventos
// Evento en el PADRE, filtro en el selector hijo:
$("#lista").on("click", "li", function() {
  $(this).toggleClass("hecho");
});

// Funciona con elementos futuros:
$("#lista").append("<li>Nuevo</li>");
// el clic en el nuevo li funciona automáticamente!

// Sin delegación (NO funciona con dinámicos):
$("li").on("click", fn);  // solo los existentes

// Múltiples selectores:
$("#tabla").on("click", "td, th", fn);

Delegación: el evento se vincula al padre y filtra por el selector hijo. Funciona con elementos creados después de la vinculación. El evento "burbujea" del hijo hasta el padre. Más eficiente: 1 handler en el padre vs N handlers en los hijos. Esencial para listas dinámicas, tablas y contenido AJAX.

preventDefault y stopPropagation
$("a").on("click", function(e) {
  e.preventDefault();      // cancela la navegación
  // hacer algo custom (AJAX, modal...)
});

$(".dropdown").on("click", function(e) {
  e.stopPropagation();    // no cierra el menú padre
  $(this).toggleClass("open");
});

// return false = ambos:
$("a").on("click", function() {
  return false;  // preventDefault + stopPropagation
});

// Verificar si fue cancelado:
if (e.isDefaultPrevented()) { /* ... */ }

preventDefault() cancela la acción nativa (navegación, submit). stopPropagation() impide que el evento suba por el árbol DOM (bubbling). return false en un handler jQuery hace ambos. isDefaultPrevented() verifica si otro handler ya lo canceló. Usar con cuidado — stopPropagation puede romper la delegación.

ready vs load vs DOMContentLoaded
// DOM listo (sin imágenes/CSS):
$(function() {
  // manipular el DOM con seguridad
});

// Todo cargado (imágenes, CSS, fonts):
$(window).on("load", function() {
  // calcular dimensiones reales
  var altura = $("#hero img").height();
});

// Vanilla equivalente a ready:
document.addEventListener("DOMContentLoaded", fn);

// Script al final del body (alternativa):
// <script src="app.js"></script> antes de </body>

$(fn) / ready dispara cuando el HTML está parseado (no espera recursos). $(window).on("load") espera todo (imágenes, CSS, fonts). Para manipular el DOM, ready basta. Para dimensiones de imágenes, usar load. Los scripts al final del <body> hacen innecesario el ready (el DOM ya existe).

Eventos de ratón
$("#caja").on({
  mouseenter: function() { $(this).addClass("hover"); },
  mouseleave: function() { $(this).removeClass("hover"); },
  mousedown: function() { $(this).addClass("press"); },
  mouseup: function() { $(this).removeClass("press"); },
});

// hover() = mouseenter + mouseleave:
$("#caja").hover(
  function() { $(this).fadeIn(); },   // enter
  function() { $(this).fadeOut(); }   // leave
);

// Coordenadas del ratón:
$(document).on("mousemove", function(e) {
  console.log(e.pageX, e.pageY);
});

mouseenter/mouseleave no disparan en los hijos (a diferencia de mouseover/mouseout). hover() es un atajo para ambos. e.pageX/e.pageY dan coordenadas relativas al documento. mousedown/mouseup para efectos de presión. Usar delegación para elementos dinámicos.

one() — ejecutar una vez
$("#btn").one("click", function() {
  alert("Solo aparece UMA vez!");
});
// segundo clic: no pasa nada

// Útil para inicializaciones:
$("#app").one("scroll", function() {
  loadDataPesados();
});

// Con delegación:
$("#lista").one("click", "li", function() {
  $(this).addClass("primero-clic");
});
// Nota: one() con delegación dispara 1x POR elemento

one() vincula un handler que se auto-elimina tras la primera ejecución. Ideal para tutoriales, lazy loading e inicializaciones únicas. Con delegación, dispara una vez por elemento hijo (no globalmente). Equivalente a vincular con on() y llamar a off() dentro del handler.

Manipulação do DOM


12 cards
Crear elementos
// Crear con un HTML string:
var $item = $("<li>Nuevo item</li>");
var $card = $('<div class="card"><h3>Título</h3></div>');

// Con atributos:
var $link = $("<a>", {
  text: "Clic aqui",
  href: "/pagina",
  class: "btn btn-primary",
  target: "_blank"
});

// Crear e insertar:
$("#lista").append($item);
$("body").append($card);

Pasar HTML a $() crea elementos (no selecciona). El segundo parámetro (objeto) define atributos y propiedades. El elemento queda en memoria hasta que se inserta en el DOM. Las variables con prefijo $ indican objetos jQuery por convención. Crear fuera del DOM e insertar una sola vez es más performante.

html() y text()
// html(): lee/define el HTML interno
var contenido = $("#caja").html();
$("#caja").html("<strong>Negrita</strong>");

// text(): lee/define solo texto (sin tags)
var texto = $("#caja").text();
$("#caja").text("Sem <b>tags</b>");  // literal

// Diferencia:
// html("<b>oi</b>") → muestra "oi" en negrita
// text("<b>oi</b>") → muestra "<b>oi</b>" literal

// Seguridad: text() escapa automáticamente
$("#nombre").text(inputUtilizador);  // seguro (XSS)

html() trabaja con HTML (interpreta tags). text() trabaja con texto puro (escapa tags). Sin argumentos, leen; con argumento, definen. Usar text() para contenido del usuario (previene XSS). html() sustituye todo el contenido interno de una vez.

each() — iterar elementos
// Iterar sobre una colección jQuery:
$("li").each(function(índice, elemento) {
  $(elemento).text((índice + 1) + ". " + $(elemento).text());
});

// this = elemento actual:
$(".card").each(function() {
  var título = $(this).find("h3").text();
  $(this).attr("title", título);
});

// Parar la iteración:
$("li").each(function() {
  if ($(this).hasClass("stop")) return false;
  $(this).addClass("visto");
});

each() itera sobre cada elemento de la colección. this refiere al elemento DOM actual (envolver con $(this) para métodos jQuery). return false dentro del callback para la iteración (como break). El callback recibe (índice, elemento). No confundir con $.each() (para arrays/objetos).

append() y prepend()
// append(): inserta al FINAL (dentro)
$("#lista").append("<li>Último</li>");
$("#lista").append($("<li>").text("Outro"));

// prepend(): inserta al INICIO (dentro)
$("#lista").prepend("<li>Primero</li>");

// Múltiples a la vez:
$("#lista").append(
  "<li>A</li>",
  "<li>B</li>",
  "<li>C</li>"
);

// appendTo() (inverso):
$("<li>Fin</li>").appendTo("#lista");
$("<li>Encabezado</li>").prependTo("#lista");

append() inserta al final de los hijos; prepend() al inicio. Aceptan múltiples argumentos, strings HTML u objetos jQuery. appendTo()/prependTo() son la forma invertida (útil para chaining). Todos insertan dentro del elemento objetivo, como hijos.

clone()
// Clonar sin eventos:
var $copia = $("#card").clone();
$("#galeria").append($copia);

// Clonar CON eventos y handlers:
var $copia2 = $("#card").clone(true);

// Clonar con eventos + descendientes:
var $copia3 = $("#card").clone(true, true);

// Modificar el clone antes de insertar:
var $nuevo = $("#template").clone()
  .attr("id", "card-" + proximoId)
  .find(".título").text("Nuevo").end();
$("#lista").append($nuevo);

clone() duplica el elemento. Sin argumentos, no copia eventos. clone(true) copia los handlers del elemento; clone(true, true) copia también los de los descendientes. El clone es independiente — modificar uno no afecta al otro. Ideal para templates: clonar, personalizar e insertar.

map() — transformar colección
// Extraer valores:
var textos = $("li").map(function() {
  return $(this).text();
}).get();  // .get() convierte a un array real

// Transformar:
var ids = $(".card").map(function() {
  return $(this).data("id");
}).get();

// $.map() (para arrays/objetos):
var dobros = $.map([1, 2, 3], function(n) {
  return n * 2;
});  // [2, 4, 6]

// grep (filtrar un array):
var pares = $.grep([1,2,3,4,5], function(n) {
  return n % 2 === 0;
});  // [2, 4]

.map() transforma cada elemento y retorna una nueva colección jQuery. .get() convierte a un array nativo. $.map() es la versión estática para arrays/objetos. $.grep() filtra arrays (equivalente a Array.filter). Útil para extraer datos de múltiples elementos de una vez.

before() y after()
// before(): inserta ANTES (hermano)
$("#alvo").before("<p>Antes de mim</p>");

// after(): inserta DESPUÉS (hermano)
$("#alvo").after("<p>Depois de mim</p>");

// insertBefore() / insertAfter() (inverso):
$("<p>Nuevo</p>").insertBefore("#alvo");
$("<p>Nuevo</p>").insertAfter("#alvo");

// Diferencia con append:
// append/prepend → DENTRO (hijo)
// before/after   → FUERA (hermano)

before() y after() insertan como hermanos (fuera del elemento). append()/prepend() insertan como hijos (dentro). insertBefore()/insertAfter() son las versiones invertidas. Todos aceptan un HTML string, objeto jQuery o elemento DOM.

wrap() y unwrap()
// wrap(): envuelve cada elemento
$("p").wrap("<div class='wrapper'></div>");
// cada <p> queda dentro de una div

// wrapAll(): envuelve TODOS en uno
$("p").wrapAll("<div class='grupo'></div>");

// wrapInner(): envuelve el CONTENIDO
$("#caja").wrapInner("<span class='interno'></span>");

// unwrap(): quita el PADRE (desenvuelve)
$("p").unwrap();  // quita la div wrapper

// Ejemplo: destacar texto
$("p").wrapInner("<mark></mark>");

wrap() envuelve cada elemento individualmente. wrapAll() los envuelve todos en un único wrapper. wrapInner() envuelve el contenido (hijos) sin mover el elemento. unwrap() quita el padre directo. Útiles para añadir estructura sin reescribir HTML.

Chaining (encadenamiento)
// Los métodos retornan el objeto jQuery:
$("#caja")
  .addClass("activo")
  .css("color", "red")
  .fadeIn(300)
  .find("span")
  .text("Hola");

// end() vuelve a la selección anterior:
$("#menu")
  .find(".item").addClass("visto")
  .end()                    // vuelve a $("#menu")
  .find(".badge").text("3")
  .end();                   // vuelve a $("#menu")

// Sin chaining (repetitivo):
var $c = $("#caja");
$c.addClass("activo");
$c.css("color", "red");

Casi todos los métodos jQuery retornan this, permitiendo chaining. end() revierte a la selección anterior en la pila. Encadenar mejora la legibilidad y evita variables repetidas. Cuidado: find(), filter(), children() cambian la selección — usar end() para volver.

remove() y detach()
// remove(): borra del DOM + eventos + datos
$("#item").remove();
$("li.hecho").remove();  // múltiples

// Con filtro:
$("li").remove(".antiguo");

// detach(): borra pero MANTIENE eventos/datos
var $el = $("#widget").detach();
// ... más tarde:
$("#sidebar").append($el);  // eventos intactos

// empty(): quita solo los HIJOS
$("#container").empty();  // queda vacío pero existe

remove() elimina el elemento y todos sus eventos y data asociados. detach() quita del DOM pero preserva eventos/datos en memoria (para reinsertar después). empty() quita solo los hijos, manteniendo el padre. Usar remove() en la mayoría de los casos; detach() para mover elementos.

replaceWith() y replaceAll()
// replaceWith(): sustituye el elemento
$("#antiguo").replaceWith("<div class='nuevo'>Nuevo</div>");

// Con función (sustitución dinámica):
$("li").replaceWith(function(i) {
  return "<p>" + $(this).text() + "</p>";
});

// replaceAll() (inverso):
$("<span>N/A</span>").replaceAll(".vacio");

// Nota: los eventos del original se pierden
// (usar detach + insert si necesitas mantenerlos)

replaceWith() sustituye el elemento seleccionado por contenido nuevo. Acepta una función para sustitución dinámica por índice. replaceAll() es la forma invertida. Los eventos del elemento original se destruyen. Para mantener los handlers, usar detach() + inserción en vez de replace.

Manipulación en lote
// LENTO: insertar en loop (reflow en cada iteración)
for (var i = 0; i < 100; i++) {
  $("#lista").append("<li>" + i + "</li>");
}

// RÁPIDO: construir string e insertar 1x
var html = "";
for (var i = 0; i < 100; i++) {
  html += "<li>" + i + "</li>";
}
$("#lista").html(html);

// O: DocumentFragment
var $fragment = $(document.createDocumentFragment());
for (var i = 0; i < 100; i++) {
  $fragment.append("<li>" + i + "</li>");
}
$("#lista").append($fragment);

Cada inserción en el DOM causa un reflow (recálculo de layout). Insertar 100 elementos en un loop = 100 reflows. Construir un string HTML e insertar una vez es mucho más rápido. DocumentFragment agrupa elementos fuera del DOM y los inserta en batch. Para listas grandes, preferir .html() con un string completo.

Traversing


11 cards
parent() y parents()
// parent(): padre directo (1 nivel)
$("li").parent()         // el <ul> u <ol>

// parents(): TODOS los ancestros
$("a").parents()         // div, body, html...

// parents() con filtro:
$("a").parents("form")   // solo ancestros <form>
$("a").parents(".card")  // primera .card por encima

// closest(): sube hasta encontrar (incluye self)
$("a").closest(".card")  // la .card más cercana
// closest empieza en this; parents empieza en el padre

parent() retorna el padre directo. parents() sube hasta el <html> (todos los ancestros). closest() sube y retorna el primero que coincide (incluye el propio elemento). closest() es ideal para delegación y encontrar containers. parents() con filtro retorna todos los que coinciden.

filter() y not()
// filter(): mantiene los que coinciden
$("li").filter(".activo")
$("li").filter(":even")
$("li").filter(function(i) {
  return $(this).text().length > 10;
});

// not(): quita los que coinciden (inverso)
$("li").not(".hecho")
$("li").not(":first")
$("input").not(":disabled")

// is(): verifica (retorna boolean)
if ($("#caja").is(":visible")) { /* ... */ }
if ($(this).is(".activo")) { /* ... */ }

filter() reduce la colección a los que coinciden. not() es el inverso — quita los que coinciden. Ambos aceptan selector, función o elemento. is() retorna un boolean (no filtra, solo verifica). filter(fn) permite lógica arbitraria. is() es ideal en condiciones if.

closest() en la práctica
// Encontrar el container a partir de un botón:
$(".btn-delete").on("click", function() {
  var $card = $(this).closest(".card");
  $card.fadeOut(function() { $(this).remove(); });
});

// En tablas:
$("td a").on("click", function() {
  var $linea = $(this).closest("tr");
  var id = $linea.data("id");
});

// En formularios:
$("input").on("invalid", function() {
  $(this).closest(".form-group").addClass("error");
});

// closest vs parents:
// closest → primer match (sube)
// parents → todos los matches

closest() es el método más usado en delegación y handlers. Sube por el árbol hasta encontrar el primer coincidente (incluye el propio). Ideal para encontrar el "container" relevante a partir del elemento clicado. Más eficiente que parents().first(). Patrón común: $(this).closest(".card").

children() y find()
// children(): hijos directos (1 nivel)
$("ul").children()        // todos los <li> directos
$("ul").children(".activo") // solo li con la class activo

// find(): descendientes (cualquier nivel)
$("ul").find("a")         // todos los links dentro
$("#form").find("input")  // todos los inputs

// Diferencia:
// children → solo 1 nivel por debajo
// find     → cualquier profundidad

// children("*") = todos los hijos
$("#caja").children().length;  // cuántos hijos

children() retorna solo hijos directos (1 nivel). find() búsqueda a cualquier profundidad. Ambos aceptan un filtro opcional. find() se usa más (más flexible). children() es más rápido cuando solo necesitas el primer nivel. Sin argumentos, retornan todos los descendientes/hijos.

has() y is()
// has(): mantiene elementos que CONTIENEN el selector
$("li").has("ul")       // li que tienen sub-listas
$("div").has("img")     // divs con imágenes
$("td").has("a.link")   // celdas con links

// is(): test booleano
$("#form input").is(":focus")    // alguno con foco?
$(".card").is(":visible")        // alguno visible?
$(this).is("a[href^='http']")   // es link externo?

// Combinar:
$("li").has("> ul").addClass("tem-submenu");

has() filtra elementos que contienen descendientes coincidentes (no retorna los descendientes). is() comprueba si algún elemento de la colección coincide (retorna true/false). has("> ul") verifica hijos directos. Ambos útiles para lógica condicional y clasificación de elementos.

index() — posición del elemento
// Posición entre hermanos:
$("li").click(function() {
  var pos = $(this).index();  // 0-based entre hermanos
  console.log("Item " + pos);
});

// Posición en una colección:
var $ítems = $(".card");
$ítems.click(function() {
  var i = $ítems.index(this);
  console.log("Card " + i + " de " + $ítems.length);
});

// Posición de un selector:
var pos = $("li").index("#especial");

index() sin argumentos retorna la posición entre hermanos (zero-based). Con elemento/DOM como argumento, retorna la posición en la colección. Con selector, retorna la posición del primer match. Útil para tabs, sliders y navegación. Retornar -1 significa no encontrado.

siblings() y hermanos
// siblings(): todos los hermanos
$("li.activo").siblings()          // otros li
$("li.activo").siblings(".hecho")  // hermanos con la class

// next(): hermano siguiente (1)
$("li.activo").next()

// prev(): hermano anterior (1)
$("li.activo").prev()

// nextAll() / prevAll():
$("li.activo").nextAll()   // todos después
$("li.activo").prevAll()   // todos antes

// nextUntil() / prevUntil():
$("li.activo").nextUntil(".fin")  // hasta encontrar .fin

siblings() retorna todos los hermanos (excluye a sí mismo). next()/prev() retornan el hermano inmediatamente siguiente/anterior. nextAll()/prevAll() retornan todos en una dirección. nextUntil() para al encontrar el selector. Todos aceptan un filtro opcional. Útiles para navegación en listas y tabs.

add() y addBack()
// add(): combina selecciones
$("h1").add("h2").add("h3").css("color", "navy");
$("p").add(".nota").addClass("texto");

// addBack(): reañade la selección anterior
$("ul").find("li")   // solo li
  .addClass("item")
  .addBack()         // ul + li
  .css("border", "1px solid #ccc");

// Sin addBack (repetir el selector):
var $ul = $("ul");
$ul.find("li").addClass("item");
$ul.css("border", "1px solid #ccc");

add() combina múltiples selecciones en un único objeto jQuery. addBack() reañade los elementos de la selección anterior (antes del find()/filter()). addBack(selector) reañade solo los que coinciden. Evita repetir selectores en operaciones que afectan a padres e hijos.

Navegación en tablas
// Patrón común: acciones en filas de tabla
$("#tabla").on("click", ".btn-edit", function() {
  var $tr = $(this).closest("tr");
  var id = $tr.data("id");
  var nombre = $tr.find("td").eq(1).text();
  var email = $tr.find("td").eq(2).text();
  abrirModal(id, nombre, email);
});

// Zebra striping:
$("#tabla tr:even").addClass("zebra");

// Destacar fila en hover:
$("#tabla").on("mouseenter", "tr", function() {
  $(this).addClass("hover");
}).on("mouseleave", "tr", function() {
  $(this).removeClass("hover");
});

Patrón típico: closest("tr") para la fila, find("td").eq(n) para celdas. data-id en el <tr> almacena el identificador. :even para zebrar. Delegación con on() para botones dentro de celdas. Este patrón se aplica a cualquier estructura repetitiva (cards, listas, grids).

first(), last() y eq()
var $ítems = $("li");

// first(): primero de la colección
$ítems.first().addClass("highlight");

// last(): último de la colección
$ítems.last().addClass("fin");

// eq(n): índice específico (zero-based)
$ítems.eq(0).css("color", "red");   // primero
$ítems.eq(2).css("color", "blue");  // tercero
$ítems.eq(-1).css("color", "green"); // último

// slice(inicio, fin):
$ítems.slice(1, 4).addClass("medio"); // índices 1,2,3

Métodos de posición en la colección jQuery. eq(n) es zero-based y acepta negativos (-1 = último). slice() funciona como Array.slice (fin exclusivo). Todos retornan un nuevo objeto jQuery (chainable). Más rápidos que los pseudo-selectores :first, :last, :eq().

contents()
// contents(): hijos incluyendo texto y comentarios
$("#caja").contents()

// Diferencia de children():
// children() → solo elementos
// contents() → elementos + nodos de texto + comentarios

// Manipular texto dentro de elemento:
$("#paragrafo").contents().filter(function() {
  return this.nodeType === 3;  // nodo de texto
}).wrap("<strong></strong>");

// Útil para iframes:
$("#frame").contents().find("body").css("font", "16px");

contents() retorna todos los nodos hijos: elementos, texto y comentarios. children() retorna solo elementos. nodeType === 3 identifica nodos de texto. Útil para manipular texto inline sin afectar tags. contents() en iframes da acceso al documento interno (mismo origen).

Atributos e Dados


11 cards
attr() — atributos HTML
// Leer atributo:
var href = $("a").attr("href");
var alt = $("img").attr("alt");

// Definir:
$("a").attr("href", "/nueva-pagina");
$("img").attr("alt", "Descripcion da imagen");

// Múltiples de una vez:
$("a").attr({
  href: "/link",
  target: "_blank",
  rel: "noopener"
});

// Con una función:
$("li").attr("data-index", function(i) {
  return i;
});

attr() lee/define atributos HTML (lo que está en el markup). Sin argumento retorna el valor del primer elemento. Con argumento define en todos los seleccionados. Acepta un objeto para múltiples atributos. Retorna undefined si el atributo no existe. Para valores booleanos (checked, disabled), preferir prop().

hasClass()
// Verificar si tiene una clase:
if ($("#menu").hasClass("abierto")) {
  fecharMenu();
} else {
  abrirMenu();
}

// Equivalente con toggleClass:
$("#menu").toggleClass("abierto");

// En colecciones (cualquier elemento):
if ($(".card").hasClass("seleccionado")) {
  // al menos UN card tiene la clase
}

// contains() nativo (alternativa):
this.classList.contains("activo");

hasClass() retorna true si cualquier elemento de la colección tiene la clase. No acepta múltiples clases. Equivalente nativo: classList.contains(). Útil para condiciones if. Para alternar sin verificar, usar directamente toggleClass() (más conciso).

Manipular múltiples atributos
// Patrón: actualizar varios atributos
function actualizarLink($el, datos) {
  $el.attr({
    href: datos.url,
    title: datos.título,
    "aria-label": datos.título,
    target: datos.externo ? "_blank" : "_self"
  });
}

// Atributos condicionales:
$("a").each(function() {
  var $a = $(this);
  if ($a.attr("href").startsWith("http")) {
    $a.attr({ target: "_blank", rel: "noopener" });
  }
});

// Quitar en lote:
$(".temp").removeAttr("style title data-debug");

attr({}) con un objeto define múltiples atributos en una llamada (más legible). Los atributos con guion necesitan comillas ("aria-label"). Valores dinámicos con ternario. removeAttr() acepta múltiples separados por espacio. Patrón: agrupar atributos relacionados en una única llamada para claridad.

removeAttr()
// Quitar un atributo:
$("input").removeAttr("disabled");
$("img").removeAttr("width height");  // múltiples

// Ejemplo: activar campo
$("#campo").removeAttr("readonly");

// Diferencia de attr("x", ""):
// removeAttr → el atributo desaparece del DOM
// attr("x","") → el atributo queda con valor vacío

removeAttr() elimina completamente el atributo del elemento. Acepta múltiples nombres separados por espacio. Diferente de definir un valor vacío — el atributo desaparece del markup. Útil para activar campos (disabled, readonly) o quitar estilos inline. Para propiedades booleanas, prop("x", false) es preferible.

val() — valores de formulario
// Leer un valor:
var nombre = $("#nombre").val();
var opción = $("select").val();

// Definir:
$("#nombre").val("John");
$("textarea").val("Texto inicial");

// Select múltiple:
$("#multi").val(["op1", "op2"]);  // array
var seleccionados = $("#multi").val();  // ["op1","op2"]

// Checkbox/radio (usar prop):
$("#check").prop("checked", true);
// val() en un checkbox retorna el atributo value

// Limpiar un campo:
$("#búsqueda").val("");

val() lee/define el value de campos de formulario. En un select, retorna el value de la opción seleccionada. En un select multiple, retorna/acepta un array. Para checkbox/radio, usar prop("checked") en vez de val(). Sin argumentos lee; con argumento define en todos los seleccionados.

innerHTML vs jQuery
// jQuery:
$("#caja").html("<p>Nuevo</p>");
var contenido = $("#caja").html();

// Equivalente vanilla:
document.getElementById("caja").innerHTML = "<p>Nuevo</p>";
var contenido = document.getElementById("caja").innerHTML;

// outerHTML (elemento + contenido):
var completo = $("#caja").prop("outerHTML");

// jQuery para texto:
$("#caja").text("Sem tags");
// Vanilla:
document.getElementById("caja").textContent = "Sem tags";

html() equivale a innerHTML nativo. text() equivale a textContent. prop("outerHTML") obtiene el elemento completo (incluyendo su propia tag). jQuery normaliza diferencias entre navegadores. Para insertar HTML de fuentes no confiables, sanitizar antes o usar text() (previene XSS).

prop() — propiedades DOM
// prop() para estados booleanos:
$("#check").prop("checked", true);
$("#campo").prop("disabled", true);
$("#select").prop("selectedIndex", 2);

// Leer:
var marcado = $("#check").prop("checked");  // true/false
var desactivado = $("#campo").prop("disabled");

// attr vs prop:
// attr("checked") → "checked" o undefined (HTML)
// prop("checked") → true o false (estado actual)

// Siempre prop para: checked, selected, disabled, readonly

prop() accede a propiedades del DOM (estado actual), no al atributo HTML. Para checked, disabled, selected — usar siempre prop(). attr() retorna el valor del markup inicial; prop() retorna el estado en tiempo real. Ejemplo: checkbox marcado por el user → prop("checked") = true, attr("checked") puede ser undefined.

data() — data-attributes
// HTML: <div data-user-id="42" data-nombre="Ana">

// Leer (camelCase automático):
$("#div").data("user-id");   // 42 (numero!)
$("#div").data("userId");    // 42 (equivalente)
$("#div").data("nombre");      // "Ana"

// Definir (solo en memoria, no en el HTML):
$("#div").data("temp", {x: 1});
$("#div").data("activo", true);

// Leer todos:
var tudo = $("#div").data();
// {userId: 42, nombre: "Ana", temp: {x:1}, activo: true}

// Quitar:
$("#div").removeData("temp");

data() accede a data-attributes con conversión automática de tipos (numeros, booleanos, JSON). Los nombres con guion pasan a camelCase. data(key, valor) almacena en memoria jQuery (no altera el HTML). Acepta objetos y arrays. removeData() lo limpia. Más rápido que attr("data-*") para lecturas repetidas.

Patrón toggle de estado
// Toggle de menú:
$("#btn-menu").on("click", function() {
  $("#menu").toggleClass("abierto");
  $(this).toggleClass("activo");
  $("#menu").attr("aria-expanded",
    $("#menu").hasClass("abierto")
  );
});

// Toggle de disabled:
function toggleCampo($campo, activo) {
  $campo.prop("disabled", !activo);
  $campo.toggleClass("desactivado", !activo);
}

// Estado con data:
$("#btn").on("click", function() {
  var $btn = $(this);
  var activo = !$btn.data("activo");
  $btn.data("activo", activo);
  $btn.text(activo ? "ON" : "OFF");
});

Patrón común: toggleClass() + prop() + data() para gestionar estado. Sincronizar atributos ARIA (aria-expanded) para accesibilidad. data() almacena el estado lógico; las clases controlan lo visual. Funciones helper (toggleCampo) evitan repetición. Mantener estado y UI sincronizados.

addClass() y removeClass()
// Añadir clase(s):
$("#caja").addClass("activo");
$("#caja").addClass("visible highlight");

// Quitar:
$("#caja").removeClass("activo");
$("#caja").removeClass();  // quita TODAS

// Toggle (añade si no tiene, quita si tiene):
$("#caja").toggleClass("abierto");

// Con condición:
$("#caja").toggleClass("error", hasError);
// true → añade; false → quita

// Con una función:
$("li").addClass(function(i) {
  return "item-" + i;
});

addClass()/removeClass() manipulan clases sin afectar a otras existentes. toggleClass() alterna (añade/quita). Un segundo parámetro booleano fuerza añadir o quitar. Sin argumentos, removeClass() quita todas las clases. Aceptan múltiples clases separadas por espacio. Preferir clases a estilos inline.

data() vs attr("data-*")
// HTML: <button data-id="5" data-config='{"a":1}'>

// data() → convierte tipos + cache en memoria:
$("button").data("id");       // 5 (Number)
$("button").data("config");   // {a: 1} (Object)

// attr() → siempre string del HTML:
$("button").attr("data-id");       // "5" (String)
$("button").attr("data-config");   // '{"a":1}' (String)

// data() no refleja cambios en el HTML:
$("button").attr("data-id", "99");
$("button").data("id");    // aún 5 (cache!)
$("button").attr("data-id"); // "99"

// Regla: usar data() consistentemente

data() convierte tipos automáticamente y hace cache en memoria. attr("data-*") retorna siempre una string del HTML actual. Atención: tras leer con data(), los cambios en el HTML vía attr() no se reflejan (cache). Usar uno u otro consistentemente. data() es preferible por rendimiento y tipos.

CSS e Dimensões


11 cards
css() — leer y definir estilos
// Leer (retorna el valor computado):
var color = $("#caja").css("color");        // "rgb(255, 0, 0)"
var tamano = $("#caja").css("font-size"); // "16px"

// Definir:
$("#caja").css("color", "blue");
$("#caja").css("font-size", "18px");

// Múltiples (objeto, camelCase):
$("#caja").css({
  backgroundColor: "#f0f0f0",
  border: "2px solid #333",
  padding: "10px",
  borderRadius: "4px"
});

css() sin argumento retorna el valor computado (no el inline). Con argumento define estilo inline. Un objeto usa camelCase (no guion). Múltiples propiedades en una llamada. Valores numéricos sin unidad asumen px. Preferir addClass() a css() para estilos reutilizables.

fadeIn() y fadeOut()
// Fade (solo opacity):
$("#caja").fadeIn(400);
$("#caja").fadeOut(400);
$("#caja").fadeToggle(400);

// Opacidad parcial:
$("#caja").fadeTo(300, 0.5);  // 50% opacidad

// Callback:
$("#overlay").fadeIn(200, function() {
  $("#modal").fadeIn(300);
});

// Secuencia:
$("#a").fadeOut(200, function() {
  $("#b").fadeIn(200);
});

fadeIn()/fadeOut() animan solo la opacity (no afectan al layout como show/hide). fadeTo() define opacidad parcial sin ocultar. fadeToggle() alterna. Aceptan una duración (ms o "slow"/"fast") y un callback de conclusión. Encadenar en callbacks para secuencias. El elemento queda con display:none tras fadeOut.

Cola de animaciones
// Las animaciones se encadenan automáticamente:
$("#caja")
  .fadeIn(300)
  .animate({ left: "100px" }, 500)
  .fadeOut(300);
// se ejecuta en secuencia (la cola "fx")

// queue() para inspeccionar:
var tamano = $("#caja").queue("fx").length;

// dequeue() para continuar manualmente:
$("#caja").queue(function(next) {
  $(this).addClass("processando");
  setTimeout(next, 1000);  // llama a next() para continuar
});

// Limpiar la cola:
$("#caja").clearQueue();
$("#caja").stop(true);  // equivalente

Las animaciones jQuery entran en una cola ("fx") y se ejecutan en secuencia. queue(fn) añade pasos custom a la cola (llamar a next() para continuar). clearQueue() quita las pendientes. stop(true) limpia la cola + para la actual. Para animaciones simultáneas, llamar a animate() con las propiedades en el mismo objeto.

width() y height()
// content (sin padding/border):
$("#caja").width();    // 200
$("#caja").height();   // 100

// Definir:
$("#caja").width(300);
$("#caja").height("50%");

// innerWidth/Height (content + padding):
$("#caja").innerWidth();   // 220 (200 + 10+10)

// outerWidth/Height (+ border):
$("#caja").outerWidth();   // 224 (220 + 2+2)

// outerWidth(true) (+ margin):
$("#caja").outerWidth(true);  // 244 (224 + 10+10)

width()/height() retornan las dimensiones del contenido (sin padding/border/margin). innerWidth() incluye padding. outerWidth() incluye padding + border. outerWidth(true) incluye también margin. Retornan numeros (sin "px"). Para definir, aceptan numero (px) o string ("50%").

slideUp() y slideDown()
// Slide (anima la altura):
$("#painel").slideDown(300);
$("#painel").slideUp(300);
$("#painel").slideToggle(300);

// Menú dropdown:
$("#menu-btn").on("click", function() {
  $("#dropdown").slideToggle(200);
});

// Acordeón:
$(".acc-header").on("click", function() {
  $(this).next(".acc-body").slideToggle(300);
  $(this).closest(".acc-item")
    .siblings().find(".acc-body").slideUp(300);
});

slideUp()/slideDown() animan la altura del elemento (efecto cortina). slideToggle() alterna. Ideal para menús dropdown, acordeones y paneles colapsables. El elemento necesita overflow:hidden durante la animación (jQuery lo aplica automáticamente). Callback en el segundo parámetro.

CSS transitions vs jQuery
/* CSS (preferir por rendimiento): */
.caja {
  transition: opacity 0.3s, transform 0.3s;
  opacity: 1;
}
.caja.oculto {
  opacity: 0;
  transform: translateY(-10px);
}

// jQuery solo hace toggle de la clase:
$("#btn").on("click", function() {
  $("#caja").toggleClass("oculto");
});

// jQuery animate para lo que CSS no hace:
$("#caja").animate({ scrollTop: 0 }, 500);
// el scroll no es animable con una CSS transition

Las CSS transitions son más performantes (GPU, no bloquean JS). Usar jQuery solo para toggleClass y dejar que CSS anime. animate() para lo que CSS no hace: scroll, contadores, valores relativos. Las transitions no necesitan cola/stop. Regla: CSS para lo visual, jQuery para la lógica y el scroll.

position() y offset()
// position(): relativo al PADRE posicionado
var pos = $("#filho").position();
pos.top;   // distancia al tope del padre
pos.left;  // distancia a la izquierda del padre

// offset(): relativo al DOCUMENTO
var off = $("#caja").offset();
off.top;   // distancia al tope de la página
off.left;  // distancia a la izquierda de la página

// Definir offset (mueve el elemento):
$("#caja").offset({ top: 100, left: 50 });

// Scroll actual:
$(window).scrollTop();   // scroll vertical
$(window).scrollLeft();  // scroll horizontal

position() es relativo al offset parent (padre posicionado más cercano). offset() es relativo al documento (página entera). Ambos retornan {top, left}. offset() puede definir la posición. Para elementos fijos en el viewport, combinar offset() con $(window).scrollTop().

animate()
// Animación custom:
$("#caja").animate({
  left: "200px",
  opacity: 0.5,
  width: "300px"
}, 500);

// Con easing y callback:
$("#caja").animate(
  { top: "100px" },
  800,
  "swing",       // o "linear"
  function() { console.log("fin!"); }
);

// Propiedades relativas:
$("#caja").animate({ left: "+=50" }, 300);
$("#caja").animate({ opacity: "-=0.2" }, 300);

// Nota: necesita position:relative/absolute

animate() anima propiedades CSS numéricas. No anima colores (usar jQuery UI o CSS transitions). +=/-= para valores relativos. Parámetros: propiedades, duración, easing ("swing" o "linear") y callback. El elemento necesita un position definido para animar top/left. Múltiples propiedades animan en simultáneo.

Scroll y posición
// Scroll suave hacia un elemento:
$("a[href^='#']").on("click", function(e) {
  e.preventDefault();
  var alvo = $($(this).attr("href"));
  $("html, body").animate({
    scrollTop: alvo.offset().top - 80  // offset del header
  }, 500);
});

// Leer scroll:
$(window).scrollTop();    // posición actual
$(window).scrollTop(0);   // ir al tope

// Scroll de container:
$("#painel").scrollTop(200);

// Detectar fin de scroll:
$(window).on("scroll", function() {
  if ($(window).scrollTop() + $(window).height()
      >= $(document).height() - 100) {
    loadMore();  // infinite scroll
  }
});

scrollTop() lee/define la posición de scroll. Animar $("html, body") para scroll suave cross-browser. Restar la altura del header fijo al calcular la posición. $(window).height() + scrollTop() vs $(document).height() para detectar el fin de página (infinite scroll). Hacer throttle al evento scroll por rendimiento.

show(), hide() y toggle()
// Mostrar/ocultar (sin animación):
$("#caja").show();
$("#caja").hide();
$("#caja").toggle();  // alterna

// Con duración (se vuelve animación):
$("#caja").show(300);      // 300ms
$("#caja").hide("slow");   // 600ms
$("#caja").toggle("fast"); // 200ms

// Callback al completar:
$("#caja").hide(300, function() {
  console.log("ocultado!");
});

// hide() = display:none (guarda el display original)
// show() restaura el display anterior

show()/hide() alteran display (sin animación por defecto). Con duración, animan opacity + tamaño. toggle() alterna entre show/hide. jQuery memoriza el display original para restaurar. hide() define display:none. Los callbacks se ejecutan tras completar. "slow"=600ms, "fast"=200ms.

stop() y delay()
// Parar la animación actual:
$("#caja").stop();

// Parar y saltar al final:
$("#caja").stop(true, true);

// Parar TODAS en la cola:
$("#caja").stop(true, false);

// Delay entre animaciones:
$("#caja")
  .delay(500)          // espera 500ms
  .fadeIn(300)
  .delay(1000)         // espera 1s
  .fadeOut(300);

// Problema clásico: hover con cola
$("#menu").hover(
  function() { $(this).stop(true).slideDown(200); },
  function() { $(this).stop(true).slideUp(200); }
);

stop() interrumpe la animación actual. stop(true) limpia la cola de animaciones pendientes. stop(true, true) salta al final. delay(ms) inserta una pausa entre animaciones en cola. Siempre usar stop(true) en hover para evitar acumulación de animaciones (bug clásico de jQuery).

Efeitos e Animações


11 cards
Efectos básicos combinados
// show/hide con animación:
$("#caja").show(400);       // aparece con scale
$("#caja").hide(400);       // desaparece con scale
$("#caja").toggle(400);     // alterna

// fade (solo opacity):
$("#caja").fadeIn(400);
$("#caja").fadeOut(400);
$("#caja").fadeToggle(400);

// slide (solo altura):
$("#caja").slideDown(400);
$("#caja").slideUp(400);
$("#caja").slideToggle(400);

// Duración: numero (ms) o string
// "slow" = 600ms, "fast" = 200ms

Tres familias de efectos: show/hide (opacity + tamaño), fade (solo opacity), slide (solo altura). Todos aceptan duración en ms o "slow"/"fast". El toggle en cada familia alterna automáticamente. Sin duración, show/hide es instantáneo; fade/slide necesitan duración. Callback en el último parámetro.

Animaciones simultáneas
// Simultáneas: propiedades en el mismo animate()
$("#caja").animate({
  opacity: 0,
  left: "+=100",
  height: "toggle"
}, 500);

// Múltiples elementos al mismo tiempo:
$(".card").each(function(i) {
  $(this).delay(i * 100).fadeIn(400);
});
// efecto cascada (stagger)

// Paralelo con sincronización:
$("#fondo").animate({opacity: 0.5}, 300);
$("#texto").animate({fontSize: "2em"}, 300);
// ambos corren en paralelo (elementos diferentes)

Las propiedades en el mismo animate() corren en simultáneo. Los elementos diferentes animan en paralelo automáticamente. delay(i * 100) crea un efecto cascada (stagger). La cola es por elemento — elementos distintos no se bloquean. Para secuencias complejas, usar callbacks o $.when().

Tooltip simple
// Tooltip con fade:
$("[data-tooltip]").on("mouseenter", function(e) {
  var texto = $(this).data("tooltip");
  var $tip = $('<div class="tooltip"></div>').text(texto);
  $("body").append($tip);

  $tip.css({
    top: e.pageY - 30,
    left: e.pageX + 10
  }).fadeIn(150);
}).on("mouseleave", function() {
  $(".tooltip").fadeOut(100, function() {
    $(this).remove();
  });
});

// Seguir el ratón:
$("[data-tooltip]").on("mousemove", function(e) {
  $(".tooltip").css({ top: e.pageY - 30, left: e.pageX + 10 });
});

Un tooltip creado dinámicamente con data-tooltip. Posicionado con e.pageX/pageY en mouseenter. fadeIn/fadeOut para una transición suave. Quitar del DOM tras fadeOut (evitar acumulación). mousemove para seguir el cursor. Usar text() (no html) para prevenir XSS. Para producción, preferir bibliotecas dedicadas.

animate() avanzado
// Múltiples propiedades:
$("#caja").animate({
  width: "toggle",      // alterna width
  opacity: "toggle",    // alterna opacity
  left: "200px",
  fontSize: "1.5em"
}, 600);

// Valores relativos:
$("#caja").animate({ left: "+=100", top: "-=50" }, 400);

// Paso a paso (step callback):
$("#barra").animate({ width: "100%" }, {
  duration: 1000,
  step: function(now) {
    $(this).text(Math.round(now) + "%");
  },
  complete: function() {
    $(this).text("Completado!");
  }
});

animate() acepta "toggle", "show", "hide" como valores para alternar. +=/-= para movimiento relativo. Un objeto de opciones permite step (en cada frame) y complete (al final). step es útil para contadores y barras de progreso. No anima colores, transforms ni propiedades no numéricas.

Modal / Overlay
// Abrir modal:
function abrirModal() {
  $("#overlay").fadeIn(200);
  $("#modal").fadeIn(300).css("display", "flex");
}

// Cerrar:
function fecharModal() {
  $("#modal").fadeOut(200);
  $("#overlay").fadeOut(300);
}

// Cerrar con ESC o un clic en el overlay:
$(document).on("keydown", function(e) {
  if (e.key === "Escape") fecharModal();
});
$("#overlay").on("click", fecharModal);

// Prevenir scroll del body:
$("body").css("overflow", "hidden");  // abrir
$("body").css("overflow", "");        // cerrar

Patrón de modal: overlay (fondo oscuro) + caja central. fadeIn para abrir, fadeOut para cerrar. Cerrar con ESC y clic en el overlay. Bloquear el scroll del body con overflow:hidden. Usar un z-index alto en el CSS. Para accesibilidad, gestionar focus y aria-modal.

Contador animado
// Animar un numero de 0 hasta un objetivo:
function animarNumero($el, alvo, duración) {
  $({ valor: 0 }).animate({ valor: alvo }, {
    duration: duración || 1500,
    easing: "swing",
    step: function() {
      $el.text(Math.floor(this.valor));
    },
    complete: function() {
      $el.text(alvo);  // garantizar el valor exacto
    }
  });
}

// Uso:
animarNumero($("#stats-users"), 15000);
animarNumero($("#stats-ventas"), 892);

// Con formato:
step: function() {
  $el.text(Math.floor(this.valor).toLocaleString("pt-PT"));
}

Truco: animar un objeto plain ($({valor: 0})) y usar step para actualizar el texto. Math.floor() evita decimales durante la animación. complete garantiza el valor exacto al final. toLocaleString() para formato de miles. Un efecto visual popular en landing pages y dashboards.

Easing
// Easing built-in:
$("#caja").animate({left: "200px"}, 500, "swing");
$("#caja").animate({left: "200px"}, 500, "linear");

// swing: acelera al inicio, desacelera al final (default)
// linear: velocidad constante

// Con jQuery UI (más easings):
$("#caja").animate({top: "100px"}, 800, "easeOutBounce");
$("#caja").animate({left: "300px"}, 600, "easeInOutCubic");
$("#caja").animate({width: "toggle"}, 500, "easeOutElastic");

// Definir un default:
$.fx.speeds.lento = 1000;
$("#caja").fadeIn("lento");

Easing controla la aceleración de la animación. jQuery core solo tiene "swing" (default) y "linear". jQuery UI añade decenas (easeOutBounce, easeInOutCubic, etc.). $.fx.speeds permite crear duraciones nombradas custom. Para animaciones complejas, considerar CSS transitions/animations o GSAP.

Acordeón
// HTML: .acc-item > .acc-header + .acc-body
$(".acc-header").on("click", function() {
  var $item = $(this).closest(".acc-item");
  var $body = $item.find(".acc-body");
  var abierto = $body.is(":visible");

  // Cerrar todos:
  $(".acc-body").slideUp(300);
  $(".acc-item").removeClass("activo");

  // Abrir el clicado (si estaba cerrado):
  if (!abierto) {
    $body.slideDown(300);
    $item.addClass("activo");
  }
});

// Inicializar: primero abierto
$(".acc-item:first .acc-body").show();
$(".acc-item:first").addClass("activo");

Patrón acordeón: slideUp() cierra todos, slideDown() abre el seleccionado. is(":visible") verifica el estado actual. closest() y find() para navegación. La clase activo estiliza el header. Permitir cerrar todos o mantener siempre uno abierto (quitar el if). Inicializar el estado al arranque.

Lazy load de imágenes
// HTML: <img data-src="foto.jpg" class="lazy">
function lazyLoad() {
  $(".lazy").each(function() {
    var $img = $(this);
    var top = $img.offset().top;
    var scroll = $(window).scrollTop();
    var altura = $(window).height();

    if (top < scroll + altura + 200) {
      $img.attr("src", $img.data("src"))
          .removeAttr("data-src")
          .removeClass("lazy")
          .hide().fadeIn(400);
    }
  });
}

$(window).on("scroll", lazyLoad);
lazyLoad();  // verificar los visibles en el load

// Nota: hacer throttle en el scroll!

Lazy load: la imagen solo carga cuando entra en el viewport. data-src guarda la URL real; src queda vacío/placeholder. Verificar offset().top vs scrollTop() + height(). Un margen de 200px para precargar. fadeIn para la transición. Siempre throttle en el scroll. Hoy: preferir loading="lazy" nativo o IntersectionObserver.

Callbacks de animación
// Callback al completar:
$("#caja").fadeOut(300, function() {
  $(this).remove();  // quitar después de ocultar
});

// Secuencia con callbacks:
$("#a").fadeOut(200, function() {
  $("#b").fadeIn(200, function() {
    $("#c").slideDown(200);
  });
});

// Promise (jQuery 3+):
$("#caja").fadeOut(300).promise().done(function() {
  console.log("todas las animaciones completas");
});

// $.when para múltiples:
$.when(
  $("#a").fadeIn(300),
  $("#b").slideDown(300)
).done(function() {
  $("#c").show();
});

Un callback se ejecuta cuando la animación termina (por elemento). Para colecciones, se dispara una vez por elemento. .promise().done() se dispara una vez cuando todas terminan. $.when() espera múltiples animaciones en paralelo. Patrón: animar → callback → próxima acción. Evitar nesting profundo (callback hell).

Tabs / Pestañas
// HTML: .tab-btn[data-tab] + .tab-panel[id]
$(".tab-btn").on("click", function() {
  var alvo = $(this).data("tab");

  // Desactivar todas:
  $(".tab-btn").removeClass("activa");
  $(".tab-panel").hide();

  // Activar la seleccionada:
  $(this).addClass("activa");
  $("#" + alvo).fadeIn(200);
});

// Con URL hash:
var hash = window.location.hash.slice(1);
if (hash) {
  $('.tab-btn[data-tab="' + hash + '"]').click();
} else {
  $(".tab-btn:first").click();
}

Patrón tabs: los botones con data-tab apuntan a IDs de paneles. hide() todos + fadeIn() el activo. La clase activa estiliza el botón. Soportar el URL hash para deep-linking. Disparar click() programáticamente para inicializar. Alternativa: CSS con :target (sin JS).

AJAX


11 cards
$.ajax() — el método completo
$.ajax({
  url: "/api/datos",
  method: "GET",
  dataType: "json",
  data: { pagina: 1, limite: 20 },
  headers: { "X-Token": "abc123" },
  timeout: 5000,
  beforeSend: function() {
    $("#loading").show();
  },
  success: function(datos, status, xhr) {
    renderizar(datos);
  },
  error: function(xhr, status, error) {
    alert("Error: " + error);
  },
  complete: function() {
    $("#loading").hide();
  }
});

$.ajax() es el método más completo y flexible. method: GET, POST, PUT, DELETE. dataType: tipo esperado de la respuesta (json, html, text). data: parámetros enviados. Callbacks: beforeSend (antes), success (éxito), error (fallo), complete (siempre). La base de todos los atajos jQuery AJAX.

Enviar JSON
// POST con JSON:
$.ajax({
  url: "/api/productos",
  method: "POST",
  contentType: "application/json",
  data: JSON.stringify({
    nombre: "Producto X",
    precio: 29.90,
    tags: ["nuevo", "highlight"]
  }),
  success: function(respuesta) {
    console.log("ID:", respuesta.id);
  }
});

// Nota importante:
// contentType: "application/json" → enviar JSON
// (default es "x-www-form-urlencoded")
// data debe ser JSON.stringify()

// PUT y DELETE:
$.ajax({ url: "/api/x/1", method: "PUT", ... });
$.ajax({ url: "/api/x/1", method: "DELETE", ... });

Para enviar JSON: definir contentType: "application/json" y usar JSON.stringify() en los datos. Sin esto, jQuery lo envía como form-encoded. method acepta PUT, DELETE, PATCH. El servidor debe responder con JSON. Para APIs REST, este es el patrón más común. Headers de auth vía headers: {}.

AJAX con formularios
$("form").on("submit", function(e) {
  e.preventDefault();
  var $form = $(this);
  var $btn = $form.find("[type=submit]");

  $btn.prop("disabled", true).text("A enviar...");

  $.ajax({
    url: $form.attr("action"),
    method: $form.attr("method"),
    data: $form.serialize(),
    success: function(r) {
      alert("Éxito!");
      $form[0].reset();
    },
    error: function(xhr) {
      var errores = xhr.responseJSON.errors;
      $.each(errores, function(campo, msg) {
        $("#" + campo).after('<span class="error">' + msg + '</span>');
      });
    },
    complete: function() {
      $btn.prop("disabled", false).text("Enviar");
    }
  });
});

Patrón de formulario AJAX: preventDefault(), serialize() para los datos, desactivar el botón durante el envío. $form.attr("action") y $form.attr("method") respetan el HTML. complete reactiva el botón (éxito o error). Mapear errores de validación por campo. $form[0].reset() limpia el formulario nativo.

$.get() y $.post()
// GET simple:
$.get("/api/users", function(datos) {
  console.log(datos);
});

// GET con parámetros:
$.get("/api/users", { activo: 1 }, function(datos) {
  listar(datos);
}, "json");

// POST:
$.post("/api/users", {
  nombre: "Ana",
  email: "ana@email.com"
}, function(respuesta) {
  alert("Creado: " + respuesta.id);
}, "json");

// POST con error:
$.post("/api/login", datos)
  .done(function(r) { /* ok */ })
  .fail(function(xhr) { /* error */ });

$.get() y $.post() son atajos simplificados. Parámetros: url, data, callback, dataType. Retornan un jqXHR (thenable) — usar .done()/.fail() en vez de callback. $.getJSON() es un atajo para GET con dataType json. Para configuraciones avanzadas (headers, timeout), usar $.ajax().

Upload de ficheros
// HTML: <input type="file" id="fichero">
$("#form-upload").on("submit", function(e) {
  e.preventDefault();

  var formData = new FormData(this);
  // o: formData.append("fichero", $("#fichero")[0].files[0]);

  $.ajax({
    url: "/api/upload",
    method: "POST",
    data: formData,
    processData: false,   // NO procesar los datos
    contentType: false,   // NO definir el content-type
    xhr: function() {
      var xhr = new XMLHttpRequest();
      xhr.upload.onprogress = function(e) {
        var pct = (e.loaded / e.total) * 100;
        $("#progresso").css("width", pct + "%");
      };
      return xhr;
    },
    success: function(r) { alert("Upload: " + r.url); }
  });
});

El upload usa FormData nativo. processData: false impide que jQuery serialice. contentType: false deja que el browser defina multipart. xhr.upload.onprogress para una barra de progreso. this.files[0] accede al fichero del input. Nunca usar $.post() para uploads — necesita $.ajax() con estas opciones.

Debounce para búsqueda
// Búsqueda con debounce (espera a que dejes de escribir):
var timer;
$("#búsqueda").on("input", function() {
  var termo = $(this).val();
  clearTimeout(timer);

  if (termo.length < 2) {
    $("#resultados").empty();
    return;
  }

  timer = setTimeout(function() {
    $.get("/api/búsqueda", { q: termo }, function(datos) {
      var html = datos.map(function(item) {
        return "<li>" + item.nombre + "</li>";
      }).join("");
      $("#resultados").html(html);
    });
  }, 300);  // 300ms tras la última tecla
});

// Abortar la petición anterior:
var xhrActual;
// xhrActual = $.get(...); xhrActual.abort();

Debounce: esperar N ms tras la última tecla antes de buscar. clearTimeout cancela el timer anterior en cada input. Un mínimo de 2 caracteres evita peticiones innecesarias. xhr.abort() cancela peticiones pendientes (evitar respuestas fuera de orden). Un patrón esencial para autocomplete y búsqueda en tiempo real.

load() — cargar HTML
// Cargar HTML directamente en un elemento:
$("#contenido").load("/pagina.html");

// Cargar un fragmento (selector):
$("#contenido").load("/pagina.html #sección");
$("#sidebar").load("/layout.html .widget");

// Con datos y callback:
$("#resultados").load("/búsqueda", { q: "jquery" },
  function(respuesta, status, xhr) {
    if (status === "error") {
      $(this).html("Error: " + xhr.status);
    }
  }
);

// Sustituir vs insertar:
// load() SUSTITUYE el contenido del elemento

load() hace un GET e inserta la respuesta HTML directamente en el elemento. Con un selector tras un espacio, carga solo un fragmento de la página. El callback recibe (respuesta, status, xhr). Sustituye el contenido existente. Ideal para cargar parciales, templates y contenido dinámico sin JavaScript de parsing.

ajaxSetup e interceptores
// Configuración global:
$.ajaxSetup({
  headers: {
    "X-CSRF-TOKEN": $('meta[name="csrf"]').attr("content")
  },
  timeout: 10000,
  dataType: "json"
});

// Interceptar TODAS las peticiones:
$(document).ajaxStart(function() {
  $("#spinner").show();
});

$(document).ajaxStop(function() {
  $("#spinner").hide();
});

$(document).ajaxError(function(e, xhr, settings) {
  if (xhr.status === 401) {
    window.location = "/login";
  }
  console.error("AJAX error:", settings.url);
});

$.ajaxSetup() define defaults para todas las peticiones AJAX (headers, timeout). Eventos globales: ajaxStart/ajaxStop (spinner global), ajaxError (tratamiento central de errores), ajaxSuccess. Ideales para el CSRF token, loading indicators y redirect en 401. Se aplican a todos los $.ajax(), $.get(), $.post().

Infinite scroll
var pagina = 1;
var carregando = false;
var fin = false;

$(window).on("scroll", function() {
  if (carregando || fin) return;

  var scrollFim = $(window).scrollTop() + $(window).height();
  var docAltura = $(document).height();

  if (scrollFim >= docAltura - 300) {
    carregando = true;
    pagina++;

    $.get("/api/posts", { page: pagina }, function(datos) {
      if (datos.length === 0) {
        fin = true;
        $("#feed").append('<p class="fin">Fin</p>');
        return;
      }
      datos.forEach(function(post) {
        $("#feed").append(renderizarPost(post));
      });
      carregando = false;
    });
  }
});

Infinite scroll: detectar la proximidad al fin de la página y cargar más. Las flags carregando y fin evitan peticiones duplicadas. Un margen de 300px para precargar. Una respuesta vacía = no hay más datos. Siempre throttle en el evento scroll por rendimiento. Alternativa moderna: IntersectionObserver (sin scroll listener).

Promises y $.when()
// jQuery 3+ (compatible con Promise):
$.get("/api/datos")
  .done(function(datos) { /* éxito */ })
  .fail(function(xhr) { /* error */ })
  .always(function() { /* sempre */ });

// then() (encadenable):
$.get("/api/users")
  .then(function(users) {
    return $.get("/api/posts/" + users[0].id);
  })
  .then(function(posts) {
    renderizar(posts);
  })
  .catch(function(error) {
    console.error(error);
  });

// Múltiples peticiones en paralelo:
$.when(
  $.get("/api/users"),
  $.get("/api/posts"),
  $.get("/api/comments")
).done(function(users, posts, comments) {
  // todos completos
});

jQuery 3+ retorna Promises compatibles. .done()/.fail()/.always() son los callbacks jQuery. .then() permite encadenar peticiones secuenciales. $.when() espera múltiples peticiones en paralelo. Cada argumento de done en $.when es un array [data, status, xhr]. Preferir then/catch para código moderno.

Tratamiento de errores
$.ajax({ url: "/api/datos" })
  .done(function(datos) {
    renderizar(datos);
  })
  .fail(function(xhr, status, error) {
    switch (xhr.status) {
      case 400:
        mostrarErros(xhr.responseJSON.errors);
        break;
      case 401:
        redireccionar("/login");
        break;
      case 404:
        alert("Recurso no encontrado");
        break;
      case 422:
        var errores = xhr.responseJSON;
        Object.keys(errores).forEach(function(campo) {
          $("#" + campo).addClass("error");
        });
        break;
      case 500:
        alert("Error no servidor");
        break;
    }
  });

xhr.status da el código de status HTTP. xhr.responseJSON es la respuesta JSON parseada (si dataType json). status (string): "success", "error", "timeout", "parsererror". Patrón: switch por código de status con mensajes específicos. 422 para errores de validación con mapeo por campo. Siempre tratar errores — nunca asumir éxito.

Formulários


11 cards
serialize() y serializeArray()
// serialize(): query string
var datos = $("form").serialize();
// "nombre=Ana&email=ana@mail.com&edad=25"

// serializeArray(): array de objetos
var arr = $("form").serializeArray();
// [{name: "nombre", value: "Ana"}, {name: "email", value: "ana@mail.com"}]

// Convertir a un objeto:
var obj = {};
$.each(arr, function(i, campo) {
  obj[campo.name] = campo.value;
});

// Solo campos específicos:
$("#form :input:not(:disabled)").serialize();

serialize() convierte todos los campos del form en una query string (listo para POST). serializeArray() retorna un array de {name, value}. Incluye solo campos con un name y no desactivados. Checkboxes/radios solo si están marcados. Ideal para enviar vía AJAX. No incluye file inputs (usar FormData).

Checkbox y radio
// Checkbox:
$("#termos").prop("checked");         // true/false
$("#termos").prop("checked", true);   // marcar
$("#termos").is(":checked");          // verificar

// Todos los marcados:
var marcados = $('input[name="tags"]:checked')
  .map(function() { return $(this).val(); })
  .get();  // ["js", "css"]

// Radio:
var opción = $('input[name="tipo"]:checked').val();

// Marcar un radio:
$('input[name="tipo"][value="admin"]').prop("checked", true);

// Select all / deselect all:
$("#select-all").on("change", function() {
  $(".checkbox-item").prop("checked", $(this).is(":checked"));
});

Para checkbox/radio, usar siempre prop("checked") (no attr). :checked filtra los marcados. .map().get() extrae los valores como array. Radio: :checked retorna el seleccionado del grupo. Patrón "select all": propagar el estado del checkbox maestro a todos los items.

Feedback visual de estado
// Estados de botón:
function setEstadoBoton($btn, estado) {
  $btn.prop("disabled", estado === "loading");
  $btn.html({
    idle: "Enviar",
    loading: '<span class="spinner"></span> A enviar...',
    success: "✓ Enviado!",
    error: "✗ Error — Tentar novamente"
  }[estado]);
  $btn.attr("class", "btn btn-" + estado);
}

// Uso:
setEstadoBoton($("#btn"), "loading");
$.post("/api/enviar", datos)
  .done(function() { setEstadoBoton($("#btn"), "success"); })
  .fail(function() { setEstadoBoton($("#btn"), "error"); });

Botones con estados: idle, loading, success, error. prop("disabled") impide el doble clic. Un objeto de mapeo para el HTML por estado. Una clase CSS por estado para el estilizado. Un spinner inline durante el loading. Un feedback visual claro mejora la UX. Revertir a idle tras un timeout en caso de error.

Validación básica
$("form").on("submit", function(e) {
  var errores = [];

  var nombre = $("#nombre").val().trim();
  if (nombre.length < 3) {
    errores.push("Nombre: mínimo 3 caracteres");
    $("#nombre").addClass("error");
  }

  var email = $("#email").val();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
    errores.push("Email inválido");
    $("#email").addClass("error");
  }

  if (errores.length > 0) {
    e.preventDefault();
    $("#errores").html(errores.map(function(e) {
      return "<li>" + e + "</li>";
    }).join(""));
  }
});

Validación client-side antes del submit. trim() quita espacios. Una regex para el email. addClass("error") destaca los campos inválidos. preventDefault() impide el envío si hay errores. Mostrar mensajes en un container. Complementar (no sustituir) la validación server-side. Limpiar errores en el input del campo.

Select dinámico
// Rellenar un select vía AJAX:
$("#país").on("change", function() {
  var paisId = $(this).val();
  var $ciudad = $("#ciudad");

  $ciudad.prop("disabled", true).html("<option>A cargar...</option>");

  $.get("/api/ciudades", { país: paisId }, function(datos) {
    var options = '<option value="">Seleccionar...</option>';
    datos.forEach(function(c) {
      options += '<option value="' + c.id + '">' + c.nombre + '</option>';
    });
    $ciudad.html(options).prop("disabled", false);
  });
});

// Leer el seleccionado:
var valor = $("#ciudad").val();
var texto = $("#ciudad option:selected").text();

Selects dependientes: cambiar uno carga las opciones del otro vía AJAX. Desactivar durante el loading. Reconstruir los <option> con la respuesta. val() retorna el value; option:selected + text() para el texto visible. Siempre incluir una opción vacía inicial. Limpiar el select dependiente cuando el padre cambia.

Autocomplete simple
var $input = $("#búsqueda");
var $lista = $("#sugestoes");
var timer;

$input.on("input", function() {
  var termo = $(this).val().trim();
  clearTimeout(timer);

  if (termo.length < 2) { $lista.hide(); return; }

  timer = setTimeout(function() {
    $.get("/api/sugestoes", { q: termo }, function(datos) {
      var html = datos.map(function(item) {
        return '<li data-id="' + item.id + '">' + item.nombre + '</li>';
      }).join("");
      $lista.html(html).show();
    });
  }, 250);
});

// Seleccionar una sugerencia (delegación):
$lista.on("click", "li", function() {
  $input.val($(this).text());
  $input.data("id", $(this).data("id"));
  $lista.hide();
});

// Cerrar al clicar fuera:
$(document).on("click", function(e) {
  if (!$(e.target).closest("#búsqueda, #sugestoes").length) {
    $lista.hide();
  }
});

Autocomplete: debounce + AJAX + una lista de sugerencias. data-id almacena el ID seleccionado. Delegación para clics en items dinámicos. Cerrar al clicar fuera con closest(). Un mínimo de 2 caracteres. Para accesibilidad: aria-autocomplete, navegación por teclado. Para producción, usar bibliotecas (Typeahead, Select2).

Validación en tiempo real
// Validar al salir del campo:
$("#email").on("blur", function() {
  var $campo = $(this);
  var válido = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test($campo.val());

  $campo.toggleClass("error", !válido);
  $campo.next(".msg-error").toggle(!válido);
});

// Limpiar el error al escribir:
$(".campo").on("input", function() {
  $(this).removeClass("error");
  $(this).next(".msg-error").hide();
});

// Validar la fuerza de la password:
$("#pass").on("input", function() {
  var forca = calcularForca($(this).val());
  $("#forca").css("width", forca + "%");
});

Validar en blur (al salir del campo) es menos intrusivo que en cada tecla. toggleClass(clase, boolean) añade/quita según una condición. Limpiar el error en input para feedback inmediato. Mensajes de error adyacentes (.next(".msg-error")). Un indicador de fuerza para passwords. Un balance entre UX y validación rigurosa.

Máscara de input
// Máscara de teléfono simple:
$("#telefono").on("input", function() {
  var v = $(this).val().replace(/\D/g, "");
  if (v.length > 9) v = v.slice(0, 9);

  if (v.length > 6) {
    v = v.replace(/(\d{3})(\d{3})(\d+)/, "$1 $2 $3");
  } else if (v.length > 3) {
    v = v.replace(/(\d{3})(\d+)/, "$1 $2");
  }
  $(this).val(v);
});

// Máscara de NIF (9 dígitos):
$("#nif").on("input", function() {
  $(this).val($(this).val().replace(/\D/g, "").slice(0, 9));
});

// Formatear al salir:
$("#precio").on("blur", function() {
  var v = parseFloat($(this).val()) || 0;
  $(this).val(v.toFixed(2));
});

Las máscaras formatean el input en tiempo real. replace(/\D/g, "") quita los no-dígitos. slice() limita la longitud. Una regex con grupos para insertar separadores. Formatear en blur para valores monetarios. Para máscaras complejas, usar plugins (jquery.mask, inputmask). Siempre validar en el servidor también.

Drag and drop básico
// Reordenar una lista (sin plugin):
var $arrastado = null;

$("#lista li").on("dragstart", function() {
  $arrastado = $(this);
  $(this).addClass("arrastando");
});

$("#lista li").on("dragend", function() {
  $(this).removeClass("arrastando");
  $arrastado = null;
});

$("#lista li").on("dragover", function(e) {
  e.preventDefault();
});

$("#lista li").on("drop", function() {
  if ($arrastado && $arrastado[0] !== this) {
    $(this).before($arrastado);
    // enviar el nuevo orden al servidor:
    var ordem = $("#lista li").map(function() {
      return $(this).data("id");
    }).get();
    $.post("/api/ordenar", { ordem: ordem });
  }
});

Drag and drop nativo HTML5 con jQuery. dragstart/dragend en el arrastrado. dragover + preventDefault() para permitir el drop. drop reposiciona con before(). map().get() extrae el nuevo orden. Para funcionalidad completa, usar jQuery UI Sortable. HTML: draggable="true" en los items.

Seleccionar y manipular campos
// Todos los campos de un form:
$("#form :input")  // input, select, textarea, button

// Por tipo:
$("#form input:text")     // type=text
$("#form input:password")
$("#form :checkbox")
$("#form :radio")
$("#form select")
$("#form textarea")

// Limpiar todos:
$("#form")[0].reset();
// o:
$("#form :input").val("").prop("checked", false);

// Desactivar/activar todos:
$("#form :input").prop("disabled", true);
$("#form :input").prop("disabled", false);

:input selecciona todos los campos (input, select, textarea, button). Filtros por tipo: :text, :checkbox, :radio. El reset() nativo restaura los valores iniciales. prop("disabled") en lote para bloquear formularios durante el procesamiento. val("") limpia el texto; prop("checked", false) desmarca.

Formulario multi-step
var passoActual = 1;
var totalPassos = $(".step").length;

function mostrarPasso(n) {
  $(".step").hide();
  $(".step").eq(n - 1).fadeIn(300);
  $("#progresso").text("Passo " + n + " de " + totalPassos);
  $("#btn-anterior").toggle(n > 1);
  $("#btn-siguiente").toggle(n < totalPassos);
  $("#btn-submit").toggle(n === totalPassos);
}

$("#btn-siguiente").on("click", function() {
  if (validarPasso(passoActual)) {
    passoActual++;
    mostrarPasso(passoActual);
  }
});

$("#btn-anterior").on("click", function() {
  passoActual--;
  mostrarPasso(passoActual);
});

mostrarPasso(1);

Un formulario en pasos: cada .step es una sección. eq(n-1) muestra el paso actual. fadeIn para la transición. Botones anterior/siguiente con toggle() condicional. Validar cada paso antes de avanzar. Una barra de progreso con texto o porcentaje. Enviar solo en el último paso.

Dicas e Boas Práticas


11 cards
Cache de selectores
// MALO: selecciona en cada uso
$("#menu").addClass("abierto");
$("#menu").find("li").show();
$("#menu").css("opacity", 1);

// BUENO: cache en una variable
var $menu = $("#menu");
$menu.addClass("abierto");
$menu.find("li").show();
$menu.css("opacity", 1);

// Convención: prefijo $ para objetos jQuery
var $lista = $("#lista");
var $ítems = $lista.find("li");
var $btn = $(".btn-submit");

// Re-seleccionar solo si el DOM cambió

Cada $() recorre el DOM — evitar repeticiones. Guardar en una variable con prefijo $ (convención). Reutilizar para múltiples operaciones. Re-seleccionar solo si el DOM fue modificado. find() en el cache es más rápido que un nuevo selector global. Impacto significativo en loops y handlers frecuentes.

Patrón módulo (IIFE)
// IIFE: Immediately Invoked Function Expression
(function($) {
  "use strict";

  var config = { velocidad: 300 };

  function init() {
    ligarEventos();
    loadData();
  }

  function ligarEventos() {
    $("#btn").on("click", handler);
  }

  function handler() {
    $("#painel").slideToggle(config.velocidad);
  }

  function loadData() {
    $.get("/api/datos", renderizar);
  }

  function renderizar(datos) { /* ... */ }

  // Iniciar cuando el DOM esté listo:
  $(init);

})(jQuery);

Un IIFE crea un ámbito privado — las variables no contaminan el global. Pasar jQuery como parámetro permite usar $ con seguridad (modo noConflict). "use strict" activa el modo estricto. Las funciones privadas son inaccesibles desde fuera. $(init) inicia cuando el DOM está listo. Patrón clásico de organización antes de los módulos ES6.

jQuery 3.x y migración
// Eliminado en jQuery 3:
// .load(), .unload(), .error() (atajos de eventos)
// → usar .on("load", fn)

// .bind()/.live()/.delegate() (deprecated)
// → usar .on()

// $.parseJSON() → JSON.parse()
// $.trim() → String.prototype.trim()
// $.type() → typeof / instanceof

// Nuevo en jQuery 3:
// .addClass() acepta una función
// Soporte de SVG
// requestAnimationFrame para animaciones
// Promises compatibles (then/catch)

// Plugin de migración:
// jquery-migrate (muestra warnings)

jQuery 3 eliminó métodos deprecated: atajos de eventos, .bind(), .live(). Sustituir por .on(). Utilidades como $.trim() tienen equivalentes nativos. jQuery 3 usa requestAnimationFrame (animaciones más suaves). Promises compatibles con el estándar. jquery-migrate ayuda en la transición (muestra warnings en la consola).

Delegación vs ligación directa
// Directo: solo elementos existentes
$("li").on("click", fn);
// 100 li = 100 handlers en memoria

// Delegación: 1 handler en el padre
$("#lista").on("click", "li", fn);
// 1 handler, funciona con futuros li

// Cuándo usar delegación:
// - Elementos dinámicos (AJAX)
// - Muchos elementos (rendimiento)
// - Listas, tablas, grids

// Cuándo usar directo:
// - Elementos estáticos y pocos
// - Eventos que no burbujean (focus, blur)
//   → usar focusin/focusout para delegación

Delegación: 1 handler en el padre vs N handlers en los hijos. Menos memoria, funciona con elementos futuros. Obligatorio para contenido dinámico (AJAX). focus/blur no burbujean — usar focusin/focusout para delegación. Para pocos elementos estáticos, la ligación directa es aceptable. Preferir delegación por defecto.

noConflict()
// Si otra librería usa $ (Prototype, etc.):
var jq = jQuery.noConflict();
jq("#caja").hide();

// O IIFE con jQuery:
(function($) {
  // $ es jQuery aquí dentro
  $("#caja").hide();
})(jQuery);

// Liberar $ Y jQuery:
var jq = jQuery.noConflict(true);

// Verificar disponibilidad:
if (typeof jQuery !== "undefined") {
  (function($) {
    // código jQuery seguro
  })(jQuery);
}

noConflict() libera la variable $ para otras librerías. noConflict(true) libera también jQuery. El patrón IIFE con (jQuery) permite usar $ internamente sin conflicto. Verificar typeof jQuery antes de usar (scripts condicionales). WordPress usa noConflict por defecto — siempre IIFE o jQuery().

jQuery vs Vanilla JS moderno
// jQuery → equivalente Vanilla:
$("#id")         → document.getElementById("id")
$(".clase")     → document.querySelectorAll(".clase")
$el.addClass("x") → el.classList.add("x")
$el.attr("href") → el.getAttribute("href")
$el.on("click")  → el.addEventListener("click")
$el.html("<p>")  → el.innerHTML = "<p>"
$.ajax()         → fetch()
$el.fadeIn()     → el.animate([{opacity:0},{opacity:1}])

// jQuery aún útil para:
// - Soporte de browsers antiguos (IE)
// - Ecosistema de plugins
// - Código legacy
// - Prototipado rápido

El Vanilla JS moderno cubre casi todo: querySelector, classList, fetch, Web Animations API. jQuery sigue siendo relevante para IE11, plugins y código legacy. fetch() sustituye $.ajax() (pero sin IE). Para proyectos nuevos sin IE, vanilla o frameworks son suficientes. jQuery no está muerto — pero no es obligatorio.

Evitar memory leaks
// MALO: quitar sin limpiar eventos
$("#widget").remove();  // remove() limpia (ok)

// MALO: innerHTML no limpia eventos jQuery
$("#container").html("");  // ok (jQuery limpia)
document.getElementById("c").innerHTML = "";  // LEAK!

// BUENO: limpiar antes de quitar
$("#widget").off().removeData().remove();

// Al destruir componentes:
function destruirModal() {
  $("#modal").off();           // eventos
  $("#modal").removeData();    // datos
  $("#modal").remove();        // DOM
  $(document).off("keydown.modal");  // namespace
}

// SPA: limpiar al cambiar de "página"

Memory leaks: eventos/datos huérfanos cuando el DOM se quita sin jQuery. El remove() y html() de jQuery limpian automáticamente. El innerHTML nativo NO limpia. off() + removeData() antes de quitar por seguridad. Los Namespaces facilitan la limpieza selectiva. Crítico en SPAs y componentes que crean/destruyen frecuentemente.

Plugins jQuery
// Crear un plugin:
$.fn.destacar = function(opciones) {
  var settings = $.extend({
    color: "yellow",
    bold: true
  }, opciones);

  return this.each(function() {
    $(this).css({
      backgroundColor: settings.color,
      fontWeight: settings.bold ? "bold" : "normal"
    });
  });
};

// Uso:
$("p").destacar();
$("p").destacar({ color: "#ff0", bold: false });

// Reglas:
// 1. Retornar this.each() (chaining)
// 2. $.extend para defaults + opciones
// 3. Prefijo $.fn para métodos de instancia

Los plugins extienden $.fn (el prototipo jQuery). return this.each() mantiene el chaining. $.extend() fusiona los defaults con las opciones del usuario. this dentro del plugin es el objeto jQuery (no DOM). Aceptar un objeto de opciones para flexibilidad. Plugins populares: Slick, Select2, DataTables, Magnific Popup.

Checklist de rendimiento
// 1. Cache de selectores
var $el = $("#caja");  // no repetir $()

// 2. Delegación en vez de N handlers
$("#lista").on("click", "li", fn);

// 3. Batch DOM (1 inserción vs loop)
var html = items.map(render).join("");
$("#lista").html(html);

// 4. Throttle/debounce en scroll/resize
$(window).on("scroll", throttle(fn, 100));

// 5. Selectores específicos
$("#form").find("input")  // rápido
$("form input")           // más lento

// 6. Evitar layout thrashing
var w = $el.width();     // leer
$el.width(w + 10);       // escribir (1x)

// 7. Eliminar lo que no se usa
$el.off().removeData().remove();

Resumen de rendimiento: cache, delegación, batch DOM, throttle, selectores específicos. Layout thrashing: alternar lectura/escritura de dimensiones causa múltiples reflows — agrupar lecturas y escrituras. find() con contexto es más rápido que un selector global. Limpiar eventos/datos al eliminar. Herramientas: la pestaña Performance de Chrome DevTools para identificar bottlenecks.

Throttle y debounce
// Debounce: espera a que pare (búsqueda)
function debounce(fn, delay) {
  var timer;
  return function() {
    var ctx = this, args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(ctx, args);
    }, delay);
  };
}
$(window).on("resize", debounce(recalcular, 250));

// Throttle: como máximo 1x por intervalo (scroll)
function throttle(fn, limite) {
  var última = 0;
  return function() {
    var ahora = Date.now();
    if (ahora - última >= limite) {
      última = ahora;
      fn.apply(this, arguments);
    }
  };
}
$(window).on("scroll", throttle(verificarPosicao, 100));

Debounce: se ejecuta tras N ms de inactividad (búsqueda, resize). Throttle: como máximo 1 ejecución por intervalo (scroll, mousemove). Sin estos, los eventos se disparan cientos de veces/segundo. apply(ctx, args) preserva el contexto. Esenciales para el rendimiento en eventos de alta frecuencia. Librerías: lodash tiene ambos.

$.extend() y $.each()
// $.extend(): merge de objetos
var defaults = { color: "azul", tamano: 12, activo: true };
var opciones = { color: "rojo", tamano: 16 };
var final = $.extend({}, defaults, opciones);
// { color: "rojo", tamano: 16, activo: true }

// Deep merge (nested):
$.extend(true, {}, obj1, obj2);

// $.each(): iterar arrays/objetos
$.each([10, 20, 30], function(i, valor) {
  console.log(i, valor);
});

$.each({ nombre: "Ana", edad: 25 }, function(clave, valor) {
  console.log(clave + ": " + valor);
});

// Nota: $.each ≠ .each() (método de colección)

$.extend() fusiona objetos (el primero es el target). {} como primero evita mutar los defaults. true para un deep merge (objetos nested). $.each() itera arrays (i, valor) y objetos (clave, valor). Diferente de .each() que es un método de colección jQuery. Ambos son utilidades estáticas ($.).