> Manuales > Desarrollo en Javascript del lado del cliente

Qué es el DOM, para qué sirve el DOM en el contexto de Javascript y el desarrollo web. Explicaciones esenciales para aprender acceder y manipular los elementos de la página.

Modelo de objetos del documento (DOM)

Nos vamos a introducir en uno de los temas más importantes en el desarrollo del lado del cliente con Javascript, el DOM. En este tema aprenderás que todo elemento representado en la página web tiene la correspondencia con un objeto Javascript y que usando esos objetos somos capaces de realizar cualquier tipo de dinamismo en la página. Además explicaremos los principales mecanismos de acceso a los objetos del DOM.

Para explicar el DOM de Javascript vamos a tratar los siguientes puntos.

Qué es el DOM

DOM son las siglas de Document Object Model o Modelo de Objetos del Documento. Es un conjunto de objetos que modelizan cada uno de los elementos que aparecen en el documento HTML visible, es decir, en la página web que el navegador está mostrando en este momento.

Por medio del DOM podremos controlar el documento de manera global y a los distintos elementos que se encuentran en la página, para hacer todo tipo de efectos y dinamismos, responder a las acciones del usuario de manera visual y en general cualquier modificación del documento actual en el navegador.

Cuando se carga una página, el navegador crea una jerarquía de objetos en memoria que sirven para controlar los distintos elementos de dicha página. Con Javascript y la nomenclatura de objetos que hemos aprendido, podemos trabajar con esa jerarquía de objetos, acceder a sus propiedades e invocar sus métodos.

Para qué sirve el DOM

Como desarrolladores Javascript usamos el DOM para controlar programáticamente los elementos que hay en la página. Con ello conseguimos hacer todo tipo de comportamientos que puedan ser necesarios para implementar las funcionalidades que requieran las aplicaciones.

Cualquier cosa que necesites hacer sobre una página web la tienes que hacer mediante el acceso y manipulación del DOM. Por ejemplo crear e insertar nuevos elementos en la página dinámicamente, hacer que ciertos elementos se reaccionen cuando el usuario interaccione con ellos, etc.

Cualquier elemento de la página se puede controlar de una manera u otra mediante Javascript accediendo al objeto correspondiente, el que modeliza aquel elemento que deseas transformar. Además, dependiendo del elemento que tengas que alterar puede tener unas propiedades y métodos distintos. Por ejemplo, no es lo mismo una división (elemento <div>) que un campo de texto (elemento <input>). Es crucial conocer bien el modelo de objetos del documento para poder controlar perfectamente las páginas web con Javascript.

Ejemplo de control del documento

Antes de empezar a ver rigurosamente el DOM, vamos a ver el ejemplo típico de acceso a una propiedad del objeto documento que nos sirve para cambiar el aspecto dinámicamente mediante el cambio del color de fondo de la página.

La propiedad que almacena el color de fondo de la página web se llama bgColor y pertenece al objeto document. A esa propiedad podemos asignarle cualquier color y cambiará el fondo con ese color. Se accede al objeto documento mediante el objeto window y luego document, para llegar finalmente a la propiedad bgColor.

window.document.bgColor = "red"

Como ya aprendimos en el artículo dedicado al BOM, el objeto window no hace falta referenciarlo, ya que todos los objetos del navegador dependen de window y se permite simplemente obviarlo. Por tanto, esta línea sería equivalente:

document.bgColor = "red"

Si ejecutamos esta sentencia en cualquier momento cambiamos el color de fondo de la página a rojo.

Hay que fijarse en que la propiedad bgColor tiene la "C" en mayúscula. Es un error típico equivocarse con las mayúsculas y minúsculas en Javascript, que es un lenguaje donde sí importa el tamaño de la caja. Si no lo escribimos bien no funcionará y en algunos casos equivocarnos entre mayúsculas y minúsculas ni siquiera arrojará un mensaje de error, con lo que el problema puede ser difícil de detectar.

Vamos a ver un ejemplo de página en la que cambiamos el color de fondo usando Javascript.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ejemplo de cambio del color de fondo</title>
</head>
<body>
  <p>En esta página no estamos indicando ningún color de fondo... 
    por lo que sería blanco, o bien del color predeterminado del navegador.</p>
  
  <script>
    // El color lo vamos a cambiar mediante Javascript
    document.bgColor = 'red';
  </script>
</body>
</html>

En esta página no se ha especificado ningún color, por lo que tendrá el color de fondo blanco. Sin embargo en el script Javascript hemos cambiado esa propiedad bgColor del documento, por lo que saldrá con color de fondo rojo.

Este no es el único ejemplo que conoces. En los ejemplos que hemos visto hasta ahora en el Manual de Javascript también hemos hecho uso de métodos de objetos del DOM, como es el caso del método write() del objeto document para escribir un texto en la página.

