JavaScript en el Navegador

Introducción

La mayoría de los navegadores incluyen un intérprete de JavaScript.

Ejecutar código

Código embebido

Por un lado es fácil ejecutar javascript en el navegador. Basta con crear un fecho demo.html:

<!DOCTYPE HTML>
<html>
<body>
<span onclick="alert('Hello World!');">Click Here</span>
</body>
</html>

Mostrará el texto “Click Here”, y al hacer ‘click’ mostrará una alerta con el texto “Hello World”.

Referencias a ficheros

Podemos crear un fichero externo, referenciarlo en la página web y llamar a las funciones que en él aparecen.

Fichero con el código JavaScript codigo.js:

function showAlert () {
   window.alert('Hello World!')
}

Y lo referenciamos en el HTML:

<!DOCTYPE HTML>
<html>
<body>
<span onclick="showAlert();">Click Here</span>
</body>
</html>

Consola

En Firefox podemos abrir una consola asociada a una página web mediante Ctrl+May+K. En dicha consola podemos ver algunas de las variables globales asociadas:

>> window
Window → file:///C:/Users/C08937/Documents/src/javascript/ex01/02.html

Si hacemos click en Window, Firefox nos mostrará todos los métodos y parámetros asociados. De los muchos que hay, podemos probar:

>> window.alert('Pepe')

Pero, sobretodo, destacamos:

>> window.document

Este último es el que contiene la estructura DOM (Document Object Model).

Peculiaridades

La cantidad de cosas que el código JavaScript puede hacer en el navegador es muy limmitada para minimizar los riesgos de seguridad. A esto se le llama sandboxing.

No todos los navegadores cumplen en igual medida los estándares. Programar en el navegador es un ambiente hostil.

DOM (Document Object Model)

La página web es un documento. Daremos una visión rápida por culturilla, aunque en la práctica tenderemos a usar la librería jQuery.

En la consola del navegador:

>> window.document.documentElement
<html>

A partir de aquí, tenemos una estructura jerárquica que tendrá una pinta parecida a la siguiente:

  • html

    • head

      -title

    • body

      • h1
      • div
        • p
          • a
        • ...

Cada nodo tendrá un nodeType. Dichos tipos vienen definidos en la propia definición del documento:

>> window.document.TEXT_NODE
3
>> window.document.COMMENT_NODE
8

Advertencia

el DOM es una interfaz genérica y no está especialmente bien integrado con JavaScript. Por ejemplo childNodes es una instancia de NodeList que no contiene métodos como slice o forEach.

Existen métodos que permiten obtener referencias a nodos próximos:

  • childNodes
  • firstChild
  • previousSibling
  • nextSibling
  • lastChild
  • parentNode

Encontrar elementos

Por ejemplo:

>> window.document.getElementsByTagName('a')
HTMLCollection [....]
>> window.document.getElementsByTagName('a')[0].href
"file:///C:/Users/C08937/AppData/Roaming/Mozilla/Firefox/Profiles/3870q4ru.default/ScrapBook/data/20140808180713/index.html"

De la misma forma tenemos métodos como:

  • window.document.getElementById
  • getElementsByClassName

Modificar el documento

Por ejemplo:

  • removeChild
  • appendChild
  • insertBefore
  • replaceChild
  • createTextNode

Atributos

Normalmente son accesibles como propiedades de la instancia del nodo.

El contenido textual del nodo viene:

  • textContent

También se puede usar:

  • getAttribute
  • setAttribute

Layout

Los elementos de una página web ocupan una posición en el navegador. Podemos obtener la información asociada mediante:

  • offsetHeight: altura que ocupa el elemento
  • offsetWidth: ancho que ocupa el elemento
  • clientHeight: altura disponible en el interior del elemento
  • clientWidth: anchura disponible en el interior del elemento
  • getBoundingClientRect: devuelve el bounding box en la pantalla (top, bottom, left, right).
  • pageXOffset / pageYOffset: nos devuelve el offset asociado al scrolling.

Estilos

Por ejemplo:

<p><a href=".">Normal link</a></p>
<p><a id="para" href="." style="color: green">Green link</a></p>

Podemos editarlo en JavaScript mediante:

var para = document.getElementById("para");
console.log(para.style.color);
para.style.color = "magenta";

CSS

Query Selectors

querySelectorAll

Posicionar y animar

Events

Usaremos addEventListener(<evento>, <callback>):

var button = document.querySelector("button");
button.addEventListener("click", function(event) {
  console.log("Button clicked.");
});

También tenemos removeEventListener.

Por otro lado, tenemos onclick para los nodos.

Los callback reciben como parámetro el objeto event:

Propagación

Los padres reciben eventos producidos en los hijos.

Un event handler puede llamar al método stopPropagation:

event.stopPropagation()

También se puede inspeccionar target que contiene el nodo en el que se originó el evento:

event.target

Podemos evitar que ocurra el comportamiento predefinido:

event.preventDefault()

Advertencia

no conviene hacer esto salvo que tengamos un buen motivo para hacerlo.

Eventos de teclado

Tenemos:

  • keydown
  • keyup
  • keypress

Después inspeccionamos el objeto event para ver si su contenido está asociado a las teclas que nos interesan. Para ello veremos el contenido de keyCode y ctrlKey:

addEventListener("keydown", function(event) {
  if (event.keyCode == 32 && event.ctrlKey)
    console.log("Continuing!");
});

Eventos del ratón

Por ejemplo:

  • mouseup
  • mousedown
  • click
  • dblclick

El evento puede generar:

event.pageX
event.pageY

El movimiento del ratón:

  • mousemove
  • mouseover
  • mouseout

Advertencia

estos eventos también se propagan. Es útil relatedTarget en este caso.

Scroll events

Tenemos el evento:

  • scroll

Y podemos analizar los valores de:

document.body.scrollHeight
innerHeight
innerWidth
pageXOffset
pageYOffset
...

Focus events

Los eventos:

  • focus
  • blur

son lanzados cuando un elemento tiene el focus.

Load event

Este evento se lanza mientra carga la página:

  • load
  • beforeunload: antes de cerrar una página.

Ejecución de un script

Qué lanza la ejecución de un script:

  • Encontrar <script>
  • Que se dispare un evento
  • La función requestAnimationFrame (llama a una función antes del redraw de otra página)

Advertencia

los script nunca se ejecutan en paralelo. Si un script tarda mucho en ejecutarse, la página se congela. Existen los Web Workers, que permiten generar un entorno de ejecución aislado.

Web workers funcionan mediante el envío de mensajes:

var squareWorker = new Worker("code/squareworker.js");
squareWorker.addEventListener("message", function(event) {
  console.log("The worker responded:", event.data);
});
squareWorker.postMessage(10);
squareWorker.postMessage(24);

Se puede poner timeout a la ejecución de funciones:

var bombTimer = setTimeout(function() {
  console.log("BOOM!");
}, 500);  // 500ms

Los timeout también pueden eliminarse:

clearTimeout(bombTimer);

De la misma forma que para requestAnimationFrame existe cancelAnimationFrame.

Para funciones que deben ejecutarse cada cierto periodo de tiempo tenemos setInterval y clearInterval:

var ticks = 0;
var clock = setInterval(function() {
  console.log("tick", ticks++);
  if (ticks == 10) {
    clearInterval(clock);
    console.log("stop.");
  }
}, 200);

Debouncing

Es la técnica por la que evitamos cierto comportamiento con eventos que se disparan muy rápido.