Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Comparte el resultado

24/28
Recursos

Aportes 56

Preguntas 7

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Vale, para agregar el fondo gris lo que hice fue crear un wrapper que encerrara a la imagen y que se adaptara al tamaño de la misma con un mínimo de 100px, y este wrapper tiene el fondo gris, así cuando se inserta sale con fondo gris:

...

imagen.width = "320";
imagen.dataset.src = `https://randomfox.ca/images/${random()}.jpg`

const imageWrapper = document.createElement("div");
imageWrapper.className = "bg-gray-300";
imageWrapper.style.minHeight = "100px";
imageWrapper.style.display = "inline-block";

imageWrapper.appendChild(imagen);
container.appendChild(imageWrapper);
...

Para eliminar las imagenes, le puse id a los botones:

<button class="p-3" id="add">Agregar Imagen</button>
<button class="p-3" id="clean">Limpiar</button>

En JavaScript los selecciono y les pongo sus eventos, para eliminarlos simplemente recorro todos los nodos hijos de mountNode, los recorro y los elimino:

const cleanImages = () => {

    console.log(mountNode.childNodes);

    [...mountNode.childNodes].forEach(child => {
        child.remove();
    }) 

}

addButton.addEventListener("click", addImage)
cleanButton.addEventListener("click", cleanImages)

Y para imprimir los logs, en el HTML agregue variables y una función super globales para tener acceso desde index.js y desde lazy.js:

<script>
    let appendedImages = 0;
    let loadedImages = 0;

    const printLog = () => {
    console.log(`⚪ Se han agregado ${appendedImages} imágenes`);
    console.log(`🟣 Se han cargado ${loadedImages} imágenes`);
    console.log("---------------------------------------");
    }
</script>
<script type="module" src="%PUBLIC_URL%/_dist_/index.js"></script>

Entonces, en la función createImageNode antes de retornar el container, aumento uno a las imagenes que se han agregado y llamo a la función:

...
imageWrapper.appendChild(imagen);
container.appendChild(imageWrapper);

appendedImages++;
printLog();

return container;
...

Y dentro de lazy.js en loadImage antes de dejar de observar hago lo mismo, pero aquí incremento las imágenes cargadas:

const loadImage = entry => {

    const container = entry.target;
    const imagen = container.firstChild;
    const imagen = container.querySelector("img");
    const url = imagen.dataset.src;
    imagen.src = url;

    loadedImages++;
    printLog();

    observer.unobserve(container)

}

Y listo 😄
.
El código completo está aquí por si quieren darle un vistazo:
.
Resolución del reto

espero lograr un efecto parecido para mi lista de pokemons.
https://codepen.io/rogergcc/full/NeEYeN
queria lograr un loading a cada pokemon porque el texto carga rapido pero la imagen demora en cargar mas.
Vi que lo hacen con imagenes estaticas pero quiero lograrlo en un api json.

Les comparto mi proyecto 😁 El curso ha estado genial!!! sitio: https://findafox.netlify.app/
repo: https://github.com/jmilo13/findFox/

Como adicional al primer reto, seria esencial agregar un icono de cargando al recuadro gris, esto le dará una mejor percepción al usuario de lo que esta sucediendo con la imagen. En la siguiente url podrán encontrar un ejemplo de cómo crear este icono con solo html y css https://devcode.la/tutoriales/crear-un-preloader-con-css3/


Les dejo el enlace: Lazy loading

Si se pudo!! En mi caso, usé webpack como builder 😄 Si le quieren dar un ojo se los dejo aquí

Index.js

lazy

El uso de clases para el pintado de los estatus de las imágenes me ha funcionado, aquí les comparto:

  • Creamos la clase, la inicializamos y la exportamos (lazy.js).

  • La clase cuenta con métodos públicos y privados para su encapsulamiento y los métodos “getAppended o getLoaded” pueden o no ser públicos dependiendo de la necesidad.

  • El método “clear” en mi caso aplique una limpieza en consola.

class ImageLoaded {
    #appendImages = 0;
    #loadedImages = 0;

    #getAppended(){
        return this.#appendImages;
    }

    #getLoaded(){
        return this.#loadedImages;
    }

    addAppend(){
        this.#appendImages += 1;
    }
    addLoad(){
        this.#loadedImages += 1;
    }

    clear(){
        console.clear();
        this.#appendImages = 0;
        this.#loadedImages = 0;
    }

    printLog() {
        console.log(`
        ⚪ Se han agregado ${this.#getAppended()} imágenes
        🟣 Se han cargado ${this.#getLoaded()} imágenes
        ---------------------------------------`);
    }
}

