Los componentes web son más fáciles de lo que cree

Cuando iba a una conferencia (cuando éramos capaces de hacer ese tipo de cosas) y veía a alguien hacer una presentación sobre componentes web, siempre pensaba que era bastante ingenioso (sí, aparentemente, soy de 1950), pero siempre Parecía complicado y excesivo. Mil líneas de JavaScript para ahorrar cuatro líneas de HTML. Inevitablemente, el orador pasaba por alto los montones de JavaScript para que funcionara o entraba en detalles insoportables y mis ojos se ponían vidriosos al pensar si mis viáticos cubrían los refrigerios.

Pero en un proyecto de referencia reciente para facilitar el aprendizaje de HTML (agregando zombis y chistes tontos, por supuesto), el completista que hay en mí decidió que tenía que cubrir todos los elementos HTML de la especificación. Más allá de esas presentaciones en conferencias, esta fue mi primera introducción a los elementos sloty template. Pero cuando intenté escribir algo preciso y atractivo, me vi obligado a profundizar un poco más.

Y aprendí algo en el proceso: los componentes web son mucho más fáciles de lo que recuerdo.

Serie de artículos

  • Los componentes web son más fáciles de lo que cree (usted está aquí)
  • Los componentes web interactivos son más fáciles de lo que cree
  • Usar componentes web en WordPress es más fácil de lo que piensas
  • Sobrealimentar elementos integrados con componentes web "es" más fácil de lo que cree
  • Los componentes web sensibles al contexto son más fáciles de lo que cree
  • Las pseudoclases y pseudoelementos de componentes web son más fáciles de lo que cree

O los componentes web han recorrido un largo camino desde la última vez que me sorprendí soñando despierto con bocadillos en una conferencia, o dejé que mi miedo inicial a ellos me impidiera conocerlos verdaderamente, probablemente ambas cosas.

Estoy aquí para decirle que usted, sí, puede crear un componente web. Dejemos nuestras distracciones, miedos e incluso nuestros bocadillos en la puerta por un momento y hagamos esto juntos.

Empecemos con eltemplate

A templatees un elemento HTML que nos permite crear, bueno, una plantilla: la estructura HTML para el componente web. Una plantilla no tiene por qué ser una gran cantidad de código. Puede ser tan simple como:

template  pThe Zombies are coming!/p/template

El templateelemento es importante porque mantiene unidas las cosas. Es como los cimientos del edificio; es la base sobre la que se construye todo lo demás. Usemos este pequeño fragmento de HTML como plantilla para un apocalyptic-warningcomponente web; ya sabes, como advertencia cuando el apocalipsis zombie esté sobre nosotros.

Luego está elslot

slotes simplemente otro elemento HTML como template. Pero en este caso, slotpersonaliza lo que templatese representa en la página.

template  pThe slotZombies/slot are coming!/p/template

Aquí, hemos colocado (¿es eso siquiera una palabra?) la palabra “Zombis” en el marcado de la plantilla. Si no hacemos nada con la ranura, el contenido predeterminado será el contenido entre las etiquetas. En este ejemplo, serían "zombis".

Usar slotes muy parecido a tener un marcador de posición. Podemos usar el marcador de posición tal como está o definir algo más para que vaya allí. Hacemos eso con el nameatributo.

template  pThe slot name="whats-coming"Zombies/slot are coming!/p/template

El nameatributo le dice al componente web qué contenido va y en qué parte de la plantilla. En este momento, tenemos una ranura llamada whats-coming. Suponemos que los zombis serán lo primero en el apocalipsis, pero eso slotnos da cierta flexibilidad para incluir algo más, como si termina siendo un robot, un hombre lobo o incluso un componente web del apocalipsis.

Usando el componente

Técnicamente hemos terminado de "escribir" el componente y podemos colocarlo en cualquier lugar donde queramos usarlo.

apocalyptic-warning  span slot="whats-coming"Halitosis Laden Undead Minions/span/apocalyptic-warningtemplate  pThe slot name="whats-coming"Zombies/slot are coming!/p/template

