This page contains a string of placeholder images and references two sources: a CSS file and a JavaScript file.
To display the placeholder image in a grid, add the following CSS to the style.css file :
* { margin: 0; padding: 0; box-sizing: border-box; } html { font-size: 62.5%; } body { font-family: Cambria, Times, "Times New Roman", serif; } h1 { text-align: center; font-size: 5rem; padding: 2rem; } img { width: 100%; display: block; } .products__list { display: flex; flex-wrap: wrap; gap: 2rem; justify-content: center; } .products__list > * { width: calc(33% - 2rem); } .loading-indicator { display: none; position: absolute; bottom: 30px; left: 50%; background: #333; padding: 1rem 2rem; color: #fff; border-radius: 10px; transform: translateX(-50%); }
Currently, your page will look like this:
Edit script.js. To implement infinite scroll, you need to detect when the user has scrolled near the bottom of the container or content page.
"use strict"; window.addEventListener("scroll", () => { if ( window.scrollY + window.innerHeight >= document.documentElement.scrollHeight - 100 ) { // Người dùng ở gần dưới cùng, tìm nạp nhiều nội dung hơn fetchMoreContent(); } });
Then create a function to fetch more placeholder data.
async function fetchMoreContent() { try { let response = await fetch("https://fakestoreapi.com/products?limit=3"); if (!response.ok) { throw new Error("Network response was not ok"); } let data = await response.json(); console.log(data); } catch (error) { console.error("There was a problem fetching new content:", error); } finally { console.log("Fetch function fired"); } }
For this project, you can use the API from fakestoreapi .
To confirm data is fetched on scroll, look at the console:
You will see the data fetched multiple times as you scroll. It may be a factor affecting the performance of the device. To avoid this, create an initial data fetch state:
let isFetching = false;
Then, edit the fetch function to only find data after a previously completed process.
async function fetchMoreContent() { if (isFetching) return; // Thoát nếu tìm nạp dữ liệu đã xong isFetching = true; // Đặt flag sang true try { let response = await fetch("https://fakestoreapi.com/products?limit=3"); if (!response.ok) { throw new Error("Network response was not ok"); } let data = await response.json(); } catch (error) { console.error("There was a problem fetching new content:", error); } finally { console.log("Fetch function fired"); isFetching = false; // Reset flag sang false } }
To show new content when the user scrolls down the page, create a function that appends the images to the main container.
First, choose the main component:
const productsList = document.querySelector(".products__list");
Then create a function that appends content:
function displayNewContent(data) { data.forEach((item) => { const imgElement = document.createElement("img"); imgElement.src = item.image; imgElement.alt = item.title; productsList.appendChild(imgElement); // Append to productsList container }); }
Finally, edit the fetch function and pass the fetched data to the append function.
async function fetchMoreContent() { if (isFetching) return; isFetching = true; try { let response = await fetch("https://fakestoreapi.com/products?limit=3"); if (!response.ok) { throw new Error("Network response was not ok"); } let data = await response.json(); displayNewContent(data); } catch (error) { console.error("There was a problem fetching new content:", error); } finally { console.log("Fetch function fired"); isFetching = false; } }
That's it, infinite scrolling will now work.
To enhance user experience, you can display a loading indicator when fetching new content. Start by adding this HTML.
Then select the loading component.
const loadingIndicator = document.querySelector(".loading-indicator");
Finally, create two functions that enable/disable loading indicator visibility.
function showLoadingIndicator() { loadingIndicator.style.display = "block"; console.log("Loading."); } function hideLoadingIndicator() { loadingIndicator.style.display = "none"; console.log("Finished loading."); }
Then add them to the fetch function.
async function fetchMoreContent() { if (isFetching) return; // Exit if already fetching isFetching = true; showLoadingIndicator(); // Show loader try { let response = await fetch("https://fakestoreapi.com/products?limit=3"); if (!response.ok) { throw new Error("Network response was not ok"); } let data = await response.json(); displayNewContent(data); } catch (error) { console.error("There was a problem fetching new content:", error); } finally { console.log("Fetch function fired"); hideLoadingIndicator(); // Hide loader isFetching = false; } }
Result:
If there isn't much content left to load, notify the user instead of constantly trying to fetch more data.