export const imageStatus = new ImageLoaded();

  • Su implementación en el archivo lazy.js, seria la siguiente:
//imageStatus
const accion = ({ target }) => {
    const imagen = (target.firstChild).firstChild;
    imagen.src = imagen.dataset.src;
    imageStatus.addLoad();
    imageStatus.printLog();
    observer.unobserve(target)
}
  • Su implementación en el archivo index.js (requiere importar):
import { registerImage, imageStatus } from './lazy';

//...

const addButton = document.querySelector('.btn-add');
const cleanButton = document.querySelector('.btn-clean');

const addImage = () => {
    const newImage = createImageNode();
    container.appendChild(newImage)
    registerImage(newImage)
    imageStatus.addAppend();
    imageStatus.printLog()
};
const cleanImage = () =>{
    const allImages = [...container.querySelectorAll('div')];
    allImages.forEach(img => img.remove())
    imageStatus.clear();
}

addButton.addEventListener('click', addImage);
cleanButton.addEventListener('click', cleanImage);

Fondo gris a las imágenes sólo se lo agregué con una clase de tailwind:

img.className = "mx-auto my-16 bg-gray-200";

Para el botón de borrar lo agregué desde js:

const cleanImages = () => {
	const gallery = document.getElementById("gallery");
	const nodes = gallery.childNodes;
	if (!nodes.length > 0) return;

	[...nodes].forEach((node) => {
		gallery.removeChild(node);
	});

	resetImages();
};

const clean = document.createElement("button");
clean.className =
	"mx-auto my-4 block bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300 ease-in-out";
clean.textContent = "Borrar imágenes";
clean.type = "reset";
clean.addEventListener("click", cleanImages);
const gallery = document.createElement("div");
gallery.id = "gallery";
container.append(button, clean, gallery);

Y para el conteo de imágenes:

let totalImages = 0;
let loadedImages = 0;

const isIntersecting = (entry) => entry.isIntersecting;

const observer = new IntersectionObserver((entries) => {
	entries.filter(isIntersecting).forEach((entry) => {
		const imgNode = entry.target;
		imgNode.src = imgNode.dataset.src;
		imgNode.onload = () => {
			loadedImages++;
			logState();
		}
		observer.unobserve(entry.target);
	});
});

export const registerImage = (image) => {
	observer.observe(image);
	totalImages++;
	logState();
};

export const resetImages = () => {
	totalImages = 0;
	loadedImages = 0;
	logState();
};

function logState() {
	console.group("Lazy loading");
  console.log(`⚪️ Total Imágenes: ${totalImages}`);
  console.log(`🟣 Imágenes cargadas: ${loadedImages}`);
	console.log(`🟡 Imágenes por cargar: ${totalImages - loadedImages}`);
	console.groupEnd();
}

html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      name="description"
      content="Web site created using create-snowpack-app"
    />
    <!--
      Snowpack will replace %PUBLIC_URL% with the value you have for `baseUrl` in `snowpack.config.js`.
      Make sure to update it with your GitHub Page URL. https://<your-username>.github.io/<your-repo-name>

      More about config options:
      - https://www.snowpack.dev/reference/configuration#buildoptions.baseurl
    -->
    <link
      rel="stylesheet"
      type="text/css"
      href="%PUBLIC_URL%/_dist_/index.css"
    />
    <title>Random fox</title>
  </head>
  <body>
    <!--
      This HTML file is a template.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.

      Start modyfing from here.
    -->
    <div class="py-10 max-w-screen-xl mx-auto px-4 sm:px-6 lg:px-8">
      <div class="text-center">
        <p
          class="text-base leading-6 text-indigo-600 font-semibold tracking-wide uppercase"
        >
          Manipulando el Dom
        </p>
        <h3
          class="mt-2 text-3xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl sm:leading-10"
        >
          Random Fox
        </h3>
        <p class="m-4 max-w-2xl text-xl leading-7 text-gray-500 mx-auto">
          Manipulacion del DOM con API de <span> <a href="https://randomfox.ca/" target="_blank">RandomFox</a></span>
        </p>

        <button id="addButton" class="p-3">Agregar Imagen</button>
        <button id="removeButton" class="p-3">Remover Imagenes</button>
       
        <div id="images">
          
        </div>

        

      </div>
    </div>

    <!-- Add more scripts here -->
    <script type="module" src="%PUBLIC_URL%/_dist_/index.js"></script>
  </body>
</html>

index.js

/**
 * This file is just a silly example to show everything working in the browser.
 * When you're ready to start on your site, clear the file. Happy hacking!
 **/

import { registerImage } from "./lazy";

const URL = "https://randomfox.ca/images";

const maximum=122;
const minimum= 1;

