En el artículo anterior explicamos como funcionaban los métodos tradicionales de búsqueda en el DOM como getElementById()
o getElementsByClassName()
. Aunque estos métodos tradicionales pueden ser más que suficientes para buscar elementos en el DOM, tenemos a nuestra disposición dos nuevos métodos de búsqueda mucho más flexibles y prácticos si conocemos y dominamos los selectores CSS.
Métodos modernos de búsqueda
En este nuevo grupo, tenemos sólo dos métodos que son equivalentes a todos los métodos tradicionales, y aún más potentes, ya que permiten hacer cosas que no se podían realizar con los anteriores.
Los métodos son los siguientes:
Método de búsqueda | Descripción | Si no lo encuentra... |
---|---|---|
.querySelector(sel) | Busca el primer elemento que coincide con el selector CSS sel . | Devuelve |
.querySelectorAll(sel) | Busca todos los elementos que coinciden con el selector CSS sel . | Devuelve [] . |
Con estos dos métodos podemos realizar todo lo que hacíamos con los métodos tradicionales mencionados anteriormente e incluso muchas más cosas (en menos código) gracias a CSS.
El método querySelector()
El método .querySelector()
devuelve el primer elemento que encuentra que encaja con el selector CSS indicado por parámetro:
const page = document.querySelector("#page"); // <div id="page"></div>
const info = document.querySelector(".main .info"); // <div class="info"></div>
Lo realmente interesante de este método, es que al permitir suministrarle un selector CSS básico o incluso un selector CSS avanzado, se vuelve un sistema mucho más potente que los tradicionales.
El primer ejemplo sería equivalente a utilizar un
.getElementById()
, sólo que en la versión de.querySelector()
indicamos por parámetro un, y en el primero le pasamos un simple . Observa que estamos indicando un #
porque se trata de unid
.En el segundo ejemplo, estamos recuperando el primer elemento con clase
info
que esté dentro de otro con clasemain
. En los métodos tradicionales, sería menos directo ya que tendríamos que realizar varias llamadas. Con.querySelector()
se hace directamente sólo con una.
El método
querySelector()
siempre devuelve un solo elemento: el primero que encuentra. En el caso de no coincidir con ninguno, devuelve.
El método querySelectorAll()
Por otro lado, el método .querySelectorAll()
realiza una búsqueda de elementos en el DOM, sólo que como podremos intuir por ese All()
, devuelve un
// Obtiene todos los elementos con clase "info"
const infos = document.querySelectorAll(".info");
// Obtiene todos los elementos con atributo name="nickname"
const nicknames = document.querySelectorAll('[name="nickname"]');
// Obtiene todos los elementos <div> de la página HTML
const divs = document.querySelectorAll("div");
El método
.querySelectorAll()
siempre nos devolverá unde elementos. En el caso de no encontrar ninguna coincidencia, nos devolverá un array de 0 elementos.
Búsquedas acotadas
Al realizar una búsqueda de un elemento particular y guardarlo en una variable o constante, podemos volver a realizar una nueva búsqueda posteriormente sobre este elemento, en lugar del DOM íntegro document
:
const menu = document.querySelector("#menu");
const links = menu.querySelectorAll("a");
Sin embargo, si controlamos un poco de CSS, y nos interesa únicamente el elemento final, puede ser mucho más sencillo realizar lo siguiente:
const links = document.querySelectorAll("#menu a");
Otros métodos interesantes
Existen algunos métodos relacionados con las búsquedas para encontrar elementos, pero con interesantes diferencias:
- 1️⃣ Los métodos
querySelector()
yquerySelectorAll()
buscan en elementos descendientes - 2️⃣ El método
closest()
busca en elementos ascendientes (hacia «arriba» en el DOM) - 3️⃣ El método
matches()
comprueba el propio elemento, si coincide con un selector
Nos queda por ver los siguientes métodos:
Métodos | Descripción | En caso negativo... |
---|---|---|
.closest(sel) | Busca el primer elemento más cercano que coincide con selector. | |
.matches(sel) | Comprueba si un elemento coincide con una selección CSS. | false |
El método closest()
El método closest()
nos permite encontrar el primer elemento más cercano hacia «arriba» en el DOM, que coincida con el selector CSS indicado por parámetro. Es decir, es como un querySelector()
, pero buscando ascendentemente en el DOM:
const item3 = document.querySelector(".item-3");
item3.closest(".container"); // <div class="container"></div>
item3.closest(".subitem"); // null
<div class="container">
<div class="sandbox">
<div class="item item-1"></div>
<div class="item item-2"></div>
<div class="item item-3">
<div class="subitem"></div>
</div>
</div>
</div>
Observa que no buscará en los elementos descendientes, sino siempre en los ascendientes. Si no encuentra ningún elemento que coincida con el selector, devolverá
El método matches()
El método matches()
no sirve para buscar, pero nos puede permitir comprobar si un elemento específico coincide con un selector CSS indicado por parámetro:
- Devuelve
true
si el elemento coincide con el selector. - Devuelve
false
si el elemento no coincide con el selector.
const container = document.querySelector(".container");
const sandbox = document.querySelector(".sandbox");
container.matches(".container"); // true
sandbox.matches(".container .sandbox"); // true (detecta ancestros)
sandbox.matches(".container"); // false
<div class="container">
<div class="sandbox"></div>
</div>
El tipo NodeList
vs HTMLCollection
Ten en cuenta que, aunque he mencionado que el método querySelectorAll()
devuelve siempre un NodeList
, que es muy similar a un
const elements = document.querySelectorAll("div");
elements.map // undefined
const elements = [...document.querySelectorAll("div")];
elements.map // ƒ map() { [native code] }
Como puedes ver, en el primer caso, la estructura devuelva (es un NodeList) no tiene el método .map()
, que utilizamos para transformar elementos de un array. Sin embargo, en el segundo caso hemos hecho una desestructuración de arrays para sacar todos los elementos de la estructura y reestructurarla en un, ahora sí, nuevo .map()
y en el segundo caso, sí.
Si no vas a realizar tareas donde necesites estas estructuras de datos, se recomienda no convertirlo en un array, pero si necesitas trabajar con métodos como
.map()
o.filter()
, por ejemplo, puedes destructurarlo o convertirlo mediante unArray.from()
.