document.write("El texto a escribir")

Acceso a los objetos que forman parte del DOM

Acabamos de ver un ejemplo de acceso a un elemento del DOM como es el documento. A este elemento accedemos siempre a través del objeto window, que como es global nos permiten simplemente no mencionarlo. Por tanto, a simple vista, el objeto document también es global y lo tenemos ahí disponible con solo nombrarlo en el código Javascript.

Sin embargo, todos los elementos de la página tienen su correspondiente objeto en el DOM, al que podemos acceder para realizar cualquier cosa con un elemento en particular, como mostrarlo, ocultarlo, cambiar su contenido, insertar otros elementos en él y cualquier cosa que nos podamos imaginar.

Existen diversos mecanismos de acceso al DOM que queremos mostrar de manera individual.

Acceso a los elementos por su identificador

Todos los elementos del HTML pueden tener un identificador definido por su atributo id. Ese identificador debería ser único y nos sirve entre otras cosas para referirnos de manera inequívoca al objeto del DOM que modeliza ese elemento.

Veamos un elemento HTML con su identificador.

<p id="miParrafo">Este es un párrafo.</p>

Para acceder a el elemento mediante el identificador usamos el método getElementById() que tiene el objeto document. Veamos el siguiente código Javascript.

let parrafo = document.getElementById("miParrafo");

Esto ha creado un variable llamada parrafo que tiene una referencia al objeto del DOM que modeliza la etiqueta <p> anterior. Ahora podríamos acceder a las propiedades o métodos de ese párrafo para hacer cosas con él.

parrafo.textContent = 'Cambio el texto del párrafo con Javascript.';

Con la línea anterior estamos cambiando el texto que hay dentro del párrafo.

Acceso a los elementos por su selector

Ahora vamos a conocer el método querySelector() del objeto document, que nos permite acceder a los elementos a partir de un selector.

Con "selector" nos referimos a los selectores de CSS que ya debes de conocer.

Por ejemplo, tenemos la siguiente división:

<div id="interfaz">Esto es otro elemento con ID</div>

Ahora podemos acceder mediante querySelector() a ese elemento, con este código Javascript.

let division = document.querySelector('#interfaz');

Y una vez que tenemos esa referencia al objeto del DOM podemos lanzar métodos sobre él o cambiar sus propiedades.

division.innerHTML = 'Hola a <b>todos</b>';

Con el código anterior cambiamos la propiedad innerHTML que sirve para actualizar el contenido del elemento con una cadena que puede tener etiquetas HTML.

Ahora bien, puede que uses selectores que encajasen con más de un elemento. Por ejemplo tenemos este elemento HTML de lista:

<ul>
  <li class="item">item 1</li>
  <li class="item">item 2</li>
  <li class="item">item 3</li>
</ul>

Podría usar este código para acceder a un elemento de la lista y modificar su color del texto:

let item = document.querySelector('.item');
item.style.color = 'orange';

Por cierto, ya es hora de decir que no hace falta crear una variable con el elemento para luego cambiar una de sus propiedades. Es perfectamente válido hacer esas dos acciones en una única línea de código.

document.querySelector('.item').style.color = 'orange';

Podríamos pensar que con el identificador '.item' se seleccionarían los tres ítem de esa lista. Sin embargo eso no funciona así con el método querySelector(), que te entrega siempre el primer elemento seleccionado con ese selector. Por tanto, en el ejemplo anterior solamente cambiaríamos el color del texto del primer elemento de la lista.

Acceder a un conjunto de elementos con su selector

Si lo que queremos es acceder a todos los elementos que encajen con un selector, entonces usamos el método querySelectorAll() del objeto document.

Veamos un ejemplo que nos permitiría acceder a todos los párrafos de la página web.

let parrafos = document.querySelectorAll('p');

Al seleccionar elementos con querySelectorAll() no obtenemos un objeto del DOM sino una colección de objetos. Incluso, aunque esa colección solamente tenga un elemeto, o ninguno, seguiría siendo una colección. Por ello, para poder hacer cosas con los elementos seleccionados debemos realizar un bucle. Podríamos iterar fácilmente por esa lista de párrafos seleccionados con una función forEach de los arrays e iterables de Javascript.

parrafos.forEach(function(parrafo) {
  console.log(parrafo.innerText);
});

Con eso conseguimos que se muestren todos los contenidos textuales de los párrafos en la consola del navegador.

Por ejemplo, si los elementos de lista actual, que tenían la clase '.item' quisiéramos cambiarles el color de fondo por amarillo, podríamos usar este código.

document.querySelectorAll('li.item').forEach(function(elemento) {
  elemento.style['background-color'] = 'yellow';
});

