Como habrás observado en artículos anteriores, uno de los problemas que tenemos al trabajar con código Javascript, es que no tenemos una forma nativa y sencilla para ejecutar código Javascript sin que sea global a toda la página. Necesitamos una forma de encapsular nuestro Javascript. Realmente, si que existe. Son los WebComponents.
¿Qué son los WebComponents?
Los WebComponents son un conjunto de tecnologías (HTML, CSS y Javascript) que unidas nos permiten crear nuestras propias etiquetas HTML, y que de forma opcional, tengan una encapsulación real y funcionen a nivel local o de componente, sin necesidad de frameworks o librerías de terceros.
Si te interesa saber más, tenemos un curso especialmente dedicado a WebComponents.
WebComponents en Astro
Astro nos permite utilizar WebComponents nativos, simplificándolos de una forma muy ingeniosa, utilizando los propios componentes .astro
para simplificarlos. Por ejemplo, veamos un componente que nos permite calificar un elemento de 0
a 5
. He utilizado círculos de emoji, pero podría personalizarse con cualquier otra cosa.
El componente de .astro
nos permite definir el value
inicial y el icon
para mostrar el rating. De esta forma, podríamos utilizarlo tal que así:
---
import CustomRating from "./components/CustomRating.astro";
---
<CustomRating value="3" />
El componente tomará el valor 3
y mostrará círculo rojo como emoji activado, ya que no he proporcionado otro. El componente se implementaría de la siguiente forma:
---
const { value = 2, icon = "🔴" } = Astro.props;
---
<custom-rating data-value={value} data-icon={icon}>
<button></button>
</custom-rating>
<script>
class CustomRating extends HTMLElement {
connectedCallback() {
const button = this.querySelector("button");
let value = Number(this.dataset.value);
let icon = this.dataset.icon;
const updateButton = () => {
button.textContent = icon?.repeat(value) + "⚫".repeat(5 - value);
}
updateButton();
button?.addEventListener("click", () => {
value = (value + 1) % 6;
this.dataset.value = value;
updateButton();
});
}
}
customElements.define("custom-rating", CustomRating);
</script>
Observa que <custom-rating>
es un custom element, una etiqueta propia nuestra que se caracteriza porque lleva un guión -
en su nombre. Las props las estamos guardando en los atributos data del elemento. Luego, en su interior hemos definido un <button>
que de momento está vacío.
Bien, ahora vamos al código Javascript:
- 1️⃣ Creamos una clase
CustomRating
que extiende de una etiqueta HTML normal. - 2️⃣ El método
connectedCallback()
se ejecuta al principio (al insertar en el DOM). - 3️⃣ Añadimos dentro del botón los iconos necesarios.
- 4️⃣ Si el usuario hace click en el botón, aumentamos en uno
value
. - 5️⃣ Finalmente, no olvidar registrar el componente con
customElements.define()
.
Como Astro procesa los bloques <script>
, si utilizamos varias veces el componente desde Astro, la primera vez ejecutará el Javascript (que registra el componente), pero las siguientes sólo utilizará la parte de marcado, que es lo único que necesitamos para usarlo.