Ves lo que hicimos allí? Colocamos el apocalyptic-warningcomponente en la página como cualquier otro divo lo que sea. Pero también incluimos un spanelemento que hace referencia al nameatributo de nuestro slot. Y lo que hay entre eso spanes lo que queremos cambiar por "Zombis" cuando el componente se renderice.

Aquí hay un pequeño problema que vale la pena mencionar: los nombres de elementos personalizados deben tener un guión. Es sólo una de esas cosas que debes saber antes de empezar. La especificación lo prescribe para evitar conflictos en caso de que HTML publique un nuevo elemento con el mismo nombre.

¿Sigues conmigo hasta ahora? No da demasiado miedo, ¿verdad? Bueno, menos los zombies. Todavía tenemos un poco de trabajo por hacer para que el slotintercambio sea posible, y ahí es donde comenzamos a adentrarnos en JavaScript.

Registrar el componente

Como dije, necesitas algo de JavaScript para que todo esto funcione, pero no es el código súper complejo, de mil líneas y profundo que siempre pensé. Ojalá pueda convencerte a ti también.

Necesita una función constructora que registre el elemento personalizado. De lo contrario, nuestro componente es como los no-muertos: está ahí pero no completamente vivo.

Aquí está el constructor que usaremos:

// Defines the custom element with our appropriate name, apocalyptic-warningcustomElements.define("apocalyptic-warning",  // Ensures that we have all the default properties and methods of a built in HTML element  class extends HTMLElement {    // Called anytime a new custom element is created    constructor() {      // Calls the parent constructor, i.e. the constructor for `HTMLElement`, so that everything is set up exactly as we would for creating a built in HTML element      super();      // Grabs the template and stores it in `warning`      let warning = document.getElementById("warningtemplate");      // Stores the contents of the template in `mywarning`      let mywarning = warning.content;      const shadowRoot = this.attachShadow({mode: "open"}).appendChild(mywarning.cloneNode(true));    }  });

Dejé comentarios detallados allí que explican las cosas línea por línea. Excepto la última línea:

const shadowRoot = this.attachShadow({mode: "open"}).appendChild(mywarning.cloneNode(true));

Estamos haciendo mucho aquí. Primero, tomaremos nuestro elemento personalizado ( this) y crearemos un operativo clandestino, es decir, DOM en la sombra. mode: opensimplemente significa que JavaScript desde fuera :rootpuede acceder y manipular los elementos dentro del DOM oculto, algo así como configurar el acceso por puerta trasera al componente.

A partir de ahí, se crea el DOM oculto y le agregamos un nodo. Ese nodo será una copia profunda de la plantilla, incluidos todos los elementos y el texto de la plantilla. Con la plantilla adjunta al DOM oculto del elemento personalizado, el atributo sloty slotse hace cargo de hacer coincidir el contenido con el lugar donde debe ir.

Mira esto. Ahora podemos colocar dos instancias del mismo componente, generando contenido diferente simplemente cambiando un elemento.

Aplicar estilo al componente

Es posible que hayas notado el estilo en esa demostración. Como es de esperar, tenemos absolutamente la capacidad de diseñar nuestro componente con CSS. De hecho, podemos incluir un styleelemento directamente en el archivo template.

template  style    p {      background-color: pink;      padding: 0.5em;      border: 1px solid red;    }  /style    pThe slot name="whats-coming"Zombies/slot are coming!/p/template

De esta manera, los estilos tienen como alcance directamente el componente y nada se filtra a otros elementos en la misma página, gracias al DOM oculto.

Ahora, en mi cabeza, asumí que un elemento personalizado tomaba una copia de la plantilla, insertaba el contenido que había agregado y luego lo inyectaba en la página usando el DOM oculto. Si bien eso es lo que parece en el front-end, no es así como realmente funciona en el DOM. El contenido de un elemento personalizado permanece donde está y el DOM oculto se coloca encima como una superposición.

