├── favicon.png ├── index.html ├── loader.svg ├── script.js └── style.css /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacintoDesign/infinite-scroll/e35e627d1644a8361ddd848a947f98347cee8fd6/favicon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Infinite Scroll 7 | 8 | 9 | 10 | 11 | 12 |

Unsplash API - Infinite Scroll

13 | 14 |
15 | Loading 16 |
17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /loader.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const imageContainer = document.getElementById('image-container'); 2 | const loader = document.getElementById('loader'); 3 | 4 | let ready = false; 5 | let imagesLoaded = 0; 6 | let totalImages = 0; 7 | let photosArray = []; 8 | 9 | // Unsplash API 10 | const count = 30; 11 | // Normally, don't store API Keys like this, but an exception made here because it is free, and the data is publicly available! 12 | const apiKey = 'jFgS8tteGD425f4oZfygQVaVnD6gt6GucN2yyz3xFek'; 13 | const apiUrl = `https://api.unsplash.com/photos/random?client_id=${apiKey}&count=${count}`; 14 | 15 | // Check if all images were loaded 16 | function imageLoaded() { 17 | imagesLoaded++; 18 | if (imagesLoaded === totalImages) { 19 | ready = true; 20 | loader.hidden = true; 21 | } 22 | } 23 | 24 | // Helper Function to Set Attributes on DOM Elements 25 | function setAttributes(element, attributes) { 26 | for (const key in attributes) { 27 | element.setAttribute(key, attributes[key]); 28 | } 29 | } 30 | 31 | // Create Elements For Links & Photos, Add to DOM 32 | function displayPhotos() { 33 | imagesLoaded = 0; 34 | totalImages = photosArray.length; 35 | // Run function for each object in photosArray 36 | photosArray.forEach((photo) => { 37 | // Create to link to full photo 38 | const item = document.createElement('a'); 39 | setAttributes(item, { 40 | href: photo.links.html, 41 | target: '_blank', 42 | }); 43 | // Create for photo 44 | const img = document.createElement('img'); 45 | setAttributes(img, { 46 | src: photo.urls.regular, 47 | alt: photo.alt_description, 48 | title: photo.alt_description, 49 | }); 50 | // Event Listener, check when each is finished loading 51 | img.addEventListener('load', imageLoaded); 52 | // Put inside , then put both inside imageContainer Element 53 | item.appendChild(img); 54 | imageContainer.appendChild(item); 55 | }); 56 | } 57 | 58 | // Get photos from Unsplash API 59 | async function getPhotos() { 60 | try { 61 | const response = await fetch(apiUrl); 62 | photosArray = await response.json(); 63 | displayPhotos(); 64 | } catch (error) { 65 | // Catch Error Here 66 | } 67 | } 68 | 69 | // Check to see if scrolling near bottom of page, Load More Photos 70 | window.addEventListener('scroll', () => { 71 | if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 1000 && ready) { 72 | ready = false; 73 | getPhotos(); 74 | } 75 | }); 76 | 77 | // On Load 78 | getPhotos(); 79 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Bebas+Neue&display=swap"); 2 | 3 | html { 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | margin: 0; 9 | font-family: Bebas Neue, sans-serif; 10 | background: whitesmoke; 11 | } 12 | 13 | h1 { 14 | text-align: center; 15 | margin-top: 25px; 16 | margin-bottom: 15px; 17 | font-size: 40px; 18 | letter-spacing: 5px; 19 | } 20 | 21 | /* Loader */ 22 | .loader { 23 | position: fixed; 24 | top: 0; 25 | bottom: 0; 26 | left: 0; 27 | right: 0; 28 | background: rgba(255, 255, 255, 0.8); 29 | } 30 | 31 | .loader img { 32 | position: fixed; 33 | top: 50%; 34 | left: 50%; 35 | transform: translate(-50%, -50%); 36 | } 37 | 38 | /* Image Container */ 39 | .image-container { 40 | margin: 10px 30%; 41 | } 42 | 43 | .image-container img { 44 | width: 100%; 45 | margin-top: 5px; 46 | } 47 | 48 | /* Media Query: Large Smartphone Vertical */ 49 | @media screen and (max-width: 600px) { 50 | h1 { 51 | font-size: 20px; 52 | } 53 | 54 | .image-container { 55 | margin: 10px; 56 | } 57 | } 58 | --------------------------------------------------------------------------------