Como ves, no necesito crear una variable para almacenar todos los elementos de la lista, sino que puedo enlazar directamente con el método forEach() para iterarlos. Otro detalle que puede que te resulte interesante es ver cómo accedemos a una propiedad de style que se llama 'background-color', con la notación de corchetes, como si fuera un array. Esto es obligatorio porque en este caso 'background-color' tiene un guión y podría confundirse con un operador aritmético resta.

Acceso a elementos por su clase CSS

También podemos usar el método getElementsByClassName() del objeto document para acceder a los elementos que tienen una clase CSS en particular.

Supongamos que tenemos los siguientes elementos en nuestro HTML:

<p class="claseEjemplo">Hola!</p>
<p class="claseEjemplo">Adiós!</p>

Podríamos acceder a ellos mediante Javascript con un código como este:

let parrafos = document.getElementsByClassName("claseEjemplo");

Luego podríamos recorrelos con un forEach() como hemos visto antes, pero también mediante un bucle for normal:

for (let i = 0; i < parrafosDeClase.length; i++) {
  parrafosDeClase[i].textContent = `Soy el párrafo número ${i + 1}`;
}

El código anterior cambiará los textos de los párrafos, indicando el número del párrafo de cada uno de ellos.

Jerarquía de objetos del documento

Es importante entender también que los objetos del documento forman una jerarquía, igual que el propio código HTML. Como sabes, en el HTML tenemos una estructura de etiquetas en forma de árbol. Sin embargo, la jerarquía de objetos que modelizan los elementos de la página en Javascript es un poco distinta.

En realidad lo que tenemos en Javascript es un objeto document, del que cuelgan propiedades simples como la que hemos visto bgColor, métodos como write() y algunos arrays de elementos, como los enlaces de la página, enlaces y formularios. A su vez, de los formularios cuelga un array con los elementos que tenemos.

Para ilustrar esta organización de los elementos del DOM podemos ver la siguiente imagen.

Representación muy parcial de la jerarquía del Modelo de objetos del documento (DOM)

No debes entender esta imagen como una especificación formal, ni mucho menos, sino como un esquema de la estructura jerárquica de objetos del documento. Hemos querido ilustrar que document es un objeto, que tiene propiedades y métodos y algunos arrays con conjuntos de otros objetos como las imágenes o los enlaces.

Las propiedades de un objeto pueden ser a su vez otros objetos

Muchas de las propiedades del objeto document son a su vez otros objetos. Por ejemplo, el array de formularios (forms) contiene cada uno de los objetos formulario que encontramos en el código HTML de la página.

Cada uno de esos elementos del array forms es un objeto de formulario, que tiene sus propiedades como action o method y métodos como submit(). Incluso los formularios tienen un array de elementos de formulario, el array elements, que contiene nuevos objetos que modelizan cada uno de los campos que tiene ese formulario, como cajas de texto, elementos de selección, cajas de verificación o lo que sea que se haya colocado en el formulario.

Acceso los objetos a través de la jerarquía de objetos del DOM

Antes vimos que existían métodos como getElementById() que nos permitían acceder a los elementos del documento. Todos esos métodos los puedes usar y son realmente cómodos, porque te dan un acceso rápido a los objetos del DOM, pero además queremos que sepas que esos mismos elementos los puedes acceder en muchos casos usando la jerarquía de objetos del documento.

Por ejemplo, imaginemos que tenemos un formulario en la página, que está puesto como primero de los formularios en el documento HTML y tiene este código:

<form id="miform" name="miformulario">
  <select name="selector" id="selector">
    <option value="x">X</option>
    <option value="y">Y</option>
  </select>
</form>

Si queremos acceder al formulario para cambiar, por ejemplo, su propiedad action, podríamos hacerlo de varias maneras, entre ellas:

// Usando el atributo id
document.getElementById('miform').action = "http://www.desarrolloweb.com/enviar.php";
// Usando el array de forms con el valor seteado en el atributo name del formulario
document.forms['miformulario'].action = "http://www.desarrolloweb.com/enviar.php";
// Usando el array de forms con el índice del formulario
document.forms[0].action = "http://www.desarrolloweb.com/enviar.php";

Las tres líneas de código anteriores tendrían el mismo efecto. Puedes usarlas indistintamente. Sin embargo no recomendaría usar la tercera alternativa, indexando el array de forms con el índice numérico del formulario. Primero porque es poco claro a qué formulario te estás refiriendo y, sobre todo, porque te podría dejar de funcionar si colocas otros formularios en el código HTML y con ello cambie el índice del formulario al que te quieres referir.

Recorridos a los elementos de los arrays de objetos del documento

Como ya dijimos en el artículo dedicado al BOM, toda la jeraquía empieza en el objeto window, aunque no era necesario mencionar a window para acceder a cualquier objeto de la jerarquía del navegador. Luego, para todo lo que es el DOM tenemos el objeto document, donde podemos encontrar propiedades que son arrays, por ejemplo la propiedad images es un array con todas las imágenes de la página web. También encontramos arrays para guardar los enlaces de la página, los applets, los formularios y las anclas.