//crea un numero aleatorio para traer las imagenes
const random = () => Math.floor(Math.random() * (maximum - minimum)) + minimum

// reporte en consola de cuantos argumentos han traido y estan cargados
const reportImgs = {
    imgLoaded: 0,
    totalImg: 0
}

const stopContentLoader = (event) => {
    const img = event.target;
    // img.parentElement.lastChild.remove();
    img.style.width = '320px';
    img.style.height= '320px';
    
    reportImgs.imgLoaded++;
    
    // debugger;
    showReportImg();
}

const showReportImg = () => {
    console.log('----------------------------------------')
    console.log(`%c⚪Total Imgs: ${reportImgs.totalImg}`, 'color: white; font-size: 0.8rem');
    console.log(`%c🟣Total Cargadas: ${reportImgs.imgLoaded}`, 'color: hotpink; font-size: 0.8rem');
    console.log('----------------------------------------')
}

const allElementsDeleted = () => {
    console.log(`⚠ Todas las imagenes fueron eliminadas`);
}

const createImageNode = () => {
    const container = document.createElement('div');
    container.className = 'flex flex-col items-center p-4 mx-auto';

    const img = document.createElement('img');
    img.className = 'mx-auto rounded bg-gray-300';
    img.width = "320";
    img.style.minHeight = '300'
    img.dataset.src = `${URL}/${random()}.jpg`; // TODO

    img.onload = stopContentLoader; //onload llama una funcion

    container.appendChild(img);

    return container;
};

const nuevaImagen = createImageNode();

const addImage = () => {
    const newImage = createImageNode();
    mountNode.append(newImage);
    registerImage(newImage);
    
    reportImgs.totalImg++;
    showReportImg();
}

const removeAllImg = () =>{
    mountNode.innerHTML = "";
    reportImgs.imgLoaded = 0;
    reportImgs.totalImg = 0;
    allElementsDeleted()
}


//captura la etiqueta img del html
const mountNode = document.getElementById('images')

//captura el button del html
const addButton = document.querySelector('#addButton');
addButton.className = 'text-white px-3 py-2 rounded-lg bg-indigo-600 focus:outline-none';

const removeButton = document.querySelector('#removeButton')
removeButton.className ='rounded-lg mt-5 px-3 py-2 text-indigo-600 border border-indigo-600 focus:outline-none';

addButton.addEventListener('click', addImage);
removeButton.addEventListener('click', removeAllImg);


lazy.js

const isIntersecting = (entry) => entry.isIntersecting; //true (dentro de la pantalla)

const loadImage = (entry) => {
    const container = entry.target; //regresa un container (DIV)
    const imagen = container.firstChild;
    const url = imagen.dataset.src
    //cargar la imagen.
    imagen.src=url

    // console.log(entry);

    //desregistrar el evento
    observer.unobserve(container);
};

const observer = new IntersectionObserver((entries)=>{
    entries.filter(isIntersecting).forEach(loadImage);
});

export const registerImage = (imagen) => {
    //intersectationObservador -> observer(imagen)
    observer.observe(imagen)
}

Bien, esto fue lo que yo hice 😄
index.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      name="description"
      content="Web site created using create-snowpack-app"
    />
    <!--
      Snowpack will replace %PUBLIC_URL% with the value you have for `baseUrl` in `snowpack.config.js`.
      Make sure to update it with your GitHub Page URL. https://<your-username>.github.io/<your-repo-name>

      More about config options:
      - https://www.snowpack.dev/reference/configuration#buildoptions.baseurl
    -->
    <link
      rel="stylesheet"
      type="text/css"
      href="%PUBLIC_URL%/_dist_/index.css"
    />
    <title>Snowpack & Tailwind App</title>
  </head>
  <body>
    <!--
      This HTML file is a template.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.

      Start modyfing from here.
    -->
    <div class="py-10 max-w-screen-xl mx-auto px-4 sm:px-6 lg:px-8">
      <div class="text-center">
        <p
          class="text-base leading-6 text-indigo-600 font-semibold tracking-wide uppercase"
        >
          Platzi
        </p>
        <h3
          class="mt-2 text-3xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl sm:leading-10"
        >
          Fox API
        </h3>
        <p class="mt-4 max-w-2xl text-xl leading-7 text-gray-500 mx-auto">
          Coleccionando imágenes de Zorros
        </p>

        <button class="button" id="buttonFox">Click me to see a new fox!</button>
        <button id="deleteFoxes" class="buttonClear">Clean images</button>
        <div id="app"></div>

      </div>
    </div>

    <!-- Add more scripts here -->
    <script type="module" src="%PUBLIC_URL%/_dist_/index.js"></script>
  </body>
