Logotipo de Zephyrnet

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

Fecha:

Otro aspecto de los componentes web del que aún no hemos hablado es que se llama a una función de JavaScript cada vez que se agrega o elimina un componente web de una página. Estas devoluciones de llamada del ciclo de vida se pueden usar para muchas cosas, incluso para hacer que un elemento sea consciente de su contexto.

Serie de artículos

Las cuatro devoluciones de llamada del ciclo de vida de los componentes web

Existen cuatro devoluciones de llamada del ciclo de vida que se puede utilizar con componentes web:

  • connectedCallback: Esta devolución de llamada se activa cuando el elemento personalizado es adjunto al elemento.
  • disconnectedCallback: Esta devolución de llamada se activa cuando el elemento es remoto del documento
  • adoptedCallback: Esta devolución de llamada se activa cuando el elemento es adicional a un nuevo documento.
  • attributeChangedCallback: Esta devolución de llamada se dispara cuando un atributo se modifica, agrega o elimina, siempre que se respete ese atributo.

Veamos cada uno de estos en acción.

Nuestro componente de persona post-apocalíptico

Dos representaciones del componente web una al lado de la otra, la izquierda es un humano y la derecha es un zombi.

Comenzaremos creando un componente web llamado <postapocalyptic-person>. Cada persona después del apocalipsis es un humano o un zombi y sabremos cuál en función de una clase, ya sea .human or .zombie — que se aplica al elemento padre del <postapocalyptic-person> componente. No haremos nada elegante con él (todavía), pero agregaremos un shadowRoot podemos usar para adjuntar una imagen correspondiente basada en esa clasificación.

customElements.define( "postapocalyptic-person", class extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: "open" }); }
}

Nuestro HTML se ve así:

<div class="humans"> <postapocalyptic-person></postapocalyptic-person>
</div>
<div class="zombies"> <postapocalyptic-person></postapocalyptic-person>
</div>

Insertar personas con connectedCallback

Cuando un <postapocalyptic-person> está cargado en la página, el connectedCallback() Se llama a la función.

connectedCallback() { let image = document.createElement("img"); if (this.parentNode.classList.contains("humans")) { image.src = "https://assets.codepen.io/1804713/lady.png"; this.shadowRoot.appendChild(image); } else if (this.parentNode.classList.contains("zombies")) { image.src = "https://assets.codepen.io/1804713/ladyz.png"; this.shadowRoot.appendChild(image); }
}

Esto asegura que se emita una imagen de un ser humano cuando el <postapocalyptic-person> es una imagen humana y una imagen de zombi cuando el componente es un zombi.

Tenga cuidado al trabajar con connectedCallback. Se ejecuta con más frecuencia de lo que te imaginas, disparando cada vez que el elemento se mueve y podría (desconcertantemente) incluso ejecutarse después de el nodo ya no está conectado, lo que puede ser un alto costo de rendimiento. Puedes usar this.isConnected para saber si el elemento está conectado o no.

contar personas con connectedCallback() cuando se agregan

Seamos un poco más complejos agregando un par de botones a la mezcla. Uno agregará un <postapocalyptic-person>, utilizando un enfoque de "lanzamiento de moneda" para decidir si es un humano o un zombi. El otro botón hará lo contrario, quitando un <postapocalyptic-person> al azar. Haremos un seguimiento de cuántos humanos y zombis están a la vista mientras estamos en eso.

<div class="btns"> <button id="addbtn">Add Person</button> <button id="rmvbtn">Remove Person</button> <span class="counts"> Humans: <span id="human-count">0</span> Zombies: <span id="zombie-count">0</span> </span>
</div>

Esto es lo que harán nuestros botones:

let zombienest = document.querySelector(".zombies"), humancamp = document.querySelector(".humans"); document.getElementById("addbtn").addEventListener("click", function () { // Flips a "coin" and adds either a zombie or a human if (Math.random() > 0.5) { zombienest.appendChild(document.createElement("postapocalyptic-person")); } else { humancamp.appendChild(document.createElement("postapocalyptic-person")); }
});
document.getElementById("rmvbtn").addEventListener("click", function () { // Flips a "coin" and removes either a zombie or a human // A console message is logged if no more are available to remove. if (Math.random() > 0.5) { if (zombienest.lastElementChild) { zombienest.lastElementChild.remove(); } else { console.log("No more zombies to remove"); } } else { if (humancamp.lastElementChild) { humancamp.lastElementChild.remove(); } else { console.log("No more humans to remove"); } }
});

Aquí está el código en connectedCallback() que cuenta los humanos y zombis a medida que se van sumando:

connectedCallback() { let image = document.createElement("img"); if (this.parentNode.classList.contains("humans")) { image.src = "https://assets.codepen.io/1804713/lady.png"; this.shadowRoot.appendChild(image); // Get the existing human count. let humancount = document.getElementById("human-count"); // Increment it humancount.innerHTML = parseInt(humancount.textContent) + 1; } else if (this.parentNode.classList.contains("zombies")) { image.src = "https://assets.codepen.io/1804713/ladyz.png"; this.shadowRoot.appendChild(image); // Get the existing zombie count. let zombiecount = document.getElementById("zombie-count"); // Increment it zombiecount.innerHTML = parseInt(zombiecount.textContent) + 1; }
}

Actualizar cuenta con disconnectedCallback

A continuación, podemos usar disconnectedCallback() para disminuir el número a medida que se eliminan los humanos y los zombis. Sin embargo, no podemos comprobar la clase del elemento principal porque el elemento principal con la clase correspondiente ya se ha ido en ese momento. disconnectedCallback se llama. Podríamos establecer un atributo en el elemento o agregar una propiedad al objeto, pero dado que la imagen src El atributo ya está determinado por su elemento principal, podemos usarlo como un proxy para saber si el componente web que se elimina es un humano o un zombi.

disconnectedCallback() { let image = this.shadowRoot.querySelector('img'); // Test for the human image if (image.src == "https://assets.codepen.io/1804713/lady.png") { let humancount = document.getElementById("human-count"); humancount.innerHTML = parseInt(humancount.textContent) - 1; // Decrement count // Test for the zombie image } else if (image.src == "https://assets.codepen.io/1804713/ladyz.png") { let zombiecount = document.getElementById("zombie-count"); zombiecount.innerHTML = parseInt(zombiecount.textContent) - 1; // Decrement count }
}

¡Cuidado con los payasos!

Ahora (y hablo por experiencia, por supuesto) lo único más aterrador que una horda de zombis que se abalanzan sobre tu posición es un payaso, ¡todo lo que se necesita es uno! Entonces, aunque ya estamos lidiando con zombis post-apocalípticos aterradores, agreguemos la posibilidad de que un payaso entre en escena para aún más horror. De hecho, lo haremos de tal manera que exista la posibilidad de que cualquier humano o zombi en la pantalla sea un payaso disfrazado en secreto.

Retiro lo que dije antes: un solo payaso zombi da más miedo que incluso un grupo de payasos "normales". Digamos que si se encuentra algún tipo de payaso, ya sea humano o zombi, los separamos de las poblaciones de humanos y zombis enviándolos a un documento completamente diferente: un <iframe> cárcel, si se quiere. (Escuché que "hacer el payaso" puede ser incluso más contagioso que el contagio de zombis).

Y cuando movemos un presunto payaso del documento actual a un <iframe>, no destruye ni recrea el nodo original; más bien adopta y conecta dicho nodo, llamando primero adoptedCallback luego connectedCallback.

No necesitamos nada en el <iframe> documento excepto un cuerpo con un .clowns clase. Mientras este documento esté en el iframe del documento principal, no se vea por separado, ni siquiera necesitamos el <postapocalyptic-person> código de instanciación. Incluiremos un espacio para humanos, otro espacio para zombis, y sí, la cárcel de los payasos... errr... <iframe> de diversion.

<div class="btns"> <button id="addbtn">Add Person</button> <button id="jailbtn">Jail Potential Clown</button>
</div>
<div class="humans"> <postapocalyptic-person></postapocalyptic-person>
</div>
<div class="zombies"> <postapocalyptic-person></postapocalyptic-person>
</div>
<iframe class="clowniframeoffun” src="adoptedCallback-iframe.html">
</iframe>

Nuestro botón "Agregar persona" funciona igual que en el último ejemplo: lanza una moneda digital para insertar aleatoriamente un humano o un zombi. Cuando presionamos el botón "Payaso potencial de la cárcel", se lanza otra moneda y toma un zombi o un humano, entregándoselos a <iframe> cárcel.

document.getElementById("jailbtn").addEventListener("click", function () { if (Math.random() > 0.5) { let human = humancamp.querySelector('postapocalyptic-person'); if (human) { clowncollege.contentDocument.querySelector('body').appendChild(document.adoptNode(human)); } else { console.log("No more potential clowns at the human camp"); } } else { let zombie = zombienest.querySelector('postapocalyptic-person'); if (zombie) { clowncollege.contentDocument.querySelector('body').appendChild(document.adoptNode(zombie)); } else { console.log("No more potential clowns at the zombie nest"); } }
});

Revelando payasos con adoptedCallback

En adoptedCallback determinaremos si el payaso es de la variedad humana zombie en función de su imagen correspondiente y luego cambiaremos la imagen en consecuencia. connectedCallback será llamado después de eso, pero no tenemos nada que deba hacer, y lo que haga no interferirá con nuestros cambios. Así que podemos dejarlo como está.

adoptedCallback() { let image = this.shadowRoot.querySelector("img"); if (this.parentNode.dataset.type == "clowns") { if (image.src.indexOf("lady.png") != -1) { // Sometimes, the full URL path including the domain is saved in `image.src`. // Using `indexOf` allows us to skip the unnecessary bits. image.src = "ladyc.png"; this.shadowRoot.appendChild(image); } else if (image.src.indexOf("ladyz.png") != -1) { image.src = "ladyzc.png"; this.shadowRoot.appendChild(image); } }
}

Detección de payasos ocultos con attributeChangedCallback

Finalmente, tenemos el attributeChangedCallback. A diferencia de las otras tres devoluciones de llamada del ciclo de vida, debemos observar los atributos de nuestro componente web para que se active la devolución de llamada. Podemos hacer esto agregando un observedAttributes() función a la clase del elemento personalizado y hacer que esa función devuelva una matriz de nombres de atributos.

static get observedAttributes() { return [“attribute-name”];
}

Luego, si ese atributo cambia, incluso si se agrega o elimina, el attributeChangedCallback incendios

Ahora, lo que debe preocuparte con los payasos es que algunos de los humanos que conoces y amas (o los que conocías y amabas antes de convertirse en zombis) podrían ser payasos disfrazados en secreto. Configuré un detector de payasos que mira a un grupo de humanos y zombis y, cuando haces clic en el botón "Revelar payasos", el detector (a través de medios completamente científicos y totalmente confiables que son no basado en números aleatorios eligiendo un índice) aplicar data-clown="true" al componente. Y cuando se aplica este atributo, attributeChangedCallback dispara y actualiza la imagen del componente para descubrir sus colores de payaso.

También debo señalar que el attributeChangedCallback toma tres parámetros:

  • El nombre del atributo
  • el valor anterior del atributo
  • el nuevo valor del atributo

Además, la devolución de llamada le permite realizar cambios en función de cuánto ha cambiado el atributo o en función de la transición entre dos estados.

Aquí está nuestro attributeChangedCallback código:

attributeChangedCallback(name, oldValue, newValue) { let image = this.shadowRoot.querySelector("img"); // Ensures that `data-clown` was the attribute that changed, // that its value is true, and that it had an image in its `shadowRoot` if (name="data-clown" && this.dataset.clown && image) { // Setting and updating the counts of humans, zombies, // and clowns on the page let clowncount = document.getElementById("clown-count"), humancount = document.getElementById("human-count"), zombiecount = document.getElementById("zombie-count"); if (image.src.indexOf("lady.png") != -1) { image.src = "https://assets.codepen.io/1804713/ladyc.png"; this.shadowRoot.appendChild(image); // Update counts clowncount.innerHTML = parseInt(clowncount.textContent) + 1; humancount.innerHTML = parseInt(humancount.textContent) - 1; } else if (image.src.indexOf("ladyz.png") != -1) { image.src = "https://assets.codepen.io/1804713/ladyzc.png"; this.shadowRoot.appendChild(image); // Update counts clowncount.innerHTML = parseInt(clowncount.textContent) + 1; zombiecount.innerHTML = parseInt(zombiecount.textContent) - 1; } }
}

¡Y ahí lo tienes! No solo hemos descubierto que las devoluciones de llamadas de componentes web y la creación de elementos personalizados sensibles al contexto son más fáciles de lo que pensaba, sino que detectar payasos postapocalípticos, aunque aterrador, también es más fácil de lo que pensaba. ¿Qué tipo de payasos postapocalípticos y tortuosos puede detectar con estas funciones de devolución de llamada del componente web?

Fuente: https://css-tricks.com/context-aware-web-components/

punto_img

Información más reciente

punto_img