Desarrollo de Web Components V1 frente a Polymer 2

  • Por
Revisión de la sintaxis y procedimientos para crear un elemento personalizado (custom element) con Web Components V1, frente al desarrollo con Polymer 2.

En el pasado artículo hemos ofrecido una introducción teórica a los objetivos de Web Components y Polymer 2, pero no estará completa sin algo de código para que podamos experimentar lo sencillo que puede llegar a ser crear nuestro primer componente.

El objetivo en esta ocasión es ofrecer un ejemplo de elemento personalizado creado con Web Components y enfrentar este código al que necesitaríamos para hacer ese mismo componente en Polymer 2, apreciando las similitudes y también las diferencias. Por tanto, este artículo nos servirá como introducción práctica de tanto Web Components V1 como de Polymer 2.

Qué es un Custom Element

Pero antes de comenzar cabe aclarar qué significa "Custom Element", la principal de las especificaciones de Web Components. Básicamente un elemento personalizado es un nuevo elemento de HTML creado por nosotros mismos para resolver cualquier tipo de necesidad que no esté implementada en el HTML estándar.

Así pues, cuando mencionamos "componente" en general, casi siempre estamos refiriéndonos a un "custom element". Los componentes pueden ser sencillos o complejos. Los complejos a menudo se apoyan en componentes más sencillos para resolver las tareas. Una aplicación generalmente será un componente que contiene a su vez un árbol de componentes que se relacionan entre sí y trabajan para resolver un conjunto de necesidades de un negocio.

Debes saber que, el marco de la tecnología "Web Components", custom element es solo una de sus especificaciones y, por lo general, para implementar componentes nos tenemos que apoyar en otras de las especificaciones, como "Shadow Dom" o "Templates". Puedes saber más sobre generalidades de las especificaciones en el artículo Qué son Web Components. https://desarrolloweb.com/articulos/que-son-web-components.html

Cómo se construye un custom element en Web Components V1

Para definir un elemento personalizado se debe utilizar una clase, de programación orientada a objetos. Nos referimos lógicamente a clases Javascript ES6 como las que explicamos en el manual de la versión 2015 del estándar ECMAScript (ES6). Posteriormente tenemos que asociar tal clase como un nuevo elemento dentro del navegador. Ambos pasos los veremos representados en el siguiente código.

// defino la clase con la que implemento el componente
class HolaComponentes extends HTMLElement {
  constructor() {
    super();
    this.attachShadow( {mode: 'open'} ).innerHTML = '<p>Hola! soy un Custom Element!</p>';
  }
}

// asocio la clase a un nombre de componente
customElements.define('hola-componentes', HolaComponentes);

En el primer pedazo de este código se define una clase llamada HolaComponentes. Como manda el estándar V1, esta clase debe heredar de un elemento HTML. En este caso usamos "HTMLElement", que es la clase que define un elemento HTML predeterminado. La herencia, como debes saber, se indica mediante la declaración extends, de la que tienes más información en el artículo de Herencia en las clases de Javascript ES6.

Como código de la clase tenemos básicamente un constructor, que crea un poco de HTML para usarlo como contenido de nuestro componente. Ese código del constructor usa métodos que pertenecen al API de Web Components V1. Por tanto, se trata de Javascript estándar, como attachShadow(), método que sirve para añadir "Shadow Dom" al componente, que básicamente crea un nuevo nodo hijo, dentro del elemento personalizado, del que pueden a su vez colgar un árbol de etiquetas. El "shadow DOM" tiene la característica de encapsular el árbol de etiquetas dependientes de un elemento y {mode: 'open'} hace referencia al nivel de encapsulación. A ese nuevo nodo Shadow DOM le estamos agregando simplemente un párrafo, gracias a manipular directamente su propiedad innerHTML.

Nota: Si a pesar de estas explicaciones este código te parece muy extraño quizás te ayudaría saber algo más sobre las clases ES6 y sobre la especificación de Shadow DOM.

En la última línea de código, se define propiamente el nuevo elemento personalizado. La declaración de la clase ES6 anterior era simplemente una clase, creada en la memoria de Javascript, pero gracias a customElements.define() podemos usarla como implementación de un nuevo componente. Para ello debemos indicar el nombre del nuevo elemento personalizado que se está creando: "hola-componentes" y el nombre de la clase con la que se implementa el componente "HolaComponentes".

Una vez definido el nuevo elemento ya lo puedes usar. Para ello simplemente tienes que colocar en el cuerpo de la página la etiqueta HTML que se ha definido en la creación del componente.

<hola-componentes></hola-componentes>
Nota: todos los custom elements necesitan en su nombre un caracter "-" al menos, para distinguirlos de etiquetas estándar HTML existentes o futuras, que no llevan nunca un guión.

Para que quede perfectamente claro, dejamos el listado de este ejercicio en una página HTML completa.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Test de Custom Element</title>
</head>
<body>
  
  <hola-componentes></hola-componentes>

  <script>
    class HolaComponentes extends HTMLElement {
      constructor() {
        super();
        this.attachShadow( {mode: 'open'} ).innerHTML = '<p>Hola! soy un Custom Element!</p>';
      }
    }
    customElements.define('hola-componentes', HolaComponentes);
  </script>