Y dado que el contenido está técnicamente fuera de la plantilla, cualquier selector o clase descendiente que usemos en el styleelemento de la plantilla no tendrá ningún efecto en el contenido ranurado. Esto no permite la encapsulación completa de la manera que esperaba o esperaba. Pero dado que un elemento personalizado es un elemento, podemos usarlo como selector de elementos en cualquier archivo CSS antiguo, incluida la hoja de estilo principal utilizada en una página. Y aunque el material insertado técnicamente no está en la plantilla, sí está en el elemento personalizado y los selectores descendientes del CSS funcionarán.

apocalyptic-warning span {  color: blue;}

¡Pero cuidado! Los estilos en el archivo CSS principal no pueden acceder a elementos en el templateDOM o sombra.

Juntemos todo esto

Veamos un ejemplo, digamos un perfil para un servicio de citas zombies, como uno que podrías necesitar después del apocalipsis. Para aplicar estilo tanto al contenido predeterminado como a cualquier contenido insertado, necesitamos tanto un styleelemento templatecomo un estilo en un archivo CSS.

El código JavaScript es exactamente el mismo excepto que ahora estamos trabajando con un nombre de componente diferente, zombie-profile.

customElements.define("zombie-profile",  class extends HTMLElement {    constructor() {      super();      let profile = document.getElementById("zprofiletemplate");      let myprofile = profile.content;      const shadowRoot = this.attachShadow({mode: "open"}).appendChild(myprofile.cloneNode(true));    }  });

Aquí está la plantilla HTML, incluido el CSS encapsulado:

template  style    img {      width: 100%;      max-width: 300px;      height: auto;      margin: 0 1em 0 0;    }    h2 {      font-size: 3em;      margin: 0 0 0.25em 0;      line-height: 0.8;    }    h3 {      margin: 0.5em 0 0 0;      font-weight: normal;    }    .age, .infection-date {      display: block;    }    span {      line-height: 1.4;    }    .label {      color: #555;    }    li, ul {      display: inline;      padding: 0;    }    li::after {      content: ', ';    }    li:last-child::after {      content: '';    }    li:last-child::before {      content: ' and ';    }  /style  div    slot name="profile-image"img src="https://assets.codepen.io/1804713/default.png"/slot  /div  div    h2slot name="zombie-name" part="zname"Zombie Bob/slot/h2    spanspanAge:/span slot name="z-age"37/slot/span    spanspanInfection Date:/span slot name="idate"September 12, 2025/slot/span    div      spanInterests: /span      slot name="z-interests"        ul          liLong Walks on Beach/li          librains/li          lidefeating humanity/li        /ul      /slot    /div    spanspanApocalyptic Statement: /span slot name="statement"Moooooooan!/slot/span  /div/template

Aquí está el CSS de nuestro zombie-profileelemento y sus descendientes de nuestro archivo CSS principal. Observe la duplicación allí para garantizar que tanto los elementos reemplazados como los elementos de la plantilla tengan el mismo estilo.

zombie-profile {  width: calc(50% - 1em);  border: 1px solid red;  padding: 1em;  margin-bottom: 2em;  display: grid;  grid-template-columns: 2fr 4fr;  column-gap: 20px;}zombie-profile img {  width: 100%;  max-width: 300px;  height: auto;  margin: 0 1em 0 0;}zombie-profile li, zombie-profile ul {  display: inline;  padding: 0;}zombie-profile li::after {  content: ', ';}zombie-profile li:last-child::after {  content: '';}zombie-profile li:last-child::before {  content: ' and ';}

¡Todos juntos ahora!

Si bien todavía hay algunos errores y otros matices, espero que ahora se sienta más capacitado para trabajar con los componentes web que hace unos minutos. Sumerge los dedos de los pies como lo hemos hecho aquí. Tal vez agregue un componente personalizado a su trabajo aquí y allá para tener una idea de cómo funciona y dónde tiene sentido.

Eso es realmente todo. Ahora bien, ¿a qué le tienes más miedo, a los componentes web o al apocalipsis zombie? Podría haber dicho componentes web en un pasado no muy lejano, pero ahora estoy orgulloso de decir que los zombies son lo único que me preocupa (bueno, eso y si mis viáticos cubrirán los refrigerios…)

Deja un comentario

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

Subir