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

En mi último artículo, vimos que los componentes web no dan tanto miedo como parecen. Analizamos una configuración súper simple y creamos un perfil de servicio de citas zombies, completo con un zombie-profileelemento personalizado. Reutilizamos el elemento para cada perfil y completamos cada uno con información única utilizando el slotelemento.

Así es como surgió todo.

Eso fue genial y muy divertido (bueno, me divertí de todos modos…), pero ¿qué pasa si llevamos esta idea un paso más allá y la hacemos interactiva? Nuestros perfiles de zombies son geniales, pero para que esta sea una experiencia de citas post-apocalíptica útil, querrás darle “Me gusta” a un zombie o incluso enviarle un mensaje. Eso es lo que vamos a hacer en este artículo. Dejaremos deslizando el dedo para otro artículo. (¿Deslizar hacia la izquierda sería lo apropiado para los zombies?)

Serie de artículos

  • Los componentes web son más fáciles de lo que cree
  • Los componentes web interactivos son más fáciles de lo que cree
    (usted está aquí)
  • 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

Este artículo asume un nivel básico de conocimiento sobre componentes web. Si eres nuevo en el concepto, está totalmente bien: el artículo anterior debería brindarte todo lo que necesitas. Adelante. Leelo. Esperaré. *juguetea los pulgares* ¿Listo? Bueno.

Primero, una actualización a la versión original.

Hagamos una pausa de un segundo (está bien, tal vez más) y miremos el ::slotted()pseudoelemento. Me llamó la atención después de que se publicó el último artículo (¡gracias, Rose!) y resuelve algunos (aunque no todos) de los problemas de encapsulación que encontré. Si recuerdas, teníamos algunos estilos CSS fuera del componente templatey algunos dentro de un styleelemento dentro del archivo template. Los estilos del interior templateestaban encapsulados pero los del exterior no.

Pero ahí es donde ::slottedentra en juego. Declaramos un elemento en el selector así:

::slotted(img) {  width: 100%;  max-width: 300px;  height: auto;  margin: 0 1em 0 0;}

Ahora, imgse seleccionará cualquier elemento colocado en cualquier ranura. ¡Esto ayuda mucho!

Pero esto no resuelve todos nuestros problemas de encapsulación. Si bien podemos seleccionar cualquier cosa directamente en una ranura, no podemos seleccionar ningún descendiente del elemento en la ranura. Entonces, si tenemos un espacio con niños, como la sección de intereses de los perfiles de zombies, no podemos seleccionarlos del styleelemento. Además, si bien ::slottedtiene una excelente compatibilidad con navegadores, algunas cosas (como seleccionar un pseudoelemento, por ejemplo ::slotted(span)::after) funcionarán en algunos navegadores (hola, Chrome), pero no funcionarán en otros (hola, Safari).

Entonces, si bien no es perfecto, ::slottedde hecho proporciona más encapsulación que la que teníamos antes. Aquí está el servicio de citas actualizado para reflejar eso:

¡Volver a los componentes web interactivos!

Lo primero que me gustaría hacer es agregar una pequeña animación para darle vida a las cosas. Hagamos que nuestras fotos de perfil de zombies se desvanezcan y se traduzcan al cargar.

Cuando intenté esto por primera vez, utilicé selectores imgy ::slotted(img)para animar directamente la imagen. Pero todo lo que obtuve fue soporte para Safari. Chrome y Firefox no ejecutarían la animación en la imagen ranurada, pero la imagen predeterminada se anima bien. Para que funcione, envolví la ranura en un div con una .picclase y en su lugar apliqué la animación al div.

.pic {  animation: picfadein 1s 1s ease-in forwards;  transform: translateY(20px);  opacity: 0;}@keyframes picfadein {  from { opacity: 0; transform: translateY(20px); }  to { opacity: 1; transform: translateY(0); }}

“Me gustan” los zombies

¿No sería algo que le diera “Me gusta” a ese lindo zombie? Me refiero desde la perspectiva del usuario, por supuesto. Eso parece algo que un servicio de citas online debería tener al menos.

Agregaremos un “botón” de casilla de verificación que iniciará una animación de corazón al hacer clic. Agregamos este HTML en la parte superior del .infodiv:

input type="checkbox"label for="trigger"Like/label

Aquí hay un SVG de corazón que armé. Sabemos que a los zombies les encanta que las cosas sean terribles, por lo que su corazón será de un tono chartreuse abrasador:

svg viewBox="0 0 160 135"  fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"path d="M61 12V0H25v12H12v13H0v36h12v13h13v12h12v12h12v12h12v13h13v12h12v-12h13v-13h11V98h13V86h-1 13V74h12V61h12V25h-12V12h-12V0H98v12H85v13H74V12H61z" fill="#7aff00"//svg

Aquí están las partes importantes del CSS que se agregan al styleelemento de la plantilla:

#trigger:checked + .likebtn {  /* Checked state of the .likebtn. Flips the foreground/background color of the unchecked state. */  background-color: #960B0B;  color: #fff;}#trigger {  /* With the label attached to the input with the for attribute, clicking the label checks/unchecks the box, so we can remove the checkbox. */  display: none;}.heart {  /* Start the heart off so small it's nigh invisible */  transform: scale(0.0001);}@keyframes heartanim {  /* Heart animation */  0% { transform: scale(0.0001); }  50% { transform: scale(1); }  85%, 100% { transform: scale(0.4); }}#trigger:checked ~ .heart {  /* Checking the checkbox initiates the animation */  animation: 1s heartanim ease-in-out forwards;}

