Ya el Lazy Loading es nativo en HTML:
<img src="imagen.png" loading="lazy">
Pero todavía no está 100% soportado por los navegadores.
Referencia: can i use
DOM y Web API
Y entonces nació internet...
Accede a la versión más actualizada de este contenido
¿Qué es el DOM?
Web APIs modernas
Operaciones básicas
Leer nodos
NodeLists vs Array
Crear y agregar
Otras formas de agregar
Atributos y propiedades
Eliminar nodos
Operaciones en lote
Workshop 1: Fetch
Presentación del proyecto
Descargando información y creando nodos
Enriqueciendo la información
Usando la API de internacionalización del browser
Comparte el resultado
Eventos
Reaccionar a lo que sucede en el DOM
Event propagation
Event delegation
Workshop 2: Lazy loading
Presentación del proyecto
Nuestro propio plugin Lazy Loading
Creando las imagenes con JavaScript
Intersection Observer
Aplicando Lazy loading
Comparte el resultado
Workshop 3
Proyectos propuestos
Librerías relacionadas
¿Y jQuery?
¿Y JSX?
Conclusiones
Conclusiones
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Convierte tus certificados en títulos universitarios en USA
Antes: $249
Paga en 4 cuotas sin intereses
Termina en:
Jonathan Alvarez
Aportes 34
Preguntas 4
Ya el Lazy Loading es nativo en HTML:
<img src="imagen.png" loading="lazy">
Pero todavía no está 100% soportado por los navegadores.
Referencia: can i use
no les pasa que ven algo asi y les dan ganas de aplicarlo a todos los proyectos de los cursos anteriores
Hay varias maneras de obtener la imagen del container sin necesidad de usar querySelector, como estas:
container.childNodes[0] // childNodes devuelve un nodeList con todos los hijos, tomamos el primero que es la imagen.
container.children[0] // Devuelve un HTMLCollection, es similar al nodeList, así que también podemos tomar el primer elemento que sería la imagen.
container.firstChild = Es un atributo que contiene el primer elemento hijo del container, que sería en este caso la imagen.
IMPORTANTE: Este método devuelve el primer elemento del container, por lo que si hay comentarios o texto como primer elemento devolverá esto y no el nodo.
container.firstElementChild = Es muy similar al fisrtChild, pero este solamente devuelve nodos HTML ignorando cualquier comentario o texto.
Woooow, esta clase me voló la cabeza, uno siempre piensa que sabe JavaScript hasta que llegan estos cursos increíbles.
Como ya se habia comentado el lazy loading ya funciona nativamente aunque no es soportado por todos los navegadores. Por supuesto que crear nuestro propio observer nos da mas control sobre el codigo y sobre el comportamiento deseado.
En mi codigo uso el lazy-loading nativo si el navedador lo soporta, si no uso el observer de la clase.
Mis Apuntes 😄
index.js
.
import {registerImage} from './lazy'
const maximun = 121;
const minimun = 1;
const random = () => Math.floor(Math.random()*(maximun - minimun)+ minimun)
const createImageNode = () =>
{
const container = document.createElement('div');
container.className = "p-4";
const imagen = document.createElement('img');
imagen.className = "mx-auto";
imagen.width = '320';
/*
1. forma
Si no queremos que una imagen cargue tenemos que eliminar
la parte que la carga ya que esta linea trae la url de la imagen
por lo tanto la hara cargar siempre.
Pasaremos este trabajo de cargar la imagen al lazy loading
2.forma
La informacion de la url se la dejaremos a la imagen pero
utilizaremos el dataset que es una propiedad de html
Dataset se utiliza mucho para comunicar informacion entre html
y js, es muy comun tener diferentes data-? para comunicar la info
*/
//imagen.src = `https://randomfox.ca/images/${random()}.jpg`;
// Esto agregara a la propieda data-src de mi imagen la url
imagen.dataset.src = `https://randomfox.ca/images/${random()}.jpg`
container.appendChild(imagen)
return container
};
const mountNode = document.getElementById('imagenes');
const addboton = document.querySelector('button');
const addImage = () =>
{
const newImage = createImageNode();
mountNode.append(newImage);
registerImage(newImage);
}
addboton.addEventListener('click', addImage);
.
lazy.js
const isIntersecting = (entry) =>{
return entry.isIntersecting
}
const loadImage = (entry) =>{
const container = entry.target;
/*obtenemos la imagen a partir del contenedor y podremos acceder
a dataset.src y obtener la url
*/
//const imagen = container.querySelector('img');
//otra forma es obteniendo el hijo con las propiedades firstChil o lastChild
// que en este caso serian las imagenes que son los hijos de nuestro contenedor
const imagen = container.firstChild;
const url = imagen.dataset.src;
//cargamos la imagen poniendo una url valida
imagen.src = url;
/*
1. forma
En la accion le agregaremos la propiedad src a nuestra imagen
Asi nos aseguramos de que solo se pondra la url real en el momento
en el que se ejecuta la accion que solo pasa cuando el elemento es
visible en pantalla
imagen.src = `https://randomfox.ca/images/${random()}.jpg`;
*/
observer.unobserve(container);
}
const observer = new IntersectionObserver((entries) => {
entries
.filter(isIntersecting)
.forEach(loadImage)
})
export const registerImage = (imagen) => {
observer.observe(imagen)
}```
Cuando conocí dataset, sabia que sería amor a primera vista♥ jjajaja. Es que piensenlo, crear tus propios atributos? Te deja oportunidad para cualquier cosa.
Estudiare mas esta clase ya que es muy importante pero también difícil de entender
Los atributos data-*
son muy utilizados para guardar información, a la que después podemos acceder con JavaScript utilizando la propiedad dataset
.
También se pueden guardar desde JavaScript añadiendo propiedades como si fuera una clase.
<!-- Desde el HTML -->
<div id="nodo" data-saludo="Hola" data-saludo-dos="Hello"></div>
// Para acceder a los datos que guardamos desde JavaScript
const div = document.getElementById("nodo");
console.log(div.dataset) // DOMStringMap {saludo: 'Hola', saludoDos: 'Hello'}
// Nos regresa un DOMStringMap como objeto con los datos que guardamos
const saludo = div.dataset.saludo; // Hola
// Si te fijas los datos que tienen más de un guión los guarda como camelcase 🐫
const saludoDos = div.dataset.saludoDos; // Hello
// Agregar más valores al dataset desde JavaScript
div.dataset.saludoTres = "Salut"
Botón eliminar verificando que el mountNode tenga hijos:
const removeButton = document.querySelector('#remove');
removeButton.className = 'text-white px-3 py-2 rounded-lg bg-red-900 focus:outline-none';
const removeImage = () => {
if (mountNode.hasChildNodes()) {
const container = mountNode.lastElementChild;
mountNode.removeChild(container);
}
}
removeButton.addEventListener('click', removeImage);
en mi caso yo intercepte directamente la imagen en el entry
const isIntersecting=(entry)=>{
return entry.isIntersecting;
}
const loadImage=(entry)=>{
const imagen=entry.target;
const url = imagen.dataset.src;
//imagen.src=url;
imagen.src=url;
observer.unobserve(imagen)
}
const observer=new IntersectionObserver((entries)=>{
entries.filter(isIntersecting).forEach(loadImage);
})
export const registerImage=(imagen)=>{
//IntersectionObserver-->observerImagen
observer.observe(imagen);
}
👏👏Uau! Excelente el uso de las tabs de devTools incluyendo el debugger
😎Mejorando workshop 1 con dataset y sweetalert.
En el workshop anterior intente hacer algo mas. Quería que cuando hiciera click en el titulo del aguacate se mostrara un alert con la descripción de aguacate.
Tenia claro que para mostrarlo iba a usar sweetalert para mostrar un alert nice🤗.
Después sabia que podía traer un solo elemento de la API con su id.
🤔Todo estaba claro, pero no sabía como grabar ese id en algún lugar cercano o en el mismo title del aguacate para hacer la petición con ese id. Es hasta esta clase que encontré la solución. Aquí dejo mi resultado 💚. Y invito a que intenten hacerlo.
![](
Este curso esta en mi top5 de los mejores que he tomado en platzi. siento que he aprendido mucho. excelente profesor
Aquí esta mi aporte utilizando la API https://randomfox.ca/floof
Index.js
import {subscribeImageObserver} from './lazy'
console.log('Actitud de Viernes :)')
function createImageNode() {
const img_container = document.createElement('div');
img_container.className="p-4";
const img = document.createElement('img');
img.className ="mx-auto";
img.width = "320";
img_container.appendChild(img);
return img_container;
}
const mountNode = document.querySelector("#images");
const btnAgregar = document.getElementById("btnagregar");
const btnLimpiar = document.getElementById("btnlimpiar");
btnLimpiar.onclick = function(){
while(mountNode.firstChild){
mountNode.removeChild(mountNode.firstChild);
}
}
btnAgregar.onclick = function(){
const nodo = createImageNode();
mountNode.appendChild(nodo);
subscribeImageObserver(nodo);
}
Lazy.js
const URL_RANDOMFOX = "https://randomfox.ca/floof";
async function ramdomUrlImagen(){
const request = await fetch(URL_RANDOMFOX);
const response = await request.json();
return response.image;
}
const isIntersecting = (entry) => {
return entry.isIntersecting;
}
const loadImage = async (entry) =>{
const nodo_container = entry.target;
console.log("holis");
const url = await ramdomUrlImagen();
nodo_container.firstChild.src = url;
observer.unobserve(nodo_container);
}
const observer = new IntersectionObserver((entries)=>{
entries.filter(isIntersecting).forEach(loadImage);
});
export const subscribeImageObserver = (image) =>{
observer.observe(image);
}
/* Promise.allSettled([createImageNode()]).then((images)=>{
images.forEach((img) =>{
if(img.status === "fulfilled"){
mountNode.appendChild(img.value);
}
});
});
*/
Me perdi @-@
Aqui hay otra forma de agregarlo :
const addImg = () => {
const foxImg = document.createElement("img");
foxImg.className = "img";
foxImg.src = `https://randomfox.ca/images/${random()}.jpg`;
foxImg.loading = "lazy"; // Agregar el atributo loading con el valor "lazy"
node.appendChild(foxImg);
registerImg(foxImg);
};
otro uso practico ademas de cargar imagenes que ya tienen implementado el “lazy”, podria ser cuando consultas infinidad de registros y ha medidda que haces scroll quieres ir lo cargando poco a poco.
wow, tantas horas invertidas haciendo cursos de JS, para que cuando llegues a estas cosas veas lo sencillo que son.
Genial
Adicionalmente, podemos alterar las opciones que se encuentren en el objeto que recibe la API de IntersectionObserver para parametrizar cuando queremos que se ejecute la callback de isLoading, asi:
.
.
.
const options = {
// root, → refers to HTML element to listen to, and when is going to be listening, by default will take the whole viewport
// rootMargin, → margin for the triggering of observer, works like a CSS margin
threshold: 0.5, //at which "size" of the element the callback will be triggerd
}
.
.
.
En este caso quise que se ejecute la callback al 50% del tamaño de la imagen (0.5)
agregue esta linea para que se elimine el atributo data-src
una vez ya aparezca la imagen, pues ese atributo ya no sirve.
image.removeAttribute('data-src')
myElement.dataset.my_set
Gracias a esto podemos guardar información en los atributos de un elemento HTML, para luego procesarla accediendo a ella por medio de la API del DOM
Esta clase es brutal, creo que esto debería aplicarse a cualquier proyecto que vayas a construir.
dataset
se utiliza mucho para comunicar información entre HTML y JS
//4 Intersection Observe
//Aplicar el Lazy loading imgs
const isIntersecting = (entry) => {
//200px lejos de la pantalla entonces haz algo EG
return entry.isIntersecting //True(dentro de la pantalla)
};
const loadImage = (entry) => {
const container = entry.target; //Es el contenedor.
const imagen = container.firstChild;
const url = imagen.dataset.src;
//Cargar imagen
imagen.src = url;
// console.log(nodo.nodeName);
//Forma profesional de hacer el debugger, no por console.log
//Si ya hiciste algo, desregistra la imagen (unlisten)
observer.unobserve(container);
};
const observer = new IntersectionObserver((entries) => {
entries
.filter(isIntersecting) //Si está presente en el viewport
.forEach(loadImage)
});
//entries tambien puede ser allElements
export const registerImage = (imagen) => {
//IntersectionObservador -> Observar(imagen)
observer.observe(imagen);
};
My code lazy.js
const isIntersecting=(entry)=>{
return entry.isIntersecting; // true (dentro de la pantalla)
};
const loadImage=(entry)=>{
const container=entry.target; //container DIV
const image=container.firstChild;
image.src=image.dataset.src;
//desregister la imagen (unlisten)
observer.unobserve(container);
};
const observer= new IntersectionObserver((entries)=>{
entries.filter(isIntersecting).forEach(loadImage);
});
export const registerImage=(image)=>{
observer.observe(image);
};
Mi función loadImagen
const actionLoadImage = (entry) => {
const nodo = entry.target;
entry.target.childNodes.forEach( element => {
element.src = element.dataset.src;
});
console.log('Te estoy viendo');
// dejar de escuchar los elementos
observer.unobserve(nodo);
}```
dataset se utiliza mucho para comunicar información entre HTML y JS (en el browser aparece como data-src).
const isIntersecting = (entry) => {
return entry.isIntersecting
}
const loadImage = (entry) => {
const container = entry.target
const image = container.firstChild
const url = image.dataset.src
image.src = url
console.log(image)
observer.unobserve(container)
}
const observer = new IntersectionObserver((entries) => {
entries.filter(isIntersecting).forEach(loadImage)
})
export const registerImage = (image) => {
observer.observe(image);
}```
Increible la calidad de este curso, uno de los mejores
Mi código 😄
function cb(entries) {
entries.forEach((entry) => {
//si la imagen se encuentra en el rango de observación que seria del 50%
if (entry.isIntersecting) {
console.log('holis');
const $container = entry.target;
const image = $container.firstChild;
const url = image.dataset.src;
//cargar imagen
image.setAttribute('src', url);
observer.unobserve($container);
}
});
}
// const observer = new IntersectionObserver(recibe un callback, configuraciones);
//threshold --> cuando detecta un porcentaje de la imagen va de 0 a 1
//por lo tanto cuando sea visible el 50% de la imagen recien cargara la imagen
//en este caso seria mejor poner 0
const observer = new IntersectionObserver(cb, { threshold: 0.5 });
export function registrarImage(image) {
//escuhar cada imagen
observer.observe(image);
}
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?