</html>

index.css :

@import 'tailwindcss/dist/base.css';
@import 'tailwindcss/dist/components.css';
@import 'tailwindcss/dist/utilities.css';

.button,
.buttonClear{
  color: white;
  padding: 5px;
  border-radius: 5px;
}

.button{
  background-color: orange;
}

.buttonClear{
  background-color: rgb(255, 81, 0);
}

index.js :

import {registerImage} from './lazy';

const maximum = 122;
const minimum = 0;
const random = () => Math.floor(Math.random() * (maximum - minimum) + minimum);

const createImageNode = () => {
  const container = document.createElement('div');
  container.className = "p-4 bg-gray-200 mt-5";

  const image = document.createElement('img');
  image.className = 'mx-auto';
  image.width = '320';
  image.dataset.src = `https://randomfox.ca/images/${random()}.jpg`;
  container.append(image);

  return container;
}

const mountNode = document.getElementById('app');
const buttonFox = document.getElementById('buttonFox');
const buttonClear = document.getElementById('deleteFoxes');

var imagenesCargadas = 0;

const addImage = () => {
  const newImage = createImageNode();
  mountNode.append(newImage);
  registerImage(newImage);
  imagenesCargadas += 1
  console.log(`Se han cargado ${imagenesCargadas} fotos`)
}

buttonFox.addEventListener('click' , addImage);

buttonClear.addEventListener('click' , () => {
  let containerWithImage = document.querySelectorAll('#app .p-4'); //!Obtiene nodeList
  containerWithImage = Array.from(containerWithImage); //!Convierte a Array
  containerWithImage.forEach(element => {
    element.remove();
  });
})

//*Las líneas de abajo ya muestran 1 imagen por defecto
//const nuevaImagen = createImageNode();
//mountNode.append(nuevaImagen);

lazy.js :

const isIntersecting = entry => {
  return entry.isIntersecting //* true si está dentro de la pantalla del navegador
}

var imagenesMostradas = 0;

const loadImage = (entry) => {
  const container = entry.target; //* div
  const image  = container.firstChild;
  const url = image.dataset.src;
  //*carga imagen
  image.src = url;
  observer.unobserve(container);
  imagenesMostradas += 1;
  console.log(`Se han mostrado ${imagenesMostradas} fotos a la vista del navegador`)
}

const observer = new IntersectionObserver((allEntries) => {
  allEntries
    .filter(isIntersecting)
    .forEach(loadImage)
})

export const registerImage = image => {
  observer.observe(image)
}

Aquí les dejo mi taller: https://christbm.github.io/workshop2/

Ahí va mi Lazy Loading. Tuve que ver el repositorio del profesor para el tema de la imagen gris, pero entendí el funcionamiento.

https://marinrmarco.github.io/lazyloading/

Mi solución, para eliminar las imagenes hice lo siguiente:

const cleanImages = () => {
    
    const nodeElementsImages = mountNode.children
    const listaElements = [...nodeElementsImages]
    listaElements.forEach((element) => element.remove())
    
}

//Agregamos el evento
cleanButton.addEventListener('click', cleanImages)

Para agregar el fondo gris :

const imagen = h('img.mx-auto', {
        width: 320,
        height : 300,
        style: {
            background:'grey'
        },
        "data-src" : `https://randomfox.ca/images/${random()}.jpg`,
        
    })

Les comparto mi solución al Reto 🎉 Aquí el repo y aquí el resultado 😁

Asi pueden eliminar todos los elementos 😄

// removeImageButton
const removeButton = document.getElementById('btn-clean');

const clearImage = () => {
    mountNode.replaceChildren();
};

removeButton.addEventListener("click", clearImage);

Encontré este código para eliminar todos los child nodes, me pareció sencillo y eficaz. 😁
https://www.javascripttutorial.net/dom/manipulating/remove-all-child-nodes/

const deleteImgs = () => {
  console.log(mountNode.childNodes);
  while(mountNode.firstChild) {
    mountNode.removeChild(mountNode.firstChild);
  }
}

Adoro estas clases prácticas que te dejan algo en Github.
https://nosoyeseoscar.github.io/workshop-2-lazy/

Mi implementación

Genial este curso 😃 se aprende mucho

Mi resultado 😄 todo ha sido genial mil gracias
Repositorio
Sitio

Monté mi proyecto en CodePen:

https://codepen.io/Londrack/full/jOaqwvJ

Este fue mi resultado:

Página
Repositorio

Este es mi resultado:
He agregado contadores y textos random cuando genero una nueva targetita de zorro ( ̄︶ ̄*))

Página aquí 👈
Repo aqui 👈