Cuando una página se carga, el navegador construye en memoria la jerarquía de objetos. De manera adicional, construye también estos arrays de objetos. Por ejemplo, en el caso de las imágenes, va creando el array colocando en la posición 0 la primera imagen, en la posición 1 la segunda imagen y así hasta que las introduce todas. Vamos a ver un bucle que recorre todas las imágenes de la página e escribe en la página su propiedad src, que contiene la URL donde está situada la imagen.

for (let i=0; i<document.images.length; i++){ 
   document.write(document.images[i].src) 
   document.write("<br>") 
}

Utilizamos la propiedad length del array images para limitar el número de iteraciones del bucle. Luego utilizamos el método write() del objeto document pasándole el valor de cada una de las propiedades src de cada imagen.

Ahora vamos a ver el uso de otro array de objetos. En este caso vamos a acceder un poco más dentro de la jerarquía para llegar a la matriz elements de los campos de formulario, que contiene cada uno de los elementos que componen el formulario. Para ello tendremos que llegar al formulario de la página, al que podremos acceder por el array de formularios, y dentro de él a la propiedad elements, que es otro array de objetos. Para cada elemento del formulario vamos a escribir su propiedad value, que corresponde con el valor del atributo value que colocamos en HTML o con lo que el usuario haya escrito como valor en los campos.

for (let i=0; i<document.forms[0].elements.length; i++){ 
   document.write(document. forms[0].elements[i].value) 
   document.write("<br>") 
}

Es un bucle muy parecido al que teníamos para recorrer las imágenes, con la diferencia que ahora recorremos el vector de elements, al que accedemos por la jerarquía de objetos pasando por el array de formularios en su posición 0, que corresponde con el primer formulario de la página.

Código de una página de ejemplo para trabajar con el DOM

Ahora, antes de acabar dejamos el código de una página web con varios de los ejemplos que hemos visto en este artículo, por si quieres usar este código como base para practicar con las funciones de acceso al DOM que hemos aprendido.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ejemplo de acceso al DOM</title>
</head>
<body>
  <p id="miParrafo">Este es un párrafo en el documento.</p>
  <p>Segundo párrafo</p>
  <p>Tercer párrafo</p>

  <div id="interfaz">Esto es otro elemento con ID</div>
  
  <ul>
    <li class="item">item 1</li>
    <li class="item">item 2</li>
    <li class="item">item 3</li>
  </ul>

  <p class="claseEjemplo">Hola!</p>
  <p class="claseEjemplo">Adiós!</p>

  <form id="miform" name="miform">
    <select name="selector" id="selector">
      <option value="x">X</option>
      <option value="y">Y</option>
    </select>
  </form>

  <script>

    document.fgColor = 'gray';

    // Acceso mediante identificador
    let parrafo = document.getElementById("miParrafo");
    parrafo.textContent = 'Cambio el texto del párrafo con Javascript.';

    let division = document.querySelector('#interfaz');
    division.innerHTML = 'Hola a <b>todos</b>';

    document.querySelector('.item').style.color = 'orange';

    let parrafos = document.querySelectorAll('p');

    parrafos.forEach(function(parrafo) {
      console.log(parrafo.innerText);
    });

    document.querySelectorAll('li.item').forEach(function(elemento) {
      elemento.style['background-color'] = 'yellow';
    });

    let parrafosDeClase = document.getElementsByClassName("claseEjemplo");
    for (let i = 0; i < parrafosDeClase.length; i++) {
      parrafosDeClase[i].textContent = `Soy el párrafo número ${i + 1}`;
    }

    document.getElementById('miform').action = "http://www.desarrolloweb.com/enviar.php";
    document.forms[0].action = "http://www.desarrolloweb.com/enviar.php";
    document.forms['miform'].action = "http://www.desarrolloweb.com/enviar.php";
  </script>
</body>
</html>

Conclusión

En este artículo hemos conocido el DOM, o modelo de objetos del documento. Hemos aprendido qué es el DOM y por qué es tan importante en Javascript y el desarrollo de aplicaciones web del lado del cliente. Además se han explicado de manera detallada y con ejemplos distintas de las variantes que puedes usar para el acceso a objetos que modelizan los elementos de la página en el DOM.

Paralelamente, has podido apreciar que los objetos del DOM tienen una estructura jerárquica y que existen diversos mecanismos de acceso a ellos. Con todos estos mecanismos tienes una buena variedad de alternativas para acceder a cualquier elemento de la página y manipularlo.

En el próximo artículo veremos con detalle las propiedades y los métodos que tenemos en el objeto document.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual