Single Page Application

29-3-2020

La aplicación de página única permite trabajar con una única request incial al servidor y luego de ello obtener la información que requerimos mediante AJAX, sin recargar la página.

El usuario tiene la idea que está clickeando una nueva página cuando en realidad no lo está haciendo, y el resultado final es una página que carga muy, muy rápido para el usuario.

Veamos cómo lo hacemos.

Primeramente tenemos links con los cuales trabajaremos y un espacio, vacío inicialmente, donde meteremos lo que traigamos vía ajax. Este espacio está dentro de las etiquetas MAIN. Podría ser cualquier otro tipo de etiqueta.

<a class="nav-link" href="#" id="perfil">Perfil</a>
<a class="nav-link" href="#" id="mensajes">Mensajes</a>

<main></main>

Adviértase que los links no conducen a ninguna parte: lo importante, con lo que vamos a trabajar, será el ID de cada uno.

Primeramente creamos una función que nos traerá el contenido solicitado vía la URL, o sea, usando el método GET:

function ajax(url, metodo) {
//el segundo parámetro "get" será opcional, ya que se puede llamar a esta función con post, pero si no se indica este segundo parámetro, el default es GET
  let httpMetodo = metodo || "get";
  let xhr = new XMLHttpRequest();
  xhr.open(httpMetodo, url);
  xhr.send();

  return xhr;
}

Usando querySelector() y querySelectorAll(), metemos en una variable los links y main, para poder trabajar con éstos más adelante:

let main = document.querySelector("main");
let links = document.querySelectorAll("a");

Como tenemos más de un link, usamos querySelectorAll(), para abarcarlos a todos. Y cada uno será un item dentro de la variable links, que es un array.

//usamos forEach() para ir a buscar cada link
links.forEach(link => {
//le agregamos un escuchador que espere por el click
  link.addEventListener("click", e => {
//impedimos que el link haga lo que hace por defecto, es decir, irse a buscar el recurso a otra página
    e.preventDefault();
//tomamos el id de cada link y lo metemos en una variable
    let id = link.id;
//vamos a usar la propiedad hash de location (propiedad del evento) y vamos a asignarle el ID como hash. Para que quede spa.html#perfil y spa.html#mensajes
    location.hash = id;
  });
});

//le agregamos un escuchador a window. Vamos a escuchar si cambia el hash
window.addEventListener('hashchange', () => {
//metemos el current hash en una variable hash
    let hash = location.hash
//vamos a obtener del hash solamente la parte que está después del signo numeral, y le agregamos.html Eso es porque queremos apuntar al contenido que tenemos en perfil.html y mensajes.html
    let archivo = hash.split('#')[1] + '.html'
//busco mediante ajax la url del archivo.
    let xhr = ajax(archivo);
//le agrego un escuchador al evento de carga de la página "load"
    xhr.addEventListener("load", () => {
//si la página cargó y devolvió algo que no sea un error... status 200...
      if (xhr.status == 200) {
        //main.innerHTML = JSON.parse(xhr.response).plantilla //PARA SERVIDOR
//meto en main la respuesta, que será el recurso html que traje.
        main.innerHTML = xhr.response;
      }
    });    

})

//Leo la URL para determinar la página inicial, en casoq ue el usuario no haya clickeado nada aún...
let hash = location.hash
let archivo = hash.split('#')[1] + '.html'
let xhr = ajax(archivo);
xhr.addEventListener("load", () => {
  if (xhr.status == 200) {
    //main.innerHTML = JSON.parse(xhr.response).plantilla //PARA SERVIDOR
    main.innerHTML = xhr.response;
  }
});