Les dejo el link del repositorio.
En este enlace pueden ver la página.

Esta es mi githubpage:
https://jsegundo.github.io/JS-intersection-observer/
Y este es el repo, todo el JS tiene comentarios que explican detalladamente(a mi parecer) todas las funciones, espero que a alguien le sirva.
https://github.com/JSegundo/JS-intersection-observer

Vamos por ese reto

Acepto toda critica. REPOSITORIO

También dejo por aquí SITIO EN VIVO

Mas los screenshots :

Este es mi proyecto, me ayude bastante de @retaxmaster, Fox Lazy Loading, repo en GitHub

Para los que miraron el repo del profe buscando como hacer lo del recuadro gris y se encontraron una ruta bastante extraña como: data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIwIiBoZWlnaHQ9IjMyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=, les dejo un recurso que explica en que consiste esto, espero le sirva a alguien 😊:
recurso

No es mucho, pero es trabajo honesto 😄
https://lazy-lodn.netlify.app/
Código del proyecto

😄 aqui mi genrador de imagenes de los zorros.

https://brayangc1.github.io/kuramaGenerator/

MAIN.JS

import { lazyLoading, imgCargadas } from "./lazyLoad.js";

const section = document.getElementById('seccion');
const boton = document.querySelector('#agregar');
const removeButton = document.getElementById('quitar');
const max = 122;
const min = 1;
export let imgCreadas = 0;

export const consoleImages = (creadas,cargadas) => {
    console.log(`🦊 Total imagenes: ${creadas}`)
    console.log(`👀 Imagenes cargadas: ${cargadas}`)
}

const random = () => Math.floor(Math.random() * (max - min)) + min;

const crearImagen = () =>{
    const figure = document.createElement('figure');
    const imagen = document.createElement('img');
    // imagen.src = `https://randomfox.ca/images/${random()}.jpg`;
    imagen.dataset.src = `https://randomfox.ca/images/${random()}.jpg`;
    imgCreadas++;

    figure.appendChild(imagen);
    return figure;
}

const borrarFigure = () =>{
    const selectDelete = document.querySelectorAll('figure');
    
    const arrayDelete = [...selectDelete];
    return arrayDelete;
} 

const borrarImagen = () =>{
    const selectDelete = document.querySelectorAll('img');
    
    const arrayDelete = [...selectDelete];
    return arrayDelete;
} 

const agregarImagen = () => {
    const newImage = crearImagen();
    section.appendChild(newImage);
    lazyLoading(newImage);

    consoleImages(imgCreadas,imgCargadas);
}

const quitarImagen = () =>{
    const deleteImage = borrarImagen();
    const deleteFigure = borrarFigure();

    deleteImage.forEach(hijo=> hijo.remove());
    deleteFigure.forEach(hijo => hijo.remove());    
}

boton.addEventListener('click', agregarImagen);

removeButton.addEventListener('click', quitarImagen);


LAZYLOAD.JS

import { imgCreadas, consoleImages } from "./main.js";

const isIntersecting = entry => entry.isIntersecting;
export let imgCargadas = 0;

const tarea = (entry) =>{    
    const container = entry.target;
    const imagen = container.firstChild;
    const url = imagen.dataset.src;
    imagen.src= url;

    imgCargadas++;
    consoleImages(imgCreadas,imgCargadas);
    observer.unobserve(container);

    imagen.onload = () =>{
        container.parentElement.replaceChild(imagen,container);
        imagen.classList.add('margin');
    }
}

const observer = new IntersectionObserver((entries)=>{
    entries.filter(isIntersecting).forEach(tarea);
})

export const lazyLoading = (figure) =>{
    observer.observe(figure);
}

también el codigo se encuentra aqui: https://github.com/brayangc1/kuramaGenerator

Terminé el proyecto y utilicé un closure para resolver el tema del informe y aproveché para agregar una función que elimine los datos de la consola cuando se limpien los lobos del DOM.
En vivo aquí

function contarImg() {
    let imgAdd = 0
    let imgPaint = 0
    
    return {
        imgAgreg: function(){
            imgAdd++
            console.log(`⚪ Se han agregado ${imgAdd} imágenes`);
            console.log(`🟣 Se han cargado ${imgPaint} imágenes`);
            console.log("---------------------------------------");
        },
        imgLoad: function(){
            imgPaint++
            console.log(`⚪ Se han agregado ${imgAdd} imágenes`);
            console.log(`🟣 Se han cargado ${imgPaint} imágenes`);
            console.log("---------------------------------------");
        },
        imgDelete: function(){
            imgPaint = 0
            imgAdd = 0
            console.clear()
        }
    }
}