Prácticamente HTML y CSS estándar allí. Nada cómodo ni firmemente parecido a un componente web. Pero bueno, ¡funciona! Y dado que técnicamente es una casilla de verificación, es tan fácil darle “no me gusta” a un zombie como darle “Me gusta” a uno.

Zombis de mensajería

Si eres un soltero post-apocalíptico que está listo para socializar y ves a un zombie cuya personalidad e intereses coinciden con los tuyos, quizás puedas enviarle un mensaje. (Y recuerda, a los zombies no les preocupa la apariencia, solo les interesa tu cerebro).

Revelemos un botón de mensaje después de que a un zombie se le dé “Me gusta”. El hecho de que el botón Me gusta sea una casilla de verificación vuelve a ser útil, porque podemos usar su estado marcado para revelar condicionalmente la opción de mensaje con CSS. Aquí está el HTML agregado justo debajo del SVG del corazón. Puede ir prácticamente a cualquier parte siempre que sea hermano del #triggerelemento y venga después.

button type="button"Message/button

Una vez marcada la #triggercasilla de verificación, podemos mostrar el botón de mensajería:

#trigger:checked ~ .messagebtn {  display: block;}

Hemos hecho un buen trabajo evitando la complejidad hasta ahora, pero vamos a necesitar utilizar un poco de JavaScript aquí. Si hacemos clic en el botón de mensaje, esperaríamos poder enviarle un mensaje a ese zombi, ¿verdad? Si bien podríamos agregar ese HTML a nuestro archivo template, para fines de demostración, usemos algo de JavaScript para crearlo sobre la marcha.

Mi primera suposición (ingenua) fue que podríamos simplemente agregar un scriptelemento a la plantilla, crear un script encapsulado y seguir nuestro camino alegre. Sí, eso no funciona. Cualquier variable instanciada en la plantilla se instancia varias veces y bueno, JavaScript está de mal humor con las variables que no se pueden distinguir entre sí. *Agita el puño ante JavaScript malhumorado*

Probablemente habrías hecho algo más inteligente y habrías dicho: "Oye, ya estamos creando un constructor de JavaScript para este elemento, así que ¿por qué no pondrías JavaScript allí?" Bueno, tenía razón en cuanto a que eres más inteligente que yo.

Hagamos precisamente eso y agreguemos JavaScript al constructor. Agregaremos un oyente que, una vez hecho clic, crea y muestra un formulario para enviar un mensaje. Así es como se ve el constructor ahora, sabelotodo:

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));    // The "new" code    // Grabbing the message button and the div wrapping the profile for later use    let msgbtn = this.shadowRoot.querySelector('.messagebtn'),        profileEl = this.shadowRoot.querySelector('.profile-wrapper');        // Adding the event listener    msgbtn.addEventListener('click', function (e) {      // Creating all the elements we'll need to build our form      let formEl = document.createElement('form'),          subjectEl = document.createElement('input'),          subjectlabel = document.createElement('label'),          contentEl = document.createElement('textarea'),          contentlabel = document.createElement('label'),          submitEl = document.createElement('input'),          closebtn = document.createElement('button');              // Setting up the form element. The action just goes to a page I built that spits what you submitted back at you      formEl.setAttribute('method', 'post');      formEl.setAttribute('action', 'https://johnrhea.com/undead-form-practice.php');      formEl.classList.add('hello');      // Setting up a close button so we can close the message if we get shy      closebtn.innerHTML = "x";      closebtn.addEventListener('click', function () {        formEl.remove();      });      // Setting up form fields and labels      subjectEl.setAttribute('type', 'text');      subjectEl.setAttribute('name', 'subj');      subjectlabel.setAttribute('for', 'subj');      subjectlabel.innerHTML = "Subject:";      contentEl.setAttribute('name', 'cntnt');      contentlabel.setAttribute('for', 'cntnt');      contentlabel.innerHTML = "Message:";      submitEl.setAttribute('type', 'submit');      submitEl.setAttribute('value', 'Send Message');      // Putting all the elments in the Form      formEl.appendChild(closebtn);      formEl.appendChild(subjectlabel);      formEl.appendChild(subjectEl);      formEl.appendChild(contentlabel);      formEl.appendChild(contentEl);      formEl.appendChild(submitEl);      // Putting the form on the page      profileEl.appendChild(formEl);    });  }});

¡Hasta ahora, todo bien!

Antes de dar por terminado el día, hay una última cosa que debemos abordar. No hay nada peor que esa primera introducción incómoda, así que engrasemos esas ruedas de citas post-apocalípticas agregando el nombre del zombie al texto del mensaje predeterminado. Esa es una pequeña y agradable comodidad para el usuario.

Como sabemos que el primer intervalo del zombie-profileelemento es siempre el nombre del zombie, podemos tomarlo y pegar su contenido en una variable. (Si su implementación es diferente y el orden de los elementos cambia, es posible que desee utilizar una clase para asegurarse de obtener siempre la correcta).

let zname = this.getElementsByTagName("span")[0].innerHTML;

Y luego agrega esto dentro del detector de eventos:

contentEl.innerHTML = "Hi " + zname + ",nI like your braaains...";

Eso no estuvo tan mal, ¿verdad? Ahora sabemos que los componentes web interactivos no dan tanto miedo como la escena de las citas zombies... bueno, ya sabes a qué me refiero. Una vez que superas el obstáculo inicial de comprender la estructura de un componente web, empieza a tener mucho más sentido. Ahora que ya cuenta con habilidades en componentes web interactivos, ¡veamos qué se le ocurre! ¿Qué otros tipos de componentes o interacciones harían que nuestro servicio de citas zombies fuera aún mejor? Hazlo y compártelo en los comentarios.

Deja un comentario

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

Subir