6. jQuery
A día de hoy, podemos asegurar que jQuery (http://jquery.com) es la librería JavaScript más utilizada ya que facilita mucho el trabajo del desarrollador. Su lema de write less, do more (escribe menos, haz más) resume su propósito.
6.1. Por qué usar jQuery
Entre sus características podemos destacar que:
-
es software libre y gratuito, lo que ha facilitado su implantación.
-
funciona en todos los navegadores modernos
-
abstrae las prestaciones que ofrece cada navegador, lo que permite que nuestro código se centre en el diseño más que en la plataforma de ejecución
-
se centra en simplificar las tareas de scripts comunes como:
-
manipular el contenido de un documento web
-
gestionar los eventos con independencia del navegador
-
añadir atractivos efectos y transiciones.
-
-
facilita los escenarios de trabajo más comunes como:
-
gestionar las configuraciones que se realizan al cargar una página
-
tras un evento, obtener y manipular/animar el contenido para volverlo a mostrar en la página.
-
-
aprovecha el conocimiento que ya poseemos de CSS, al utilizar la misma sintaxis de selectores
-
trabaja con conjuntos de elementos, permitiéndonos realizar una acción sobre más de un elemento DOM de manera simultánea
-
permite realizar múltiples operaciones sobre un conjunto de elementos mediante una única línea de código, mediante el encadenamiento de sentencias (statement chaining).
-
es extensible mediante multitud de plugins de terceros, o si queremos, mediante plugins de nuestra propia creación
6.2. Versiones
Si accedemos a la página de jQuery (http://jquery.com) podemos descargar dos versiones: la versión 1.12.1 y la 2.2.1. La principal diferencia es que la versión 2.x deja de dar soporte a las versiones 6, 7 y 8 de Internet Explorer.
Además, a la hora de descargar la versión en la que estemos interesados, podemos bajar uno de los dos siguientes scripts:
-
un script que no está comprimido y que nos permite consultar el código, pero que ocupa más (este es el que usaremos en el módulo)
-
el que está comprimido (minificado) y que se usa en producción para reducir la carga de la página.
Por ejemplo, si nos centramos en la versión 1.12.1
, la versión de desarrollo ocupa 287KB mientras que la minificada sólo ocupa 95KB, es decir, casi tres veces más.
Si no queremos descargarla, podemos usar cualquiera de los CDNs que más nos interese:
-
jQuery:
<script src="//code.jquery.com/jquery-1.12.1.min.js"></script>
-
Google:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
-
CDNJS:
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
Así pues, una vez elegida la versión que mejor nos convenga, la incluiremos dentro de nuestro código, teniendo en cuenta que deberíamos cargarla tras los archivos CSS y antes de todas las librerías que dependan de jQuery:
<link rel="stylesheet" type="text/css" href="estilos.css" />
<script src="jquery.js" />
<script src="libQueUsaJQuery.js" />
En todos los ejemplos que veremos en esta sesión y las posteriores damos por supuesto que se ha incluido correctamente la librería de jQuery. |
6.3. Alias: jQuery
por $
Así pues, uno de los puntos fuertes de jQuery es que reduce el número de instrucciones que usaríamos con JavaScript:
document.getElementById("miCapa").className = "resaltado";
jQuery("#miCapa").addClass("resaltado");
Además de ser más corto, jQuery nos permitirá acceder a un elemento sin hacerlo por su ID (por ejemplo, por su clase CSS, por el tipo de etiqueta HTML, …) y filtrar los resultados del selector.
Para reducir el tamaño del código, en vez de utilizar todo el rato la función jQuery
, se utiliza el alias $
que viene predefinido en la librería:
$("#miCapa").addClass("resaltado");
Así pues, tras el $
, rodeado por paréntesis le pasaremos el selector del elemento sobre el que queremos trabajar, para posteriormente encadenar la acción a realizar sobre la selección.
Si utilizamos otras librerías JavaScript que también utilice el $
, se recomienda realizar una llamada a $.noConflict()
para evitar conflictos de namespace. Tras la llamada, el alias $
deja de estar disponible, obligándonos a escribir jQuery
cada vez que escribiríamos $
.
Permitiendo otro alias
Tal como hemos visto, es recomendable agrupar las instrucciones dentro de una función expresión de invocación inmediata. Si ademas queremos permitir que fuera de esta función se use el alias
Otra manera es usando el evento
|
6.4. Seleccionando contenido
Sin duda, una de las operaciones que más vamos a realizar con jQuery es recuperar contenido, mediante selectores y filtros, sobre el cual posteriormente realizaremos alguna acción.
El resultado de aplicar un selector siempre va a ser un array de objetos (no son objetos DOM, sino objetos jQuery que envuelven a los objetos DOM añadiéndoles funcionalidad extra) que cumplen el criterio de la consulta. Posteriormente, podemos aplicar un filtro sobre un selector para refinar el array de resultados que devuelve.
6.4.1. Selectores
Los selectores y filtros que usa jQuery se basan en la sintaxis de CSS. Para aplicar un selector, le tenemos que pasar el selector como un parámetro entre comillas a la función jQuery
, o mejor, a su alias $
, del siguiente modo:
$('selector');
Si queremos restringir el contexto de aplicación del selector para evitar realizar la búsqueda sobre el documento DOM completo, le podemos pasar el contexto como segundo parámetro:
$('selector', contexto);
Si el contexto que le pasamos contiene muchos elementos, cada elemento se utiliza como punto de inicio en la búsqueda del selector.
De este modo, obtendríamos resultados diferentes:
$('p:even'); (1)
$('p:even', $('.importante')); (2)
1 | Obtiene los párrafos pares |
2 | Dentro de los elementos cuya clase es importante, obtendría los párrafos pares |
Si únicamente queremos restringir la búsqueda a un elemento lo mejor es buscar el elemento por su id y pasarle como contexto el HTMLElement
:
var contenido = document.getElementById("contenido");
$('p:even', contenido);
Hay que intentar minimizar las llamadas a DOM para mejorar el rendimiento. Si podemos sacar a una variable la referencia al elemento que queremos trabajar ahorraremos llamadas jQuery. |
Básicos
A continuación tenemos los selectores que son exactamente igual que en CSS:
Selector | Propósito | Ejemplo |
---|---|---|
etiqueta |
Encuentra todos los elementos de etiqueta |
|
#identificador |
Encuentra el elemento cuyo |
|
.nombreClase |
Encuentra todos los elementos cuyo |
|
etiqueta.nombreClase |
Encuentra todos los elementos de tipo etiqueta cuyo |
|
etiqueta#ident.nombreClase |
Encuentra el elemento de tipo etiqueta cuyo |
|
* |
Encuentra todos los elementos de la página |
|
Para poder probar todos estos selectores vamos a basarnos en la siguiente página:
<!DOCTYPE html>
<html>
<head lang="es">
<meta charset="UTF-8">
<title>Selectores</title>
<style>
.a { color: red; }
.b { color: gold; }
</style>
</head>
<body>
<ul id="listado">
<li class="a">elemento 0</li>
<li class="a">elemento 1</li>
<li class="b">elemento 2</li>
<li class="b">elemento 3</li>
</ul>
<p id="pa0" class="a" lang="es-AR">Párrafo 0</p>
<p>Párrafo 1</p>
<p id="pa2" class="b">Párrafo 2</p>
<p id="pa3" lang="es-ES">Párrafo 3</p>
</body>
</html>
La cual se visualiza del siguiente modo:
Y ahora vamos a comparar como lo haríamos mediante DOM y como con jQuery (http://jsbin.com/modiko/6/edit?html,css,js,output) en los siguientes ejemplos:
document.getElementsByTagName("p");
$("p");
listado
document.getElementById("listado");
$("#listado");
li
cuya clase sea a
:var todos = document.getElementsByTagName("li"); (1)
var liClaseA = [];
for (var i = 0, tam = todos.length; i < tam; i++) {
if (todos[i].className === "a") {
liClaseA.push(todos[i]);
}
}
$("li.a"); // jQuery
1 | Mediante DOM tenemos que recuperar todas las etiquetas, recorrerlas como un array y seleccionar los elementos deseados |
b
, pero solo si están dentro de un lista desordenadavar todos = document.getElementsByTagName("ul"); (1)
...
...
$("ul .b"); // jQuery
1 | Mediante DOM tenemos que recuperar todas las etiquetas, recuperar sus hijos, nietos, etc… y ver si alguno tiene dicha clase |
Jerárquicos
Además de los selectores básicos, podemos hacer consultas dependiendo de las relaciones jerárquicas o una serie de criterios comunes, mediante la siguiente sintaxis:
Selector | Propósito | Ejemplo |
---|---|---|
selector1, selector2, … |
Encuentra todos los selectores especificados |
|
.clase1.clase2 |
Encuentra todos los elementos cuya |
|
padre > hijo |
Encuentra todos los elementos hijo que son hijos directos del tipo padre |
|
ascendiente descendiente |
Encuentra todos los elementos descendiente contenidos dentro del tipo ascendiente |
|
anterior + posterior |
Encuentra todos los elementos posterior que están después de anterior |
|
anterior ~ hermanos |
Encuentra todos los hermanos (siblings) que están tras anterior y que cumplen el selector de hermanos |
|
Y algunos ejemplos con estos selectores (http://jsbin.com/modiko/6/edit?html,css,js,output):
b
:$("p, li.b");
a
y que sean descendientes de una lista desordenada:$("ul li.a");
$("ul + p"); // párrafo 0
listado
:$("#listado ~ p"); // párrafo 0
6.4.2. Filtros
Los filtros trabajan de manera conjunta con los selectores para ofrecer un control todavía más preciso a la hora de seleccionar elementos del documento.
Comienzan con :
, y se pueden encadenar para crear filtros complejos, como por ejemplo:
$("#noticias tr:has(td):not(:contains('Java'))");
Básicos
Permiten refinar la selección con los elementos que cumplen condiciones relativas a la posición que ocupan o un determinado índice:
Filtro | Propósito |
---|---|
:first |
Selecciona sólo la primera instancia del conjunto devuelto por el selector |
:last |
Selecciona sólo la última instancia del conjunto devuelto por el selector |
:even |
Selecciona sólo los elementos pares del conjunto devuelto por el selector |
:odd |
Selecciona sólo los elementos impares del conjunto devuelto por el selector |
:eq(n) |
Selecciona los elementos situados en el índice n |
:gt(n) |
Selecciona los elementos situados detrás del índice n |
:lt(n) |
Selecciona los elementos situados antes del índice n |
:header |
Selecciona todos los elementos cabeceras ( |
:animated |
Selecciona todos los elementos que están actualmente animados de alguna manera |
:not(selector) |
Selecciona los elementos que no cumplen el selector |
Y algunos ejemplos con estos filtros (http://jsbin.com/hufido/1/edit?html,css,js,output):
$("p:first");
a
$(".a:last");
$("p:even");
$("p:gt(1)");
$("p:not(p:eq(1))");
Basados en los Atributos
Permiten refinar la selección con los elementos que cumplen condiciones relativas al contenido de los atributos:
Filtro | Propósito |
---|---|
[atrib] |
Incluye los elementos que tienen el atributo atrib |
[atrib=valor] |
Incluye los elementos que tienen el atributo atrib con el valor valor |
[atrib!=valor] |
Incluye los elementos que tienen el atributo atrib y no tiene el valor valor |
[atrib^=valor] |
Incluye los elementos que tienen el atributo atrib y su valor comienza por valor |
[atrib$=valor] |
Incluye los elementos que tienen el atributo atrib y su valor termina con valor |
[atrib*=valor] |
Incluye los elementos que tienen el atributo atrib y su valor contiene valor |
[filtroAtrib1][filtroAtrib2] |
Incluye los elementos que cumplen todos los filtros especificados, es decir, filtroAtrib1 y filtroAtrib2 |
Y algunos ejemplos con estos filtros (http://jsbin.com/ziraqe/1/edit?html,css,js,output):
$("p[class]");
pa2
$("p[id=pa2]");
pa
$("p[id^=pa]");
pa
y que su atributo lang
contenga es
$("p[id^=pa][lang*=es]");
Basados en el Contenido
Permiten refinar la selección con los elementos que cumplen condiciones relativas a su contenido:
Filtro | Propósito |
---|---|
:contains(texto) |
Incluye los elementos que contienen la cadena texto |
:empty |
Incluye los elementos vacíos, es decir, sin contenido |
:has(selector) |
Incluye los elementos que contienen al menos uno que cumple el selector |
:parents |
Incluye los elementos que son padres, es decir, que contienen al menos otro elemento, incluido texto |
Y algunos ejemplos con estos filtros (http://jsbin.com/runojo/1/edit?html,css,js,output):
$("p:contains(3)");
$(":contains(3)"); (1)
$("p:contains(3),li:contains(3)"); (2)
1 | Selecciona los que contienen un 3, y sus padres, ya que por ejemplo, el elemento body contiene un 3 dentro de un párrafo, con lo cual no sería una solución correcta |
2 | Restringimos la búsqueda sobre los elementos que conocemos. Para hacerlo correctamente deberíamos seleccionar todos aquellos que fueran hijos |
$("p:parent");
b
$("ul:has(li[class=b])");
Basados en la Visibilidad
Permiten refinar la selección con los elementos que cumplen condiciones relativas a la propiedad visibility
:
Filtro | Propósito |
---|---|
:visible |
Incluye los elementos visibles |
:hidden |
Incluye los elementos ocultos |
Y un ejemplo:
$("p:hidden");
Basados en los Hijos
Permiten refinar la selección examinando la relación que cada elemento tiene con su elemento padre:
Filtro | Propósito |
---|---|
:nth-child(índice) |
Incluye los hijos número índice, numerados de 1 a n. |
:nth-child(even) |
Incluye los hijos pares |
:nth-child(odd) |
Incluye los hijos impares |
:nth-child(ecuación) |
Incluye los hijos cuya posición cumple la ecuación, por ejemplo, |
:first-child |
Incluye los elementos que son el primer hijo |
:last-child |
Incluye los elementos que son el último hijo |
:only-child |
Incluye los elementos que son hijos únicos, es decir, no tienen hermanos |
Y algunos ejemplos con estos filtros:
$("ul li:nth-child(3)");
$("ul li:last-child");
Basados en los Elementos del Formulario
Aunque se consideran como selectores de formulario, se expresan como filtros y permiten refina los campos dependiendo del tipo de elemento:
Selector | Propósito |
---|---|
:input |
Encuentra todos los input, select, textarea y elementos button |
:text |
Encuentra todos los elementos de dicho tipo |
:password |
|
:radio |
|
:checkbox |
|
:submit |
|
:reset |
|
:image |
|
:button |
|
:file |
Y para realizar filtrados adicionales sobre los elementos, podemos usar los siguientes filtros de manera conjunta a los anteriores:
Filtro | Propósito |
---|---|
:enabled |
Incluye los elementos que están habilitados |
:disabled |
Incluye los elementos que están deshabilitados |
:checked |
Incluye los elementos que están marcados (radio y checkbox) |
:selected |
Incluye los elementos que están seleccionados (select) |
Y algunos ejemplos con estos filtros:
$("form :input");
$("form :text:enabled");
$("form :checkbox:checked");
6.4.3. El objeto jQuery
Tras seleccionar la información mediante selectores y filtros obtendremos un objeto jQuery
, el cual envuelve a uno o más elementos HTML.
A partir de este objeto vamos a poder acceder al resultado, iterar sobre él o encadenar nuevas sentencias.
Las propiedades y métodos que soporta un objeto jQuery
son:
Propiedad / Método | Propósito | Devuelve |
---|---|---|
context |
Devuelve el conjunto de elementos utilizado como contexto |
|
each(función) |
Invoca la función para cada uno de los elementos buscados |
|
find(selector) |
Obtiene elementos descendientes que cumplen el selector |
|
get() / toArray() |
Devuelve un array con todos los elementos DOM del conjunto de resultado. Se usa cuando necesitamos trabajar con los objetos DOM en vez de los objetos propios de jQuery |
|
get(índice) |
Obtiene un único elemento DOM que ocupa la posición índice del conjunto de resultados |
|
index(HTMLElement) |
Obtiene el indice del HTMLElement especificado |
|
index(jQuery) |
Obtiene el indice del primer elemento del objeto jQuery |
|
index(selector) |
Obtiene el indice del primer elemento del objeto jQuery dentro del conjunto de elementos encontrados por el selector. Realiza la operación inversa a las anteriores |
|
length / size() |
Número de elementos del conjunto de resultados |
|
selector |
Devuelve el selector empleado |
|
Destacar que los métodos index()
son los complementarios a get()
, de modo que en get()
se indica un índice y se obtiene un HTMLElement
, y el index()
a partir del elemento se obtiene el índice.
Vamos a practicar estos métodos con algunos ejemplos:
var parrafosImpares = $("p:odd");
console.log(parrafosImpares.selector); // "p:odd"
var numParrafos = $("p").length;
$("li").get()[0]; // object HTMLLIElement -> objeto DOM
$("li").get(0); // object HTMLLIElement -> objeto DOM
$("li:first-child"); // object Object -> objeto jQuery
$("body *").index(document.getElementById("contenido"));
$("body *").index($("#contenido"));
$("#contenido").index("body *");
b
$("ul").find("li.b");
$("ul li.b");
$("p").each(function() {
// Por ejemplo, ponerles un borde
$(this).css("border","3px solid red");
});
De HTMLElement
a jQuery
Si tenemos un objeto DOM y queremos crear un objeto jQuery
, podemos hacerlo pasándolo como argumento a la función $
. De este modo podemos incluir código que no usa jQuery e integrarlo de un modo sencillo.
var contenido = document.getElementById("contenido");
var contenidoJQuery = $(contenido);
6.4.4. Modificando la selección
Una vez seleccionada la información mediante selectores y filtros, vamos a poder modificarla añadiendo nuevos elementos al conjunto de resultados o restringiendo los resultados a un subconjunto menor.
Encadenando sentencias
Una de las características más potentes de jQuery es su habilidad de encadenar múltiples sentencias de manera conjunta para realizar varias operaciones en una única línea de código.
Para ello, tras usar el selector, mediante el operador .
podemos añadir métodos que se irán encadenando unos detrás de otros:
$(selector).funcion1().funcion2().funcion3();
Al encadenar las sentencias, los métodos se ejecutan sobre el elemento modificado. Si queremos que dentro del chaining vuelva a trabajar con la selección inicial, podemos usar end()
.
$(this).siblings('button').removeAttr('disabled').end().attr('disabled','disabled');
Todos los métodos que veremos a continuación devuelven un objeto jQuery, para permitir el encadenamiento de sentencias.
Expandiendo la selección
El método add
permite ampliar la selección añadiendo elementos al conjunto de resultados:
Método | Propósito |
---|---|
add(selector) |
Añade todos los elementos que cumplen el selector |
add(selector, contexto) |
Añade todos los elementos que cumplen el selector dentro del contexto |
add(HTMLElement) |
Añade un elemento o un array de HTMLElements |
add(HTMLElement[]) |
|
add(jQuery) |
Añade los contenidos del objeto jQuery |
Por ejemplo, podemos obtener un selector para posteriormente reutilizarlo sobre otra selección:
var imgFlickr = $("img[src*=flickr]");
$("img:even").add("img[src*=twitpic]").add(imgFlickr);
Reduciendo la selección
Si lo que queremos es reducir el conjunto de resultados para refinar la selección, podemos utilizar los siguientes métodos similar a los empleados en los filtros:
Método | Propósito |
---|---|
eq(índice) |
Elimina todos los elementos a excepción al que ocupa la posición índice . Si el indice es negativo, cuenta desde el final. |
first() |
Elimina todos los elementos excepto el primero |
has(selector) |
Elimina los elementos que no tengan un descendiente que cumpla el selector o el objeto jQuery o aquellos descendientes que no incluyan los objetos HTMLElement especificados |
has(jQuery) |
|
has(HTMLElement) |
|
has(HTMLElement[]) |
|
last() |
Elimina todos los elementos excepto el último |
slice(inicio, fin) |
Elimina los elementos fuera del rango indicado por los valores de inicio y fin |
Por ejemplo, mediante los operadores sencillos podemos restringir el conjunto de resultados (http://jsbin.com/hufoci/1/edit?html,css,js,output):
$("li").first();
$("li").last();
$("li").eq(1); // segundo elemento
$("li").eq(-1); // último elemento
$("li").slice(0,2); // primeros dos elementos
Otros métodos que permiten restringir el resultado son filter()
y not()
, los cuales son complementarios:
Método | Propósito |
---|---|
filter(selector) |
Mantiene todos los elementos que cumplen el selector |
filter(HTMLElement) |
Elimina todos los elementos menos el HTMLElement |
filter(jQuery) |
Elimina todos los elementos que no están contenidos en el objeto jQuery |
filter(función(índice)) |
La función se invoca por cada elemento; aquellos en los que la función devuelva |
not(selector) |
Elimina los elementos que cumplen el selector |
not(HTMLElement[]) |
Elimina los elementos del array |
not(HTMLElement) |
Elimina el elemento especificado |
not(jQuery) |
Elimina los elementos contenidos en el objeto jQuery |
not(función(índice)) |
La función se invoca por cada elemento; aquellos en los que la función devuelva |
Por ejemplo (http://jsbin.com/dahuvu/1/edit?html,css,js,output):
$("p").filter("[class]")
$("p").not("[class]");
var pa = $("[id^=pa]");
$("p").filter(pa);
$("p").not(pa);
$("p").filter(function(indice) {
return this.getAttribute("class") == "a" || indice == 2;
});
6.5. Navegando por la selección
Una vez tenemos la selección de elementos con la que queremos trabajar podemos navegar (traversing) desde la selección empleando las relaciones DOM entre los elementos.
6.5.1. Navegación descendiente
Para navegar descendentemente podemos emplear los siguientes métodos:
Método | Propósito |
---|---|
children() |
Selecciona los hijos (descendientes inmediatos) de todos los elementos del conjunto de resultados |
children(selector) |
Selecciona todos los elementos que cumplen el selector y que son hijos del conjunto de resultados |
contents() |
Devuelve los hijos, incluyendo los contenidos de texto u nodos de comentarios de todos los elementos |
El uso de las relaciones DOM suele emplearse con el método find()
(ver El objeto jQuery
) para buscar un selector entre los descendientes de la selección. Además, en ambos casos no se devuelven elementos duplicados.
Por ejemplo, podemos recorrer todos los hijos de un selector de este modo:
var numHijos = $("ul").children().each(
function(indice, elem) {
console.log(elem.tagName + " - " + elem.className);
}
).length;
6.5.2. Navegación ascendente
Si en cambio estamos interesados en los elementos que están por encima de nuestro conjunto de resultados usaremos los siguientes métodos:
Método | Propósito |
---|---|
parent() |
Selecciona el padre de cada elemento del objeto jQuery, pudiéndose filtrar por el selector |
parent(selector) |
|
parents() |
Selecciona los ascendentes de cada elemento del objeto jQuery, pudiéndose filtrar por el selector |
parents(selector) |
|
parentsUntil(selector1) |
Selecciona los ascendentes de cada elemento del objeto jQuery hasta que se encuentre una ocurrencia para el selector1. Los resultados se pueden filtrar mediante selector2. |
parentsUntil(selector1, selector2) |
|
parentsUntil(HTMLElement) |
Selecciona los ascendentes de cada elemento del objeto jQuery hasta que se encuentre uno de los elementos especificados. Los resultados se pueden filtrar mediante un selector. |
parentsUntil(HTMLElement, selector) |
|
parentsUntil(HTMLElement[]) |
|
parentsUntil(HTMLElement[], selector) |
|
closest(selector) |
Selecciona el ascendente más cercano de cada elemento del objeto jQuery y realiza la intersección con el selector / contexto. |
closest(selector, contexto) |
|
closest(jQuery) |
Selecciona el ascendente más cercano de cada elemento del objeto jQuery y realiza la intersección con los elementos contenidos en el parámetro. |
closest(HTMLElement) |
|
offsetParent() |
Encuentra el ascendente posicionado más cercano (tiene valor |
Algunos ejemplos con estos métodos:
lang
$("a").parent();
$("a").parent("[lang]");
a
$(".a").parents();
form
de los elementos cuya clase sea a
y que contenga el valor es
en el atributo lang
$(".a").parentsUntil('form','[lang*=es]');
a
, de la imagen cuya fuente referencie a flickr$("img[src*=flickr]").closest(".a");
6.5.3. Navegación horizontal
Finalmente, si lo queremos es navegar entre los elementos que están en el mismo nivel, podemos utilizar los siguientes métodos:
Método | Propósito |
---|---|
siblings() |
Selecciona todos los hermanos (anteriores y posteriores) para cada uno de los elementos del objeto |
next() |
Selecciona el hermano inmediatamente posterior para cada elemento del objeto jQuery. |
nextAll() |
Selecciona todos los hermanos posteriores para cada elemento del objeto jQuery, pudiéndose filtrar por el selector |
nextUntil(selector) |
Selecciona los hermanos anteriores para cada elemento hasta (sin incluir) un elemento que cumpla el selector o un elemento del objeto |
nextUntil(jQuery) |
|
nextUntil(HTMLElement[]) |
|
prev() |
Selecciona el hermano inmediatamente anterior para cada elemento del objeto |
prevAll() |
Selecciona todos los hermanos anteriores para cada elemento del objeto |
prevUntil(selector) |
Selecciona los hermanos anteriores para cada elemento hasta (sin incluir) un elemento que cumpla el selector o un elemento del objeto |
prevUntil(jQuery) |
|
prevUntil(HTMLElement[]) |
Todos estos métodos aceptan un segundo parámetro opcional con un selector para filtrar resultados. |
6.6. Manipulando contenido
Una vez seleccionados los elementos con los que queremos trabajar mediante el uso de selectores y filtros, llega el momento de manipular su contenido.
En ocasiones crearemos contenido de manera dinámica, de modo que jQuery nos ofrece métodos para crear, copiar, borrar y mover contenido, además de permitir envolver contenido dentro de otro.
Además, jQuery ofrece soporte Cross-Browser para trabajar con CSS, incluyendo información sobre posicionamiento y tamaño.
6.6.1. Creando contenido
Para crear nuevo contenido, no tenemos más que pasarle una cadena con el código HTML a la función $()
var nuevoEncabezado = $("<h1>Encabezado Nivel 1</h1>");
También podemos hacerlo mediante los siguientes métodos:
Método | Propósito |
---|---|
html() |
Devuelve el contenido HTML del primer elemento del conjunto de resultados |
html(nuevoContenido) |
Asigna el nuevoContenido HTML a todos los elementos del conjunto de resultados |
text() |
Devuelve el contenido de todos los elemento del conjunto de resultados |
text(nuevoTexto) |
Asigna el nuevoTexto a todos los elementos del conjunto de resultados |
La principal diferencia entre html(contenido) y text(contenido) es que si pasamos código HTML al método text() , éste escapará los símbolos de < y > .
|
Vamos a practicar estos métodos con algunos ejemplos:
console.log($("#listado").html()); // <li class="a">elemento 0.......elemento 3</li>
console.log($("#listado").text()); // elemento 0 elemento 1 ... elemento 3
console.log($("li").html()); // elemento 0
console.log($("li").text()); // elemento 0elemento 1elemento 2elemento 3
$("#listado").html("<li>Nuevo elemento mediante jQuery</li>");
console.log($("#listado").html()); // <li>Nuevo elemento mediante jQuery</li>
$("p:first").html("Este es el primer párrafo con <br /> en medio");
$("p:last").text("Este es el último párrafo con <br /> en medio");
Como podemos observar, al asignar nuevo contenido estamos eliminando el contenido previo y sustituyéndolo por el nuevo, pero manteniendo los atributos de la etiqueta sobre la que se añade el contenido.
6.6.2. Trabajando con valores
Una vez hemos seleccionado elementos que forman parte de un formulario, podremos obtener o modificar sus valores mediante el método val()
:
Método | Propósito |
---|---|
val() |
Devuelve el valor del primer elemento del conjunto de resultados |
val(valor) |
Asigna el valor a todos los elementos del conjunto de resultados |
val(función) |
Asigna valores a todos los elementos del conjunto de resultados mediante la función |
Por ejemplo:
$("input").each(function(indice, elem) {
console.log("Nombre: " + elem.name + " Valor: " + $(elem).val());
});
$("input").val(function(indice, valorActual) {
return (indice + 1) * 100;
});
6.6.3. Trabajando con atributos
Para inspeccionar o modificar el valor de los atributos de los elementos usaremos el método attr
.
Método | Propósito |
---|---|
attr(nombre) |
Accede a la propiedad del primero elemento del conjunto de resultados. Éste método facilita obtener el valor de propiedades. Si el elemento no tiene un atributo con dicho nombre, devuelve |
attr(objetoPropiedades) |
Asigna una serie de atributos en todos los elementos del conjunto de resultado mediante la sintaxis de notación de objeto, lo que permite asignar un gran número de propiedades de una sola vez
|
attr(clave, valor) |
Asigna valor a la propiedad clave a todos los elementos del conjunto de resultados |
attr(clave, función) |
Asigna una única propiedad a un valor calculado para todos los elementos del conjunto de resultados. En vez de pasar un valor mediante una cadena, la función devolverá el valor del atributo. |
removeAttr(nombre) |
Elimina el atributo nombre de todos los elementos del conjunto de resultados |
Vamos a estudiar algunos ejemplos, suponiendo que tenemos un enlace con una imagen del siguiente modo:
<a href="imagenes/logo.jpg"><img src="imagenes/logo.jpg" alt="logo" /></a>
$("a").attr("target","_blank");
$("a").removeAttr("href");
$("img").attr({src:"imagenes/batman.jpg", alt:"Batman"});
6.6.4. Insertando contenido
jQuery ofrece varios métodos para insertar nuevo contenido en el documento, tanto antes como después del contenido de los elementos de la página.
Método | Propósito |
---|---|
append(contenido) |
Anexa contenido (al final) dentro de cada elemento del conjunto de resultados |
appendTo(selector) |
Traslada todos los elementos del conjunto de resultados detrás de los encontrados por el selector |
prepend(contenido) |
Añade contenido (al inicio) dentro de cada elemento del conjunto de resultados |
prependTo(selector) |
Traslada todos los elementos del conjunto de resultados delante de los encontrados por el selector |
El contenido de los métodos puede ser contenido HTML, un objeto jQuery
, un array de HTMLElement
o una función que devuelva el contenido.
Supongamos que partimos del siguiente fragmento:
<p>Párrafo 1</p>
<p>Párrafo 2</p>
$("p").append(" con nuevo contenido anexado");
// <p>Párrafo 1 con nuevo contenido anexado</p>
// <p>Párrafo 2 con nuevo contenido anexado</p>
$("p").prepend("Nuevo contenido en el ");
// <p>Nuevo contenido en el Párrafo 1</p>
// <p>Nuevo contenido en el Párrafo 2</p>
$("p:last").prependTo("p:first");
// <p>Párrafo 2</p>
// <p>Párrafo 1</p>
Autoevaluación
Suponiendo que tenemos una capa que contiene una capa con artículos ¿Qué realiza el siguiente código ? [1]
|
Si queremos que el contenido se situe antes o después de ciertos elementos (y no dentro de los seleccionados), hemos de emplear los siguiente métodos:
Método | Propósito |
---|---|
after(contenido) |
Inserta el contenido detrás de cada elemento del conjunto de resultados |
before(contenido) |
Inserta el contenido antes de cada elemento del conjunto de resultados |
insertAfter(selector) |
Inserta todos los elementos del conjunto de resultados detrás de los encontrados por el selector |
insertBefore(selector) |
Inserta todos los elementos del conjunto de resultados delante de los encontrados por el selector |
$("p").after("<p>Párrafo separado</p>");
$("<p>Párrafo separado</p>").insertAfter("p");
// <p>Párrafo 1</p>
// <p>Párrafo separado</p>
// <p>Párrafo 2</p>
// <p>Párrafo separado</p>
Por ejemplo, si queremos mover un elemento una posición hacia abajo, dentro de after
podemos crear una función anónima que devuelva el contenido a mover (además nos sirve para hacer un filtro):
$("p:eq(1)").after(function() {
return $(this).prev();
});
Finalmente, si queremos duplicar el contenido usaremos el método clone()
:
Método | Propósito |
---|---|
clone() |
Clona los elementos del conjunto de resultados y selecciona los clonados |
clone(bool) |
Clona los elementos del conjunto de resultados y todos sus manejadores de eventos y selecciona los clonados (pasándole |
Por ejemplo, podemos clonar un elemento existente para modificarlo a continuación:
var vip2 = $("#vip").clone();
vip2.attr("id","vip2");
6.6.5. Modificando el contenido
jQuery permite envolver contenido en la página, sustituir contenido, copiar y eliminarlo, mediante los siguientes métodos.
Si nos centramos en los métodos para envolver contenido, de manera que les añadiremos un padre, tenemos:
Método | Propósito |
---|---|
wrap(html) |
Envuelve cada elemento del conjunto de resultados con el contenido html especificado |
wrap(elemento) |
Envuelve cada elemento del conjunto de resultados con el elemento especificado |
wrapAll(html) |
Envuelve todos los elementos del conjunto de resultados con el contenido html especificado |
wrapAll(elemento) |
Envuelve todos los elementos del conjunto de resultados con un único elemento |
wrapInner(html) |
Envuelve los contenidos de los hijos internos de cada elemento del conjunto de resultados (incluyendo los nodos de texto) con una estructura html |
wrapInner(elemento) |
Envuelve los contenidos de los hijos internos de cada elemento del conjunto de resultados (incluyendo los nodos de texto) con un elemento DOM |
Una caso particular de wrapAll()
es el cual en el que la selección no comparte un padre común. En este caso, el nuevo elemento se inserta com padre del primer elemento seleccionado. A continuación, jQuery mueve el resto de elementos para que sean hermanos del primero.
Vamos a practicar estos métodos con algunos ejemplos (http://jsbin.com/gavipi/1/edit?html,js,output):
$("p").wrap("<div style='color:red' />");
// <div style='color:red'><p>Párrafo 1</p></div>
// <div style='color:red'><p>Párrafo 2</p></div>
$("p").wrapAll("<div style='color:red' />");
// <div style='color:red'><p>Párrafo 1</p><p>Párrafo 2</p>...</div>
$("p").wrapInner("<div style='color:red' />");
// <p><div style='color:red'>Párrafo 1</div></p>
// <p><div style='color:red'>Párrafo 2</div></p>
Si lo que queremos es sustituir o eliminar contenido, tenemos los siguientes métodos:
Método | Propósito |
---|---|
replaceWith(contenido) |
Sustituye todos los elementos del conjunto de resultados con el contenido especificado, ya sea HTML o un elemento DOM |
replaceAll(selector) |
Sustituye los elementos encontrados por el selector con los del conjunto de resultados, es decir, lo contrario a |
empty() |
Elimina todos los nodos hijos del conjunto de resultados |
remove() |
Elimina todos los elementos del conjunto de resultados del DOM |
detach() |
Igual que |
detach(selector) |
|
unwrap() |
Elimina el padre de cada uno de los elementos del conjunto de resultados, de modo que los elementos se convierten en hijos de sus abuelos. |
Vamos a practicar estos métodos con algunos ejemplos:
$("p").replaceWith("<div>Capa Nueva</div>");
$("<div>Capa Nueva</div>").replaceAll("p");
ul
sigue en el documento)$("ul").empty();
ul
desaparece)$("ul").remove();
var listaBorrada = $("ul").detach();
6.6.6. Trabajando con CSS
Los métodos jQuery facilitan el acceso y modificación de las propiedades CSS con código Cross-Browser, además de facilitar la información de posicionamiento y tamaño de los elementos de la página.
El método css()
permite obtener y asignar estilos CSS a un conjunto de elementos modificando el valor del atributo style
mediante valores a propiedades CSS:
Método | Propósito |
---|---|
css(nombre) |
Devuelve el valor de la propiedad CSS nombre del primer elemento del conjunto de resultados |
css(propiedades) |
Asigna las propiedades de cada elemento del conjunto de resultados mediante la sintaxis de objeto: |
css(propiedad, valor) |
Asigna un valor a una única propiedad CSS. Si se pasa un número, se convertirá automáticamente a un valor de píxel, a excepción de: |
Algunos ejemplos del uso del método css()
:
var tamAnt = $("p").css("font-size");
$("p").css("font-size","1.5em");
$("p").css("font-size","+=5"); // 5 píxeles más
var valoresCSS = {
"font-size": "1.5em",
"color": "blue"
};
$("p").css("font-size", valoresCSS);
Además, jQuery también ofrece métodos para trabajar con las clases CSS y poder añadir, borrar, detectar o intercambiar sus clases:
Método | Propósito |
---|---|
addClass(clase1 [clase2]) |
Añade la clase especificada a cada elemento del conjunto de resultados |
hasClass(clase) |
Devueve |
removeClass(clase [clase2]) |
Elimina la clase de todos los elementos del conjunto de resultados |
toggleClass(clase [clase2]) |
Si no está presente, añade la clase. Si está presente, la elimina. |
toggleClass(clase, cambio) |
Si cambio es |
Y algunos ejemplos de la manipulación de clases CSS (http://jsbin.com/tujuni/3/edit?html,css,js,console,output):
$("p").addClass("a");
$("p:even").removeClass("b").addClass("a");
console.log("En algún elemento:" + $("p").hasClass("a"));
$("p").each(function(indice, elem) {
console.log("Elemento: " + $(elem).text() + " -> " + $(elem).hasClass("a"));
});
$("p").toggleClass("a");
Respecto al posicionamiento CSS, jQuery ofrece métodos que soportan Cross-Browser para averiguar la posición de los elementos:
Método | Propósito |
---|---|
offset() |
Obtiene el desplazamiento actual (en píxeles) del primer elemento del conjunto de resultados, respecto al documento |
offsetParent() |
Devuelve una colección jQuery con el padre posicionado del primer elemento del conjunto de resultados |
position() |
Obtiene la posiciones superior e izquierda de un elemento relativo al desplazamiento de su padre |
scrollTop() |
Obtiene el desplazamiento del scroll superior del primer elemento del conjunto de resultados |
scrollTop(valor) |
Asigna el valor del desplazamiento del scroll superior a todos los elementos del conjunto de resultados |
scrollLeft() |
Obtiene el desplazamiento del scroll superior del primer elemento del conjunto de resultados |
scrollLeft(valor) |
Asigna el valor del desplazamiento del scroll izquierdo a todos los elementos del conjunto de resultados |
var pos = $("img").position();
console.log("Arriba:" + pos.top + " Izq:" + pos.left);
Y finalmente para obtener información Cross-Browser y manipular propiedades específicas relativas al tamaño de los elementos:
Método | Propósito |
---|---|
height() |
Obtiene la altura calculada en píxeles del primer elemento del conjunto de resultados |
height(valor) |
Asigna la altura CSS para cada elemento del conjunto de resultados |
width() |
Obtiene la anchura calculada en píxeles del primer elemento del conjunto de resultados |
width(valor) |
Asigna la anchura CSS para cada elemento del conjunto de resultados |
innerHeight() |
Obtiene la altura interna (excluye el borde e incluye el padding) para el primer elemento del conjunto de resultados |
innerWidth() |
Obtiene la anchura interna (excluye el borde e incluye el padding) para el primer elemento del conjunto de resultados |
outerHeight(margen) |
Obtiene la altura externa (incluye el borde y el padding) para el primer elemento del conjunto de resultados. Si el margen es |
outerWidth(margen) |
Obtiene la anchura externa (incluye el borde y el padding) para el primer elemento del conjunto de resultados. Si el margen es |
Por ejemplo, supongamos que tenemos el siguiente fragmento CSS:
div#capa {
width: 250px;
height: 180px;
margin: 10px;
padding: 20px;
background: blue;
border: 2px solid black;
cursor: pointer;
}
p, span {
font-size: 16pt;
}
Si en el documento HTML tenemos capas con ids para imprimir el valor de las propiedades mediante este código:
$("#height").html($("#capa").height());
$("#width").html($("#capa").width());
$("#innerH").html($("#capa").innerHeight());
$("#innerW").html($("#capa").innerWidth());
$("#outerH").html($("#capa").outerHeight());
$("#outerW").html($("#capa").outerWidth());
$("#offset").html($("#capa").offset().top + " - " + $("#capa").offset().left);
$("#position").html($("#capa").position().top + " - " + $("#capa").position().left);
Tendríamos un resultado similar a este (http://jsbin.com/futozu/2/edit?html,css,js,output):
6.6.7. Asociando datos con elementos
jQuery ofrece el método data()
para trabajar con los atributos de datos personalizados que ofrece HTML5, que empiezan por data-
, es decir, data-nombre
, data-tipo
, etc…
Método | Propósito |
---|---|
data(clave) |
Obtiene el atributo |
data(clave, valor) |
Almacena el valor en el atributo |
removeData() |
Elimina todos los atributos de datos de cada elemento del conjunto de resultados |
removeData(clave) |
Elimina el atributo |
Es mejor acceder a los elementos por su atributo data que por el texto que contienen sus atributos, ya que éste último puede cambiar debido a la internacionalización (18n) de la aplicación.
|
Vamos a practicar estos métodos con algunos ejemplos:
$("#listado").data("tipo","tutorial");
$("#listado").data("codigo", 123); (1)
1 | Lo que sería similar a <ul id="#listado" data-tipo="tutorial" data-codigo="123"> . Cuidado que estos atributos no se renderizan como atributos del DOM, por lo cual no los podemos inspeccionar mediante las DevTools |
$("#listado").removeData("tipo");
Los atributos de datos almacenados mediante jQuery no se trasladan a atributos del DOM, por lo que no podremos obtenerlos mediante getAttribute() .
|
6.7. Eventos
Igual que estudiamos en la sesión de JavaScript vamos a ver como jQuery simplifica, y mucho, el tratamiento de los eventos.
Sus principales ventajas son:
-
permite asociar un manejador a un grupo de elementos obtenido mediante selectores y filtros.
-
permite conectarse a y desconectarse de los eventos de manera Cross-Browser y dar soporte a IE8 y anteriores.
-
ofrece un objeto de evento que expone la mayoría de las propiedades comunes de manera Cross-Browser.
-
ofrece funciones que encapsulan las funcionalidades de eventos más comunes y funciones auxiliares con código Cross-Browser.
Para empezar veremos el evento que más vamos a utilizar.
6.7.1. Evento document.ready
Del mismo modo que con JavaScript básico, si ponemos un selector jQuery en el encabezado que referencia a elementos DOM que no se han cargado, no va a funcionar. En cambio, si movemos el selector a una posición previa a cerrar el body
irá todo correctamente. Para asegurarnos, de manera similar a window.onload
, mediante jQuery usaremos el siguiente fragmento:
$(document).ready(function() {
// código jQuery
}
La ventaja de usar jQuery es que permite usar varias funciones sobre el mismo evento, ya que mediante window.onload
sólo se ejecutará la última función que le hayamos asignado.
$(document).ready(function() {
// código alfa
}
$(document).ready(function() {
// código beta
}
Además, mientras que con window.onload
el evento espera a que haya cargado toda la página, incluidas las imágenes, con jQuery se lanzará cuando haya cargado el DOM, sin tener que esperar a descargar todas las imágenes. Esto se conoce como el evento document.ready
.
Si queremos poner el mismo código pero de manera simplificada, aunque menos legible, podemos hacerlo del siguiente modo:
$(function() {
// código jQuery
});
Es decir, cada vez que le pasemos una función a jQuery()
o $()
, le diremos al navegador que espere hasta que el DOM haya cargado completamente para ejecutar el código.
6.7.2. Adjuntando manejadores de eventos
Una vez hemos seleccionado el conjunto de elementos al cual queremos asociarle un manejador, usaremos la función on()
para indicar que evento capturar y el código del manejador, y off()
para eliminar un manejador de eventos.
En versiones anteriores de jQuery se usaban los métodos bind()
, unbind()
, live()
, die()
, los cuales han sido marcados como métodos deprecated y no veremos en este módulo.
Antes de jQuery 1.7, en vez de on() , se usaba bind() con jQuery 1.0, live() con la versión 1.3 y delegate() a partir de la versión 1.4.2
|
Así pues, mediante on(eventos [,selector] [,datos] ,manejador(objetoEvento))
capturaremos los eventos. Más información en http://api.jquery.com/on . En su versión más simple la usaremos del siguiente modo:
$(selector).on("nombreDelEvento", function() {
// código del manejador
})
Por ejemplo, si queremos capturar cuando se hace click sobre un párrafo:
$("p").on("click", function() {
console.log("Click sobre un párrafo");
})
Si queremos capturar más de un evento, hemos de separar el nombre de los eventos con espacio:
$("p").on("click mouseenter", function() {
console.log("Click o mouseenter sobre un párrafo");
})
Cuando aplicamos el evento on
, en vez de seleccionar todos los elementos de un tipo que hay en DOM, es mejor elegir el padre del que estamos interesado y luego filtrar dentro del método. Por ejemplo, en vez de:
$("dt").on("mouseenter", function() {
es más eficiente hacer
$("dl").on("mouseenter","dt",function() {
Ejemplo eventos
Vamos a realizar un ejemplo para ver a jQuery en acción. Vamos a cambiar los estilos de una caja cuando el ratón pase por encima del mismo. Si hacemos click sobre la caja, eliminaremos el evento.
Así pues, primero dibujemos la caja:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<style type="text/css">
.normal {
width:300px; height:200px; background-color:yellow; font-size:18pt;
}
.resaltado {
background-color:red;
}
</style>
</head>
<body>
<h1>Eventos con jQuery</h1>
<div id="destinoEvento" class="normal">Pasar el ratón para ver el efecto. Click para quitar/añadir el manejador.</div>
</body>
</html>
A continuación, el código JavaScript para capturar y manejar los eventos:
$(document).ready(function() {
var dest = $("#destinoEvento"); (1)
dest.on("mouseover mouseleave", function(evt) { (2)
dest.toggleClass("resaltado");
});
dest.on("click", function(evt) {
dest.off("mouseover mouseleave"); (3)
$("#destinoEvento").text("Manejadores eliminados");
});
});
1 | Guardamos el destino del enlace en una variable para evitar repetir la búsqueda |
2 | Capturamos los eventos de mouseover y mouseleave sobre la caja y le cambiamos la clase del estilo dentro del manejador |
3 | Dentro de la captura del evento click , eliminamos los manejadores de los eventos mouseover y mouseleave e informamos al usuario del cambio. Si el destino tuviese más manejadores sobre estos eventos, también se eliminarían. |
.on() sólo puede crear manejadores de eventos sobre elementos que ya existen en el momento de asignación del listener. Los elementos similares creados tras asignar los manejadores no capturarán los eventos configurados con anterioridad.
|
6.7.3. Métodos auxiliares
jQuery ofrece un conjunto de métodos auxiliares para simplificar su uso con los eventos más utilizados. Si los ordenamos por su categoría tenemos:
-
Ratón:
click()
,dblclick()
,focusout()
,hover()
,mousedown()
,mouseenter()
,mouseleave()
,mousemove()
,mouseout()
,mouseover()
,mouseup()
. -
Teclado:
focusout(), keydown()
,keypress()
,keyup()
. -
Formulario:
blur()
,change()
,focus()
,focusin()
,select()
,submit()
. -
Navegador:
error()
,resize()
,scroll()
.
Es decir, las dos acciones siguientes son semejantes:
$("p").click(function() {
// Manejador
});
$("p").on("click", function() {
// Manejador
});
Un caso particular que conviene estudiar es el método hover()
, el cual acepta dos manejadores, los cuales se ejecutarán cuando el ratón entre y salga del elemento respectivamente:
$(function() {
$("#destino").hover(resaltar, resaltar);
$("#destino").click(fnClick1);
$("#destino").dblclick(fnClick2);
});
function resaltar(evt) {
$("#destino").toggleClass("resaltado");
}
function fnClick1() {
$("#destino").html("Click!");
}
function fnClick2() {
$("#destino").html("Doble Click!");
}
Recordad que el método clone() clona el contenido seleccionado, pero sin copiar sus eventos. Para ello, hay que pasarle como parámetro true , para que clones los eventos del selector
|
También podemos usar los siguientes métodos para realizar tareas específicas:
Método | Propósito |
---|---|
one(tipo, datos, manejador) |
Permite capturar el evento tipo una sola vez para cada elemento del conjunto de resultado |
trigger(evento, datos) |
Lanza un evento para cada elemento del conjunto de resultados, lo que también provoca que se ejecute la acción predeterminada por el navegador. Por ejemplo, si le pasamos un evento |
triggerHandler(evento, datos) |
Dispara todos los manejadores asociados al evento sin ejecutar la acción predeterminada o burbujero del navegador. Sólo funciona para el primer elemento del conjunto de resultados del selector |
Por ejemplo, supongamos que tenemos varios cuadrados y queremos que cambien su color una sola vez:
<!DOCTYPE html>
<html lang="es">
<head>
<title>Usando el objeto jQuery Event</title>
<meta charset="UTF-8">
<style type="text/css">
div {
width: 60px; height: 60px; margin: 10px; float: left;
background: blue; border: 2px solid black; cursor: pointer;
}
p {
font-size: 18pt;
}
</style>
</head>
<body>
<p>Click en cualquier cuadrado para cambiar su color</p>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>
Y el código para cambiar el color una sola vez al hacer click:
$(function() {
$("div").one("click", function(evt) {
$(this).css({
background: "red", cursor: "auto"
});
console.log("Evento " + evt.type + " en div " + $(this).attr("id"));
});
});
Si hacemos click más de una ocasión sobre un mismo cuadrado podemos comprobar como no sale por consola.
6.7.4. Objeto jQuery Event
Para poder trabajar con manejadores de eventos Cross-Browser, es importante que exista un único objeto que permite acceder a las propiedades más importantes:
Propiedad / Método | Propósito |
---|---|
type |
Tipo del evento, por ejemplo, |
target |
Elemento que lanzó el evento |
data |
Datos pasados al manejador |
pageX, pageY |
Coordenadas relativas al documento del ratón en el momento de lanzarse el evento |
result |
Valor devuelto por el último manejador |
timestamp |
Tiempo en el que se lanzó el evento |
preventDefault() |
Previene el comportamiento por defecto del navegador |
idDefaultPrevented() |
Averigua si se ha detenido el comportamiento por defecto |
stopPropagation() |
Detiene el burbujeo del evento hacia los elementos superiores |
isPropagationStopped() |
Averigua si se ha detenido el burbujeo del evento |
Este objeto se obtiene como parámetro de la función manejadora del evento. Para mostrar estas propiedades en acción, vamos a basarnos en el siguiente código donde podemos ver tres capas:
<!DOCTYPE html>
<html lang="es">
<head>
<title>Usando el objeto jQuery Event</title>
<meta charset="UTF-8">
<style type="text/css">
.normal {
width:300px; height:200px; background-color: silver;
font-size:18pt; margin:5pt 5pt 5pt 5pt;
}
</style>
</head>
<body>
<h1>Usando el objeto jQuery Event</h1>
<div id="div1" class="normal">Click en esta capa (div1) para ver la información del evento</div>
<div id="div2" class="normal">Click en esta capa (div2) para ver la información del evento</div>
</body>
</html>
Y el código para mostrar la información:
$(function() {
$("div").click(function(evt) {
$(this).html("pageX: " + evt.pageX + ", pageY: " + evt.pageY + ", tipo: " + evt.type + ", target: " + evt.target);
});
});
Al pulsar encima de las capas, se mostrará la información de coordenadas relativas, tipo y target del evento:
6.7.5. Eventos personalizados
Sabemos que una vez seleccionado un elemento, mediante el método on
podemos capturar el evento y controlar el código del manejador mediante una función anónima.
Ya hemos visto que si queremos lanzar un evento de manera programativa, sin que lo haga el usuario, podemos usar el método trigger(evento,datos)
:
$('body').trigger('click'); // lanza el evento _click_ sobre el _body_
De este modo, podemos crear eventos personalizados para posteriormente capturarlos:
$('body').on('batClick', function() {
console.log("Capturado el evento personalizado batClick");
});
$('body').trigger('batClick');
Veamos un ejemplo práctico. Supongamos que accedemos a un servicio REST que devuelve JSON como el de OMDB visto en la sesión anterior:
var datos;
$.getJSON('http://www.omdbapi.com/?s=batman&callback=?', function(resultado) {
datos = resultado;
});
console.log(datos); // undefined
Tal como vimos, se trata de una llamada asíncrona de modo que cuando mostramos los datos recibidos no obtenemos nada porque realmente la llamada AJAX todavía no ha finalizado.
Para poder controlar cuando se han cargado los datos podemos lanzar un evento personalizado de modo que al capturarlo estaremos seguro que la petición ha finalizado.
Ejemplo modelo publicador/subscriptor - http://jsbin.com/pisihe/edit?html,js,console,output
$.getJSON('http://www.omdbapi.com/?s=batman&callback=?', function(datos) {
$(document).trigger('obd/datos', datos); // publicador
});
$(document).on('obd/datos', function(evt, datos) {
console.log('Subscriptor 1 recibe los datos'); // subscriptor 1
});
$(document).on('obd/datos', function(evt, datos) {
console.log('Subscriptor 2 recibe los datos'); // subscriptor 2
});
A este mecanismo de comunicación se le conoce como Publish/Subscribe (y que implementa el patrón Observer), donde podemos tener varios publicadores que envían información mediante el trigger
del evento personalizado y múltiples subscriptores con los capturadores del evento.
Esto mismo lo podemos resolver mediante las promesas que veremos en la siguiente unidad. |
6.8. this
Ya sabemos que al cargar una página, si referenciamos a this
desde la raíz apunta al objeto window
. En cambio, si lo hacemos desde dentro una función, siempre apuntará a su padre. Es decir, si la función se llama desde el click de un enlace, this
contendrá el enlace.
Supongamos que tenemos un botón que lanza un manejador:
<button id="clickeame">Click aquí</button>
Al mostrar con consola el valor de this
obtendremos el elemento button:
$("#clickeame").click(function(evt) {
console.log(this); // HTMLButtonElement
console.log(this.type); // "submit"
})
Una acción que se utiliza mucho es convertir el elemento HTML a un objeto jQuery:
var $this = $(this);
6.8.1. Modificando this
Si queremos especificar qué va a ser this
al pasarle el control a una función, podemos usar un proxy mediante:
$.proxy(nombreDeLaFuncion, objetoQueSeraThis);
Supongamos que rescribimos el ejemplo anterior mediante un módulo, del siguiente modo:
var manejador = {
type: "Mi manejador de eventos",
manejadorClick: function(evt) {
console.log(this.type);
}
};
$(function() {
$("#clickeame").click(manejador.manejadorClick);
});
Si volvemos al ejemplo anterior, y en vez de obtener mediante this
el botón queremos que tome el del manejadores haremos:
$(function() {
$("#clickeame").click($.proxy(manejador.manejadorClick, manejador));
});
Más información en http://api.jquery.com/jQuery.proxy/
6.9. Ejercicios
6.9.1. (0.2 ptos) Ejercicio 61. Recuperando contenido
A partir del siguiente documento con enlaces, añadir el código jQuery necesario para que al lado de cada enlace muestre mediante una imagen el formato del archivo (pdf, html) o el tipo de enlace (sólo para email).
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Ejercicio 61. Enlaces</title>
</head>
<body>
Enlaces
<ul>
<li><a href="algunsitio.html">Enlace 1</a></li>
<li><a name="#ancla1">Ancla de Enlace</a></li>
<li><a href="algunsitio.html">Enlace 2</a></li>
<li><a href="algunsitio.pdf">Enlace 3</a></li>
<li><a href="algunsitio.html">Enlace 4</a></li>
<li><a href="algunsitio.pdf">Enlace 5</a></li>
<li><a href="algunsitio.pdf">Enlace 6</a></li>
<li><a href="mailto:batman@heroes.com">Enlace email</a></li>
</ul>
</body>
</html>
Tras ejecutar la página, el resultado debe ser similar a la siguiente imagen:
Todo el código estará incluido en el archivo ej61.js
6.9.2. (0.7 ptos) Ejercicio 62. Apuntes 1.0
A partir del documento HTML de los apuntes, haciendo uso de jQuery realizar las siguientes tareas:
-
cambia los datos del autor y email con tus datos personales
-
sustituye la tabla de contenidos con una lista desordenada que sólo contenga los títulos de primer nivel, con enlaces al lugar correspondiente
-
añade un enlace al final de cada capítulo para volver al inicio del documento.
-
añade dos botones (A+, a-) tras el título del documento que modifiquen el tamaño del texto para hacerlo más grande o más pequeño.
La apariencia será similar a la siguiente:
Todo el código estará incluido en el archivo ej62.js
6.9.3. (0.3 ptos) Ejercicio 63. Tabla con resaltado
Supongamos que tenemos una tabla con información en filas similar a la siguiente:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Ejercicio 63. Tablas</title>
<style type="text/css">
th,td {
font-family: Verdana, Arial, Helvetica; font-size: 18px; color: #000000;
}
tr {
border: 1px solid gray;
}
td {
width:200px; padding:3px;
}
th {
background-color:#D2E0E8; color:#003366
}
table {
border: 1pt solid gray;
}
.clickable {
cursor:pointer;
}
</style>
</head>
<body>
<h1>Usando jQuery para resaltar filas de una tabla</h1>
<table id="laLista">
<thead>
<tr><th>Producto</th><th>Precio</th></tr>
</thead>
<tbody>
<tr><td>Leche</td><td>1.99</td></tr>
<tr><td>Huevos</td><td>2.29</td></tr>
<tr><td>Mantequilla</td><td>3.49</td></tr>
<tr><td>Pan</td><td>0.99</td></tr>
<tr><td>Macarrones</td><td>1.19</td></tr>
<tr><td>Miel</td><td>4.39</td></tr>
<tr><td>Galletas</td><td>2.99</td></tr>
</tbody>
</table>
</body>
</html>
Las tareas a realizar son:
-
Añadir a cada fila de manera alterna los siguientes estilos:
.par {
background-color:#0f0;
}
.impar {
background-color:#afa;
}
-
Resalta la fila sobre la que está el ratón con el siguiente estilo:
.resaltado {
background-color: #ffcc00;
font-weight:bold;
}
-
Al clickar sobre una fila, mostrará una alerta con el producto y su precio
Todo el código estará incluido en el archivo ej63.js