├── 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 |

16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/loader.svg:
--------------------------------------------------------------------------------
1 |
2 |
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 |
--------------------------------------------------------------------------------