export const contar = contarImg()

Estoy disfrutando este curso demasiado. Eres uno de los mejores profesores en la plataforma.
Les dejo mi resultado con algunos ajustes como deshabilitar el botón de Limpiar cuando no hay imágenes en la lista. También, si las imagenes son eliminadas, el reporte vuelve a 0.

El despliegue lo hice en Netlify porque ahí manejo todos mis proyectos actualmente.

Para publicarlo ahí solo es necesario conectar la cuenta de github y en el deploy colocar “npm run build” y elegir la carpeta “build/” como la carpeta de donde se levantará la web una vez hecho el build.

https://youthful-jang-e738c2.netlify.app/

Con un poco de complicaciones pero pude terminarlo!. 😁
Muchas gracias a todos los compañeros que compartieron sus aportes y al profesor sin duda alguna 😊
Reto completado
Repo

Wenas [email protected];

Por aquí dejo mi solución del segundo proyecto. Wen domingo.

Entonces tenemos 3 retos:

  • Dar la percepción de carga con el recuadro gris.
  • Eliminar todo el contenido y limpiar la pantalla por medio de un botón
  • Por medio de la consola indicar cuantas han cargado y cuantas faltan por cargar

¡Vamo a darle! 😃

Les comparto mi resultado me demore un poco con este reto me toco apoyarme en comentarios de los compañeros y repo del profe pero gracias a Dios lo pude terminar les comparto el deploy Aqui y el repo

Días después se me ocurrió solucionar el tema del log de la cuenta con clousures, es un poco más organizada a mi parecer. Les comparto mi solución 😀

Ya luego solo importamos he invocamos como

count.imageRendered();
count.imageLoaded();

Hola, les dejo mi resultado.
repo: https://github.com/sebaser99/lazy
github pages: https://sebaser99.github.io/lazy/

Agradezco el feedback

Para el lazy-loader solo agregué estilos al div

// index.js
  ...
  div.style.width = "200px"
  div.style.minHeight = "100px"
  div.style.height = "auto"
  ...
};

Para eliminar toda la lista de imgs use un add event y un foreach

// index.js
const cleanImgButton = document.getElementById("cleanButton");

cleanImgButton.addEventListener("click", () => {
  [...imgContainer.childNodes].forEach((item) =>
    imgContainer.removeChild(item)
  );
});

Para el console fueee un poquito mas complicado para mi

//index.js
import { registerImage, changesRegister } from "./lazy";
changesRegister(imgContainer);
  • Use el Mutation Observer para leer las mutaciones en el container, y una sola funcion que leyera la data y la muestre en consola
//lazy.js
/** Esto es lo que hara el mutation observer */
const mutationObserver = new MutationObserver(() => updateConsole());

/** Convierte el objeto obtenido en un mutation observer  */
export const changesRegister = (container) => {
  mutationObserver.observe(container, {
    attributes: false,
    childList: true,
    subtree: false,
  });
};

/** Funcion que lee el numero de imagenes y el numero de imagenes sin src, y luego lo imprime */
const updateConsole = () => {
  const creadas = imgContainer.childElementCount;
  const cargadas = [...imgContainer.children].filter((item) =>
    item.children[0].hasAttribute("src")
  ).length;
  console.log(`------------------------------`);
  console.log(`🦊 Total imagenes: ${creadas}`);
  console.log(`👀 Imagenes cargadas: ${cargadas}`);
};

agrego el updateConsole tambien en cada vez que sea cargada la imagen en el intersectionObserver

// lazy.js
const loadImage = (entry) => {
  ...
  updateConsole();
  ...
}

MI solución.

// lazy.js
import { registerImage } from "./lazy";
// random images
const min=1, max=122;
const random=()=> Math.floor(Math.random()*(max-min))+min;
// images HTML -> JS
const createImageNode=()=>{
    const container = document.createElement('div');
    container.className='p-4';
    const image= document.createElement('img');
    image.className='mx-auto rounded-md bg-gray-300';
    image.width='320';
        image.dataset.src=`https://randomfox.ca/images/${random()}.jpg`
    container.appendChild(image);
    return container;
};

const mountnode=document.getElementById('images');
//eventListerner DOM -> addImages
const addButton=document.getElementById('btnaddimg');
const addImage=()=>{
    const newImage=createImageNode();
    mountnode.append(newImage);
    registerImage(newImage);
};
addButton.addEventListener('click',addImage);

//clean Images
const clean=document.getElementById('btnclnimg');
clean.addEventListener('click',()=>{
    mountnode.innerHTML="";
});
 