</body>
</html>

Fíjate que el código anterior es HTML estándar y Javascript nativo, que soportan los navegadores compatibles con Web Components V1. Para el resto de los navegadores solo funcionaría si se carga el correspondiente polyfill, cosa que no hemos hecho todavía. En el momento de escribir este artículo, si lo abres en Chrome, Opera o Safari funcionará. No necesitas cargar ninguna librería extra gracias a su soporte nativo!

Cómo crear este componente con Polymer 2

Polymer 2 se apoya al máximo en lo que el propio navegador dispone, por lo que no hay mucha diferencia entre crear un componente nativo o un componente creado con Polymer 2. Pero además te ofrece algunas nuevas características, como mayor facilidad para crear Shadow Dom, utilidades para mantener el estado del componente, para gestionar eventos personalizados y sincronizar los valores de las propiedades entre fuera y dentro del componente, etc. En adelante iremos aprendiendo todas estas ventajas, ahora nos centraremos en un código suficientemente simple para comenzar sin demasiada dificultad.

Si queremos usar Polymer 2 lo primero que tendremos que hacer es importar la librería, lo que se consigue con un HTML Import.

Nota: HTML Import es otra de las especificaciones de Web Components que sirve para importar, adquirir, incorporar código que está en otros documentos HTML.

Por facilitar la labor vamos a usar el CDN de Polymer 2, aunque más adelante veremos que lo común es usar gestores de dependencias como Bower para traerse el código de Polymer, o de otros elementos en los que queramos apoyarnos para hacer una aplicación.

<link rel="import"  href="https://polygit.org/components/polymer/polymer-element.html">

Una vez realizado el import el navegador ya conoce Polymer, por lo que a continuación podemos crear nuestra clase ES6 para implementar el componente. Por último tendremos que hacer el correspondiente customElements.define() para registrar el elemento en el navegador, igual que antes.

El próximo código observarás que Polymer 2 puede ser muy similar en su modo de trabajo a cómo se creó el componente anteriormente, usando el estándar Web Components V1, sin apoyarse en ninguna librería.

class HolaComponentes extends Polymer.Element {
  static get template() { return document.getElementById('mi-template') }
  static get is() { return 'hola-componentes'; }
}

customElements.define(HolaComponentes.is, HolaComponentes);

Las diferencias que debes percibir son:

  • Extendemos la clase HolaComponentes de Polymer.Element en lugar de HTMLElement.
  • Creamos el shadow dom a partir de un template. Para ello definimos una propiedad getter llamada "template" que se encarga de acceder a la página, buscar una etiqueta TEMPLATE a través de su id "mi-template".
  • Creamos una propiedad getter que indica el nombre del custom element que estamos implementando.

Luego el customElements.define() es prácticamente igual. Solo que nos apoyamos en la propiedad "is" de la clase, para acceder al nombre del custom element que se está definiendo.

Para que esto funcione, en el cuerpo de la página debería figurar el template al que se está accediendo en "static get template()", que podría tener una forma como esta:

<template id="mi-template">
  <p>Hola! soy un Polymer Element simple!</p>
</template>
Nota: Si quieres saber más de templates te recomendamos la lectura del artículo sobre la etiqueta template de Web Components.

Para acabar, y a fin de no dejar dudas, colocamos el código completo de una página en la que se usa este componente creado con Polymer 2.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">

  <link rel="import"  href="https://polygit.org/components/polymer/polymer-element.html">

  <title>Test de componente usando Polymer 2</title>
</head>
<body>
  
  <template id="mi-template">
    <p>Hola! soy un Polymer Element simple!</p>
  </template>
  
  <script>
    class HolaComponentes extends Polymer.Element {
      static get template() { return document.getElementById('mi-template') }
      static get is() { return 'hola-componentes'; }
    }

    customElements.define(HolaComponentes.is, HolaComponentes);>
  </script>
  
  <hola-componentes></hola-componentes>
    
</body>
</html>
Nota: Quizás pueda haber decepcionado un poco la cantidad de código necesaria para crear un elemento de Polymer, en relación a la cantidad de código usando el estándar Web Componentes V1, pues es incluso algo mayor. Para un componente tan simple como este no hay mucha ganancia entre usar Polymer o limitarnos al Javascript nativo. No te preocupes, más adelante, cuando las cosas se pongan un poco más interesantes, observaremos todas las ventajas de apoyarse en Polymer.

Con esto hemos podido realizar nuestro primer acercamiento con código al estándar de Web Components V1 y a Polymer 2, para crear un primer custom element mediante dos alternativas de código sencillo: Javascript nativo Vs Polymer.

Solo cabe aclarar que las cosas no se hacen exactamente en Polymer 2 como hemos visto en este artículo, pues existen algunos otros detalles que todavía no conoces y que debemos de explicar para producir un código más ajustado a la práctica habitual.

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir