En este artículo vamos a utilizar el API de Custom elements (Elementos HTML personalizados) para crear nuevas etiquetas y utilizarlas en nuestro código HTML, en futuras publicaciones explicaremos como se usan en conjunto con los otros 3 estándares. Para crear un componente web se utilizan 4 tecnologías principales estándares de la web.

  • Custom elements o elementos HTML personalizados
  • Shadow DOM, DOM en las sombras.
  • HTML Templates, Plantillas HTML.
  • Carga de módulos o componentes externos
    • HTML imports con la etiqueta <link rel="import">
    • <script type="module">, cargando módulos usando el tag script. Este tecnología sustituye a los html imports.

Para más información sobre componentes web te recomiendo que leas este artículo Cómo crear mejores aplicaciones con los fascinantes componentes web

Elementos HTML Personalizados

El estándar Custom elements nos indica dos maneras de extender la funcionalidad del HTML:

  • Crear nuestros propios elementos desde cero, nuevos elementos a los que le agregamos toda la funcionalidad que sea necesaria.
  • Extender la funcionalidad de elementos ya existentes. Lamentablemente esta característica no esta soportada por todos los navegadores modernos. En la versión v0 si había soporte, pero esa versión ya está obsoleta.

Para entender la diferencia, en el primer caso podríamos crear un elemento llamado <mi-boton>, al que tendríamos que agregar estilos y funcionalidad desde cero para que se comporte como un botón.

En el segundo, podemos crear un elemento <mi-boton-extendido>, el cual extiende de la etiqueta <button>, entonces este componente si tendría los estilos, eventos y demás comportamientos de un botón, es decir, hereda el comportamiento de <button> y entonces solo se le agregaría algún comportamiento extra para cumplir con el objetivo en mente.

Veamos la primera forma para crear un nuevo tipo de elemento, desde cero:

Hay algunas cosas importantes que remarcar en el código:

  • Todos los elementos deben tener un prefijo, esto es un requisito para evitar que en futuras versiones de HTML las nuevas etiquetas colisionen con los elementos creados por ti u otros programadores.
  • Podemos registrar un elemento en dos pasos, creando la clase y pasando su referencia como parámetro en el método customElements.define o utilizar una clase anónima como se hizo con <mi-boton-2> directamente en el método customElements.define.
  • Una clase en Javascript no es una clase como en otros lenguajes de programación orientada a objetos, realmente es como un tipo de función especial que te permite utilizar herencia de prototipos de una forma más familiar y limpia.
  • En el constructor siempre debemos de invocar la función super(), de esta manera obtenemos la herencia, pues provoca que se invoque este mismo método en la cadena de prototipos/herencia. Si no se invoca, el navegador web te mostrara un caught ReferenceError: Must call super constructor in derived class before accesing 'this' or returning from derived constructor.

Ahora vamos a crear un nuevo elemento basado en uno ya existente, solo pondremos el ejemplo del código, realmente como mencionamos antes, no todos navegadores aún soportan este estándar, esperemos que en futuras versiones lo hagan:

Las principales diferencias cuando extendemos la funcionalidad de elementos nativos es que seguimos utilizando el nombre de la etiqueta nativa y agregamos el atributo is para indicar que será del tipo elemento que definimos.

Además en la definición (método customElements.define) utilizamos un tercer parámetro donde podemos indicar de que elemento HTML vamos a extender, extends.

Métodos del ciclo de vida de un elemento

Los custom elements tiene funciones que se ejecutan en un determinado momento de su existencia, de tal manera que el autor puede ejecutar acciones, cambios o inicialización de datos para cumplir con alguna operación necesaria.

Si revisas la consola de la página creada por codepen, el orden en que son ejecutados estos callbacks es:

constructor: Cuando el elemento es creado
attributeChangedCallback: Cuando cambia un atributo
connectedCallback: Cuando el elemento es insertado en el documento

Para probar disconnectedCallback solo inspecciona el elemento <mi-mensaje> y elimínalo. Un mensaje de alerta parecerá informando de la eliminación.

Cuando se crea el elemento, attributeChangedCallback se ejecuta al definir por primera vez el atributo antes de que el elemento sea insertado en el DOM.

Sincronización de atributos y propiedades

Recuerda que las propiedades y los atributos son cosas diferentes, aunque los atributos se ocupen para reflejar el estado de un elemento, no son lo mismo. Un atributo se ocupa normalmente para declarar información del elemento en el código HTML y reflejar su estado, una propiedad forma parte de la instancia del elemento.

Para obtener un atributo se utiliza elemento.getAttribute(nombreAtributo), para obtener una propiedad se utiliza elemento.propiedad.

Para definir un atributo se utiliza elemento.setAttribute(nombreAtributo, valor), para definir una propiedad se utiliza elemento.propiedad = valor.

Los atributos se guardan en una propiedad elemento.attributes de la instancia del elemento.

Para entender mejor esto, vamos a crear un ejemplo un poco más complejo, donde se implementa la sincronización de atributos, propiedades y el estado del elemento. Este nuevo elemento consta de dos propiedades principales, msj y casiVisible, estos se sincronizan con los atributos msj y casi-visible.

Cuando el atributo casi-visible está declarado, el elemento se opaca hasta casi  desaparecer, además el borde negro desaparece. Puedes cambiar el contenido del atributo msj para que el mensaje del elemento cambie.

Cuando decimos que se sincronizan es que un cambio en la propiedad, se refleja en el atributo y viceversa.

Puedes hacer varias pruebas, inspeccionando los elementos, agrega y elimina el atributo casi-visible.

También puedes inspeccionar el elemento y modificar el atributo msj para ver que sucede.

Las mismas pruebas las puedes hacer con las propiedades, utilizando google chrome inspecciona los elementos y en la consola ejecutas el código de abajo:

$0.msj = 'HOLA MODIFICANDO EL MENSAJE';
$0.casiVisible = false; // muestra el elemento
$0.casiVisible = true; // casi oculta el elemento

En todos los casos notarás cambios en el estado del elemento y en el contenido del mensaje.

En siguientes publicaciones veremos como utilizar el estándar template o plantilla y shadow DOM (DOM en las sombras), luego veremos el uso de HTML imports y JS modules, para al final crear componentes completos y ver como se comunican entre ellos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.