// lazy.js
let totalImage=0, loadedImage=0;

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;
    image.onload=()=>{
        loadedImage++;
        logstate();
    }
    //desregister la imagen (unlisten)
    observer.unobserve(container);
};

const observer= new IntersectionObserver((entries)=>{
    entries.filter(isIntersecting).forEach(loadImage);
});

export const registerImage=(image)=>{
    observer.observe(image);
    totalImage++;
    logstate();
};

function logstate(){
    console.log(`Total Images: ${totalImage}`);
    console.log(`Loaded Images: ${loadedImage}`);
} 

Aqui esta mi solucion,para el fondo gris lo unico que hago es darle un background color grey a la imagen y un min height asi

const createImageNode = () => {
  const container = document.createElement('div')
  container.className = 'p-4'

  const img = document.createElement('img')
  const imageUrl = `https://randomfox.ca/images/${randomNumber()}.jpg`
  img.dataset.src = imageUrl
  img.className = 'mx-auto bg-gray-300'
  img.style.minHeight = "300px"
  img.width = '320'
  container.appendChild(img)

  return container
}

Para borrar las imagenes lo unico que se tiene que hacer es un :

innerHTML = ''

cuando le das click a un boton al nodo de las imagenes, asi

const imagesNode = document.querySelector('#images')
const clearBtn = document.querySelector('#clearImages')

const clearImages = () =>{
  imagesNode.innerHTML = ""
}
clearBtn.addEventListener('click',clearImages)

y para hacer los logs, en el observer agrege un log cada que llamara al cb y obtengo todas las imagenes de la pagina y las loggeo como agregadas y loggeo las cargadas con un contador que avanza cada que se carga una imagen


const isIntersecting = (entry) => {
  return entry.isIntersecting
}
let loadedImagesCounter = 0
const action = (entry) => {
  const container = entry.target
  const img = container.firstChild
  const url = img.dataset.src
  img.src = url
  loadedImagesCounter++
  observer.unobserve(container)
}

const observer = new IntersectionObserver((entries) => {
  const unloadedImagesCounter = document.querySelectorAll('img').length
  entries.filter(isIntersecting).forEach(action)
  console.log(`⚪ Se han agregado ${unloadedImagesCounter} imágenes`);
  console.log(`🟣 Se han cargado ${loadedImagesCounter} imágenes`);
  console.log("---------------------------------------");
})

export const registerImage = (image) => {
  observer.observe(image)
}

Terminado 😄

Repo
Live Demo

Mi solucion para el tracker de imagenes cargadas:

Lo primero crear dos variables en el lazy.js, para ir incrementandolas en las funciones correspondientes:

let totalImages = 0
let totalImagesLoaded = 0

export const registerImage = (imagen) => {
    totalImages += 1;
    console.log(`Total imagenes : ${totalImages} \nTotal Imagenes Cargadas : ${totalImagesLoaded}`)
    //intersectactionObserver
    observer.observe(imagen);
}
const loadImage = (entry) =>{
    totalImagesLoaded += 1;
    console.log(`Total imagenes : ${totalImages} \nTotal Imagenes Cargadas : ${totalImagesLoaded}`)
    const container = entry.target
    const imagen = container.querySelector('img')
    const url = imagen.dataset.src;
    // imagen.backgroun = 'grey';
    imagen.src = url
    
    //desregistra la imagen
    observer.unobserve(container)
}

Realice el proyecto como un generador de covers de libros aleatorio empleando la API Open Library.
Emplee un archivo js adicional llamado contador para mantener el reporte de los cambios en las imágenes.
De esta forma el resultado final de mi solución es:

index.js

import {registrarImagen} from './lazy'

const URL = 'https://covers.openlibrary.org/b/id/'
const TAMANO_Y_FORMATO = '-L.jpg'

const MAXIMO = 10610627
const MINIMO = 1
const random = () => Math.floor(Math.random() * (MAXIMO - MINIMO)) + MINIMO

const convertirAStringLen8 = () => {
    let stringNumero = random().toString()
    switch (stringNumero.length) {
        case 1: return `0000000${stringNumero}`
        case 2: return `000000${stringNumero}`
        case 3: return `00000${stringNumero}`
        case 4: return `0000${stringNumero}`
        case 5: return `000${stringNumero}`
        case 6: return `00${stringNumero}`
        case 7: return `0${stringNumero}`
        case 8: return `${stringNumero}`
    }
}

const crearNodoImagen = () => {
    const imagen = document.createElement('img')
    imagen.className = 'mx-auto shadow-xl'
    imagen.dataset.src = `${URL}00${convertirAStringLen8()}${TAMANO_Y_FORMATO}`

    const contenedorImagen = document.createElement('div')
    contenedorImagen.className = 'flex align-items mx-auto w-80 h-96 p-4 border-4 border-blue-600 bg-blue-50 rounded-lg hover:border-blue-300'
    contenedorImagen.appendChild(imagen)

    imagenesAgregadas += 1
    logEstadoImagenes()

    return contenedorImagen
}

