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 slot
y 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 template
es 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 template
elemento 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-warning
componente web; ya sabes, como advertencia cuando el apocalipsis zombie esté sobre nosotros.
Luego está elslot
slot
es simplemente otro elemento HTML como template
. Pero en este caso, slot
personaliza lo que template
se 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 slot
es 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 name
atributo.
template pThe slot name="whats-coming"Zombies/slot are coming!/p/template
El name
atributo 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 slot
nos 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-warning
componente en la página como cualquier otro div
o lo que sea. Pero también incluimos un span
elemento que hace referencia al name
atributo de nuestro slot
. Y lo que hay entre eso span
es 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 slot
intercambio 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:
open
simplemente significa que JavaScript desde fuera :root
puede 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 slot
y slot
se 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 style
elemento 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 style
elemento 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 template
DOM 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 style
elemento template
como 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-profile
elemento 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