HTML/JavaScript — Document Object Model (DOM)
Temario
- Document Object Model (DOM)
- Acceso a elementos DOM — (getElementById, getElementsByTagName, getElementsByClassName, getElementsByName, querySelector, querySelectorAll)
- Tipos de nodos (raíz, principales, hijos, hermanos)
- Events (handlers and listeners)
- Tipos de evento (mouse, teclado, otros)
- La interfaz evento (Event) de DOM (target, preventDefault, stopPropagation)
i. Document Object Model (DOM)
By the book: El Modelo de Objetos del Documento
DOM
es un API para documentosHTML
yXML
. Proporciona una representación estructural del documento, permitiendo la modificación de su contenido o su presentación visual. Esencialmente, comunica las páginas web con los scripts o los lenguajes de programación.La interfaz del Modelo de Objetos del Documento describe las propiedades comunes y métodos para todo el documento. Dependiendo del tipo de documento
HTML,XML,SVG,etc
, una interfaz más grande está disponible: Los documentosHTML
, servidos con el tipo de contenidotext/html
implementan la interfaz de HTMLDocument, mientras queXML
ySVG
implementan la interfaz de XMLDocument.DOM es un estándar del W3C (World Wide Web Consortium)
En español, El modelo de Objetos del Documento es una interfaz para poder comunicar el XHTML estructurado de una página con la parte de los scripts (JavaScript por ejemplo), de tal forma que en tiempo de ejecución se puedan leer y modificar los nodos del documento; siendo un nodo un elemento dentro del documento como unidad atómica.
El árbol de nodos del documento, es la forma de representar jerárquicamente todos los nodos y sus descendias a fin de que se sepa quiénes son los nodos padres (parents), los nodos hermanos (siblings) y los nodos hijos (descendants); el cual se puede recorrer por medio de JavaScript para obtener los valores, atributos y propiedades de cada nodo.
Podemos ver que en nuestro ejemplo tenemos que el nodo HTML
es el padre, head
y body
son hermanos, así como head
y body
contienen nodos secundarios como un árbol genealógico.
ii. Acceso a elementos DOM
Para poder acceder a los nodos de un documento, la interfaz cuenta con unos métodos dependiendo el tipo de identificador que tenga el nodo.
Para ejemplificar todos los tipos de accesos al DOM
, tendremos el siguiente HTML
como referencia:
a — getElementById
La función getElementById('id')
devuelve el elemento XHTML cuyo atributo id coincide con el parámetro indicado en la función. Como el atributo id debe ser único para cada elemento de una misma página, la función devuelve únicamente el nodo deseado.
Así entonces, al usar la función en nuestro HTML
de ejemplo, tendríamos el siguiente resultado:
b — getElementsByTagName
La función getElementsByTagName('tagName')
obtiene todos los elementos de la página XHTML cuya etiqueta sea igual que el parámetro que se le pasa a la función.
A diferencia de la función anterior que solo podíamos regresar 1 solo elemento, con esta podremos obtener todos los elementos en un arreglo de nodos, que después podremos iterar para obtener mayor detalle.
c — getElementsByClassName
La función getElementsByClassName('className')
obtiene todos los elementos que en su clase coincidan con el parámetro pasado a la función; esto tiene la ventaja de que pueden haber múltiples elementos en el documento, pero con distintas clases que nos servirán para diferenciarlos a la hora de seleccionarlos.
d — getElementsByName
La función getElementsByName('name')
obtiene todos los elementos que en su nombre coincidan con el parámetro pasado a la función, este tiene mayor utilidad cuando queremos seleccionar campos de formularios, ya que son los que casi siempre posee dicho atributo.
Adicionalmente, si quisiéramos hacer un selector interno dependiendo de otro selector, podríamos ir combinando los selectores que hemos visto.
e — querySelector
Hasta ahora, las funciones vistas solo hacen foco en un tipo de nodo que se busca en todo el documento, y así también solo se pueden seleccionar TODOS o UNO de los elementos que estén en todo el documento, y no sólo ciertos elementos que estén contenidos en otro de nuestro interés.
El querySelector
ayuda a hacer selectores más específicos, ya que permite especificar cuáles son los padres o hermanos del elemento que queremos encontrar, así como sintaxis adicionales para hacer más robusta la selección.
Importante notar que
querySelector
solo traerá la primera coincidencia que encuentre.
Otra forma de escribir el selector combinado del bloque anterior usando querySelector
seria:
f — querySelectorAll
Por último tenemos querySelectorAll
, este nos traerá todas las coincidencias que haya encontrado basado en el query pasado a la función.
Usando el mismo query del selector pasado tendríamos:
Ejemplo completo:
iii. Tipos de nodos
Cuando hablamos del DOM, estamos hablando de propiedades o nodos donde vamos aplicar nuestro JavaScript, podemos considerar 3 tipos: Padre, Hijo y Hermano
Para entenderlo vamos a usar el siguiente HTML
de ejemplo:
a — Nodos de raíz
Sabemos que el objeto principal es window
, y dentro de esta variable se encuentra el objeto document
, es básicamente todo lo que estamos visualizando dentro de nuestro navegador, por defecto contiene 2 nodos principales : head
y body
, si nosotros abrimos la consola de nuestro navegador y escribimos lo siguiente:
Podemos observar que nos muestra el contenido que tiene el nodo.
b — Nodos padre
Como hemos venido mencionando, los nodos dentro del DOM los podemos dividir en padres, hijos y hermanos, estos se identifican dependiendo la relación que tenga con otros nodos, se puede identificar un nodo padre cuando tiene nodos hijos directos, de acuerdo al HTML
que tenemos arriba vamos a dividirlos:
- Sabemos que
html
es el padre dehead
ybody
body
a su vez es hijo dehtml
y es el padre deh1, h2, p
yul
ul
es hijo debody
y es el padre deli
- Por último
h1, h2, p
yul
son hermanos entre ellos
Lo que acabamos de escribir tenemos forma de saberlo, para identificar quien es el padre de algún nodo usamos parentNode
.
Podemos probar subiendo todos los niveles que creamos que son necesarios:
Qué pasaría si nos pasamos de parentNode
, simplemente nos retorna null
y después un error Cannot read property ‘parentNode’ of null ya que null
no tiene propiedades
c — Nodos hijos
Los nodos hijos son los que están del nivel uno en adelante en el árbol jerárquico; para poder trabajar con dichos nodos utilizaremos dos tipos de búsqueda:
- Ven todo los nodos: Los que incluyen una lista de nodos hijos y nodos no elementos (tipo textos y comentarios) —
childNodes, firstChild, lastChild
- Nodos de elementos: Son los que incluyen solamente la colección de nodos de elementos (no toma en cuenta a los nodos no elementos) —
children, firstElementChild, lastElementChild
Veamos en un ejemplo cuando hacemos uso de childNodes
y children
:
Podemos observar que childNodes
nos retorna nodos text
, estos son espacios en blanco causados por la sangría entre elementos, que el DOM considera como nodos. No podemos visualizarlos directamente en la consola, ya que el DevTools elimina esos nodos.
d — Nodos hermanos
Los nodos hermanos, son aquellos que se encuentran en el mismo nivel del árbol jerárquico en el DOM, pueden ser o no del mismo tipo div,span,etc
, al igual que los nodos hijos, este tiene dos tipos de búsqueda:
- Ven todo los nodos: Los que incluyen una lista de nodos hijos y nodos no elementos (tipo textos y comentarios) —
previousSibling,nextSibling
- Nodos de elementos: Son los que incluyen solamente la colección de nodos de elementos (no toma en cuenta a los nodos no elementos) —
previousElementSibling,nextElementSibling
Veamos un ejemplo:
De la lista que tenemos, vamos a seleccionar Yo soy el segundo, y después veremos los nodos hermanos.
iv. Events (handlers and listeners)
Los eventos, son acciones que ocurren cuando el usuario/aplicación realiza una acción dentro de nuestro sitio web, los eventos más comunes son la carga de página, movimiento del mouse, tamaño de ventanas, clicks a botones, escribir en el teclado, entre otros. Los eventos, son la interacción que tiene JavaScript con el HTML.
En JavaScript tenemos dos tipos de eventos:
- Controladores de eventos (Event Handlers): Es una función que se ejecuta cuando se realiza una acción.
- Oyente de eventos (Event listeners): Es cuando el elemento espera o escucha a que se realice una acción.
Dentro de los Event Handlers tenemos dos formas de hacerlo:
- Inline Event Handlers
- Event Handler Properties
a.1 — Event Handlers — Inline Event Handlers
Vamos con el ejemplo más sencillo, tenemos un html
, donde tiene un botón y se espera que al darle click a este nos lance un mensaje.
Cada vez que le damos click al botón, se dispara el evento que ejecuta la función alertMessage();
, y este lanza un mensaje alert("Hello I'm a message :)");
.
El poner dentro del HTML el atributo onclick
se le llama Inline Event Handlers ya que estamos mezclando JavaScript dentro del HTML. No está mal hacerlo, pero esa no es la manera correcta, lo ideal es mantener separado JavaScript, CSS, HTML.
a.2 — Event Handlers — Event Handler Properties
Los Event Handler Properties funcionan MUY PARECIDO igual a los Inline Event Handlers, el MUY PARECIDO es que debemos de quitar el atributo onClick
del HTML, esto quiere decir, que ya no vamos a mezclar JavaScript dentro del HTML.
Como podemos observar, nuestro método sigue siendo el mismo, solo hemos agregado la variable btn
, para agregar el elemento DOM del botón y después agregamos la propiedad onclick
, donde, le asignamos nuestra función.
Y en pantalla vamos a ver exactamente el mismo resultado, que el ejemplo anterior.
Vamos a aumentar complejidad a nuestro ejemplo, qué pasaría si quisiéramos agregar otro método al evento onClick
, quizás, pensaríamos que puede ser de la siguiente manera:
Como podemos observar en el gif, realmente SIEMPRE se ejecuta el último, esto quiere decir que se sobreescribe el evento, mas no se agrega.
Hasta aquí ya hemos separado el JavaScript del HTML, pero aún tenemos ciertos problemas:
- Solo podemos tener un evento en línea asignado.
- Los eventos se almacenan como propiedad dentro del elemento DOM.
- No tenemos forma de eliminar el evento (solamente sobreescribiendo).
Entonces aquí es donde surge los Event listeners…
b — Event listeners
Los Event listeners registran un evento de un elemento, a diferencia del otro que asigna el evento directo en el elemento DOM, para ello usaremos el método addEventListener.
De hecho el addEventListener
es la mejor forma de escuchar una acción de evento, ya que podemos agregarlo a un elemento DOM, o a document
e inclusive a window
.
:: Sintaxis
Para ver más a fondo cómo funciona useCapture
[ref].
Si seguimos nuestro ejemplo anterior, el HTML lo seguimos conservando:
En el archivo JavaScript, es donde vamos a hacer cambios, agregaremos el evento al botón
Nota: En las dos primeras formas se hizo referencia a un evento de click como
onclick
, pero con los Event listeners se hace referencia al evento comoclick
. Cada Event listeners asigna de manera interna elon
.
La ventaja que tenemos al usar Event listeners, es que podemos genera n escuchas para una sola acción:
Y eso no es todo, a diferencia de las otras formas, con Event listeners SI permite remover el evento.
Ver ejemplo completo:
v. Tipos de evento
Hasta ahora hemos se han hecho ejemplos con el evento click
, pero ese no es el único, por ahora sólo mencionaremos los más utilizados:
- Eventos de mouse
- Eventos de teclado
- Otros eventos
a — Eventos de mouse
Estos eventos son los más utilizados, ya que son con los que hace más interacción el usuario con nuestro sitio web, que va desde un simple click, hasta el movimiento del mouse.
— click
: Acción que se ejecuta cuando damos click con el mouse a un elemento DOM (botón, link, etc), y es una combinación de mousedown y mouseup
— dblclick
: Acción que se ejecuta cuando se le da click dos veces con el mouse a un elemento DOM (botón, div, imagen, etc)
— mouseenter
: Acción que se ejecuta cuando el puntero del mouse esta encima un elemento DOM.
— mouseleave
: Acción que se ejecuta cuando el puntero del mouse deja un elemento DOM.
— mousemove
: Acción que se ejecuta cuando se mueve el puntero dentro de un elemento DOM.
— mousedown
: Acción que se ejecuta cuando damos click con el mouse sobre un elemento DOM (este se produce en el momento de dejar pulsado el botón de click, se suelte o no)
— mouseup
: Acción que se ejecuta cuando soltamos el botón del mouse que previamente se había pulsado dentro de un elemento DOM.
Veamos el siguiente ejemplo:
En el ejemplo anterior hacemos uso del argumento event que recibe la función, este tiene bastantes propiedades que nos pueden ser de gran utilidad, para el ejemplo se ha utilizado la propiedad que sirve para saber el tipo type de acción que se está escuchando.
Les dejo un gif del resultado de cada evento:
Ver ejemplo completo:
b — Eventos de teclado
Estos eventos son también muy populares, ya que hacen interacción con el teclado del usuario, cuando presiona una tecla, deja de presionar la tecla.
— keydown
: Acción que se ejecuta se presiona una tecla, sin importar si la ha soltado o no, se conoce cada tecla que se presiona.
— keyup
: Acción que se ejecuta cuando se suelta la tecla.
— keypress
: Acción que se ejecuta continuamente mientras se presiona la tecla, antes de este evento se ejecuta keydown
, evita teclas como SHIFT, ALT.
Veamos el siguiente ejemplo:
Con el argumento de la función event
, podemos saber que tecla se está presionando, existen propiedades de teclado que son:
— Obsoleta — keyCode
— key
: Nombre del carácter (ej. M
)
— code
: Tecla física que se está presionando (ej. KeyM
)
— charCode
: Devuelve el valor unicode de una tecla de caracteres de la tecla presionada (ej. 77
)
Importante: Debemos de tener cuidado al usar
keyCode
, ya que para el estándar web está obsoleta, por lo que en una versión nueva de algún navegador puede ya no funcionar, para detectar la tecla presionada se recomienda usarkeypress
, ya que tiene un mejor control.
Veamos un ejemplo de cómo podemos acceder a estas propiedades y su funcionalidad:
Cuando se deba usar el evento de teclado, se recomienda validar el botón de la siguiente manera:
Ver ejemplo completo:
c — Otros eventos
Vamos a enlistar otros eventos que también son importantes o útiles al momento de interactuar con el usuario.
— focus
(Formulario): Cuando un elemento tiene el foco, que es donde está situado el cursor (campo de texto, botón, etc).
— blur
(Formulario): Cuando un elemento pierde el foco.
— change
(Formulario): Cuando se confirma un cambio en el valor del elemento (campo de texto, combo ó selector, área de texto).
— drag
(Arrastrar y soltar): Se arrastra un elemento o selección de texto (se dispara continuamente cada 350 ms).
— drop
(Arrastrar y soltar): Un elemento se deja caer o se suelta en un objetivo de caída válido.
Ver ejemplo de focus
y blur
:
Ver ejemplo de change
:
Ver ejemplo de drag
y drop
:
Si deseas ver todos los eventos que hay[ref].
vi. La interfaz evento (Event) de DOM
Event
proporciona información contextual sobre un evento al controlador que procesa el evento. Contienen información relacionada con el tipo de evento que lo acciono, comúnmente es el primer y único argumento.
Dependiendo del evento que se esté escuchando click, blur, drag, keypress, etc.
, son las propiedades y métodos que va a tener.
Ya hemos visto anteriormente algunos ejemplos type, key, code
, pero veamos otros que son igual de importantes…
a — event.target
event.target
hace referencia al objeto que lanzó el evento.
Puede ser de gran utilidad, ya que podemos aprovechar para manipular el DOM, como: cambiar estilo, acceder al data, acceder a sus elementos padre, hermanos o hijos, etc.
El siguiente ejemplo, usa tiene la función getRandomColor
[ref] que sirve para obtener hexadecimales aleatorios.
Los números hexadecimales de 3 bytes (contiene 6 dígitos), representa la intensidad del rojo, verde y azul
#RRVVAA
, sus valores van desde el00
, que es la intensidad más baja (oscuro) del color, hastaFF
, que es la intensidad más alta (claro) del color. Para obtener el color blanco#FFFFFF
(mezcla de los 3 colores en su intensidad más alta), caso contrario para el negro#000000
(intensidad más baja), para obtener los 3 colores primarios#FF0000
(rojo),#00FF00
(verde),#0000FF
(azul), para saber más…[ref]
Ver ejemplo completo:
b — event.preventDefault
Esta propiedad detiene al evento sin detener el resto de su funcionamiento, esto quiere decir que podemos volver a ejecutar la acción sin problema. Es usado cuando no queremos que un elemento DOM se comporte de la manera en que se debe comportar, lo sé suena confuso, pero mejor expliquemos con ejemplos.
Cuando usamos la etiqueta <a>
, la mayoría de los casos es para redirigirlo a otra página, con event.preventDefault
podemos evitar que se vaya a otra página y mejor haga otra cosa, veamos el ejemplo:
Cuando le damos click a la liga, podemos observar que se detiene su comportamiento normal (es dirigirte a una página) inclusive podemos mandar a imprimir en consola dos veces, y esto es gracias a que estamos usando event.preventDefault()
(evita que su comportamiento natural continue).
Ver ejemplo completo:
c — event.stopPropagation
Antes de explicar cómo funciona este método, primero veamos el siguiente ejemplo, vamos a tener un html
donde vamos a tener algo así:
Donde a cada uno de estos elementos les vamos agregar un evento, que va a estar escuchando el click
, el ejemplo completo, quedaría de la siguiente manera:
Cuando le damos click al botón podemos observar que también se lanza el evento del div, article, section
Esto se debe a los eventos van de abajo hacia arriba, y sucede por los elementos anidados (veamos la imagen del ejemplo):
Para estos casos el método event.stopPropagation()
es bastante útil, ya que se va a encargar de parar la propagación de eventos. Agreguemos al botón el método.
Si volvemos a revisar nuestra aplicación (con el nuevo cambio), podemos observar que ya no se propagan los eventos, ya que gracias a event.stopPropagation()
va a evitar cuando se le da click al botón los demás también se lancen; eso sí, si le damos click al div
también se lanza el evento del article
y section
, ya que a estos no les ha agregado el método.
Ver ejemplo completo:
En la siguiente entrega vamos a ver JavaScript — Principios SOLID
La entrega pasada vimos JavaScript — Class ES6 (Parte V)
Bibliografía y links que te puede interesar…