const nodoMontaje = document.getElementById('images')
nodoMontaje.className = 'flex flex-wrap'
const botonAgregar = document.getElementById('agregar')
const botonClear = document.getElementById('clear')

const agregarImagen = () => {
    const nuevaImagen = crearNodoImagen()
    nodoMontaje.append(nuevaImagen)
    registrarImagen(nuevaImagen)
}

const limpiarImagenes = () => {
    [...nodoMontaje.childNodes].forEach(childNode => {
        childNode.remove()
    })
    imagenesAgregadas = 0
    imagenesCargadas = 0
    logEstadoImagenes()
}

botonAgregar.addEventListener('click', agregarImagen)
botonClear.addEventListener('click', limpiarImagenes)

lazy.js

const estaIntersectando = entrada => {
    return entrada.isIntersecting
}

const cargarImagen = entrada => {
    const contenedorImagen = entrada.target
    const imagen = contenedorImagen.firstChild
    const URL = imagen.dataset.src
    imagen.src = URL
    imagenesCargadas += 1
    logEstadoImagenes()
    observador.unobserve(contenedorImagen)
}

const observador = new IntersectionObserver(entradas => {
    entradas.filter(estaIntersectando).forEach(cargarImagen)
})

export const registrarImagen = imagen => {
    observador.observe(imagen)
}

contador.js

let imagenesAgregadas = 0
let imagenesCargadas = 0

const logEstadoImagenes = () => {
    console.log(`Imagenes agregadas = ${imagenesAgregadas}`)
    console.log(`Imagenes cargadas = ${imagenesCargadas}`)
}

Hola:

Comparto mi proyecto con los puntos del reto:

https://robmvsk.github.io/workshop-2-lazy-loading/index.html

Saludos 😃

Hola todos!!

Esta muy bueno el curso!

Les comparto mi solucion en codepen.
Cualquier feedback es bienvenido.

codepen

Para el reporte en mi index tengo esta funcion que exporto:

export function imprimirReporte (total, loaded) {
    console.log(`👍Total de imagenes: ${total}`);
    console.log(`✅Imágenes cargadas: ${loaded}`);
}```

y al registrar la imagen aumento totalImages++ y antes de termina de desobservar el container aumento loadedImages++

El curso ha resultado genial, cada día aprendo mas en Platzi.

Mi solución
Index.js

import { getLoadedImg, registerImage } from "./lazy"

let totalImg = 0

const mini = 1
const maxi = 122
const randomImg = () => Math.floor(Math.random() * (maxi - mini)) + mini

export const report = () => {
    console.log(`👍Total images: ${totalImg}`);
    console.log(`✅Images loaded: ${getLoadedImg()}`);
}

const createImg = () => {
    const container = document.createElement('div');
    container.className = "p-4"
    const img = document.createElement('img');
    img.className = "mx-auto grayBackground"
    img.width = "320"
    img.dataset.src = `https://randomfox.ca/images/${randomImg()}.jpg`
    container.appendChild(img)
    return container
}

const main = document.getElementById("images")
const addBtn = document.getElementById('add')
const delBtn = document.getElementById('del')

const addImage = () => {
    const newImg = createImg()
    main.append(newImg)
    registerImage(newImg)
    totalImg++;
    report()
}

const delImage = () => {
    let count = main.childElementCount;
    for (let i = 0; i < count; i++) {
        main.lastChild.remove()
    }
}

addBtn.addEventListener("click", addImage)
delBtn.addEventListener("click", delImage)

lazy.js

import { report } from "./index"

let loadedImg = 0;

const isIntersecting = (entry) => {
    return entry.isIntersecting
}

const loadImg = (entry) => {
    const container = entry.target
    const img = container.firstChild
    const url = img.dataset.src
    img.src = url
    img.onload = () => {
        img.classList.remove("grayBackground")
        loadedImg++;
        report()
    }
    observer.unobserve(container)
}

const observer = new IntersectionObserver((entries) => {
    entries
    .filter(isIntersecting)
    .forEach(loadImg)
});


export const registerImage = (image) => {
    observer.observe(image);
}

export const getLoadedImg = () => {
    return loadedImg;
}

Para los botones

<button id="add" class="p-3">Agregar Imagen</button>
<button id="del" class="p-3">Limpiar</button>

Me gustaría poder conocer su feedback, en especial en la función delImage
¯_(ツ)_/¯