Elaboración de plantillas HTML reutilizables
En nuestro último artículo, analizamos las especificaciones de los componentes web (elementos personalizados, DOM ocultos y plantillas HTML) en un alto nivel. En este artículo, y en los tres siguientes, pondremos a prueba estas tecnologías, las examinaremos con mayor detalle y veremos cómo podemos utilizarlas en la producción actual. Para hacer esto, crearemos un diálogo modal personalizado desde cero para ver cómo encajan las distintas tecnologías.
Serie de artículos:
- Una introducción a los componentes web.
- Elaboración de plantillas HTML reutilizables ( esta publicación )
- Crear un elemento personalizado desde cero
- Encapsulando estilo y estructura con Shadow DOM
- Herramientas avanzadas para componentes web.
plantillas HTML
Una de las características menos reconocidas, pero más poderosas, de la especificación de componentes web es el template
elemento. En el primer artículo de esta serie, definimos el elemento de plantilla como “plantillas definidas por el usuario en HTML que no se representan hasta que se solicitan”. En otras palabras, una plantilla es HTML que el navegador ignora hasta que se le indica lo contrario.
Luego, estas plantillas se pueden distribuir y reutilizar de muchas maneras interesantes. A los efectos de este artículo, veremos la creación de una plantilla para un cuadro de diálogo que eventualmente se usará en un elemento personalizado.
Definiendo nuestra plantilla
Por más simple que parezca, a template
es un elemento HTML, por lo que la forma más básica de una plantilla con contenido sería:
template h1Hello world/h1/template
Ejecutar esto en un navegador daría como resultado una pantalla vacía ya que el navegador no muestra el contenido del elemento de plantilla. Esto se vuelve increíblemente poderoso porque nos permite definir contenido (o una estructura de contenido) y guardarlo para más adelante, en lugar de escribir HTML en JavaScript.
Para utilizar la plantilla, necesitaremos JavaScript.
const template = document.querySelector('template');const node = document.importNode(template.content, true);document.body.appendChild(node);
La verdadera magia ocurre en el document.importNode
método. Esta función creará una copia de la plantilla content
y la preparará para insertarla en otro documento (o fragmento de documento). El primer argumento de la función toma el contenido de la plantilla y el segundo argumento le dice al navegador que haga una copia profunda del subárbol DOM del elemento (es decir, todos sus hijos).
Podríamos haber usado template.content
directamente, pero al hacerlo habríamos eliminado el contenido del elemento y lo habríamos agregado al cuerpo del documento más tarde. Cualquier nodo DOM solo se puede conectar en una ubicación, por lo que los usos posteriores del contenido de la plantilla darían como resultado un fragmento de documento vacío (esencialmente un valor nulo) porque el contenido se había movido previamente. El uso document.importNode
nos permite reutilizar instancias del mismo contenido de plantilla en múltiples ubicaciones.
Luego, ese nodo se agrega document.body
y se representa para el usuario. En última instancia, esto nos permite hacer cosas interesantes, como proporcionar a nuestros usuarios (o consumidores de nuestros programas) plantillas para crear contenido, similar a la siguiente demostración, que cubrimos en el primer artículo:
En este ejemplo, se proporcionan dos plantillas para representar el mismo contenido: autores y libros que han escrito. A medida que cambie el formulario, elegimos representar la plantilla asociada con ese valor. Usar esa misma técnica nos permitirá eventualmente crear un elemento personalizado que consumirá una plantilla que se definirá más adelante.
La versatilidad de la plantilla.
Una de las cosas interesantes de las plantillas es que pueden contener cualquier HTML. Eso incluye elementos de guión y estilo. Un ejemplo muy simple sería una plantilla que agrega un botón que nos avisa cuando se hace clic en él.
buttonLog click event/button
Vamos a darle estilo:
button { all: unset; background: tomato; border: 0; border-radius: 4px; color: white; font-family: Helvetica; font-size: 1.5rem; padding: .5rem 1rem;}
…y llámalo con un script realmente simple:
const button = document.getElementById('click-me');button.addEventListener('click', event = alert(event));
Por supuesto, podemos juntar todo esto usando HTML style
y script
etiquetas directamente en la plantilla en lugar de en archivos separados:
template script const button = document.getElementById('click-me'); button.addEventListener('click', event = alert(event)); /script style #click-me { all: unset; background: tomato; border: 0; border-radius: 4px; color: white; font-family: Helvetica; font-size: 1.5rem; padding: .5rem 1rem; } /style buttonLog click event/button/template
Una vez que este elemento se agregue al DOM, tendremos un nuevo botón con ID #click-me
, un selector CSS global dirigido al ID del botón y un detector de eventos simple que alertará el evento de clic del elemento.
Para nuestro script, simplemente agregamos el contenido usando document.importNode
y tenemos una plantilla de HTML en su mayor parte que se puede mover de una página a otra.
Creando la plantilla para nuestro diálogo.
Volviendo a nuestra tarea de crear un elemento de diálogo, queremos definir el contenido y los estilos de nuestra plantilla.
template script document.getElementById('launch-dialog').addEventListener('click', () = { const wrapper = document.querySelector('.wrapper'); const closeButton = document.querySelector('button.close'); const wasFocused = document.activeElement; wrapper.classList.add('open'); closeButton.focus(); closeButton.addEventListener('click', () = { wrapper.classList.remove('open'); wasFocused.focus(); }); }); /script style .wrapper { opacity: 0; transition: visibility 0s, opacity 0.25s ease-in; } .wrapper:not(.open) { visibility: hidden; } .wrapper.open { align-items: center; display: flex; justify-content: center; height: 100vh; position: fixed; top: 0; left: 0; right: 0; bottom: 0; opacity: 1; visibility: visible; } .overlay { background: rgba(0, 0, 0, 0.8); height: 100%; position: fixed; top: 0; right: 0; bottom: 0; left: 0; width: 100%; } .dialog { background: #ffffff; max-width: 600px; padding: 1rem; position: fixed; } button { all: unset; cursor: pointer; font-size: 1.25rem; position: absolute; top: 1rem; right: 1rem; } button:focus { border: 2px solid blue; } /style div div/div div role="dialog" aria-labelledby="title" aria-describedby="content" button aria-label="Close"#x2716;#xfe0f;/button h1Hello world/h1 div pThis is content in the body of our modal/p /div /div /div/template
Este código servirá como base para nuestro diálogo. Desglosándolo brevemente, tenemos un botón de cierre global, un encabezado y algo de contenido. También agregamos un poco de comportamiento para alternar visualmente nuestro cuadro de diálogo (aunque aún no es accesible). Desafortunadamente, los estilos y el contenido del script no se limitan a nuestra plantilla y se aplican a todo el documento, lo que genera comportamientos no ideales cuando se agrega más de una instancia de nuestra plantilla al DOM. En nuestro próximo artículo, utilizaremos elementos personalizados y crearemos uno propio que consuma esta plantilla en tiempo real y encapsule el comportamiento del elemento.
Serie de artículos:
- Una introducción a los componentes web.
- Elaboración de plantillas HTML reutilizables ( esta publicación )
- Crear un elemento personalizado desde cero
- Encapsulando estilo y estructura con Shadow DOM
- Herramientas avanzadas para componentes web.
Deja una respuesta