Last active
November 22, 2022 19:15
-
-
Save Alfa-Q/d7bbcf7d0727a90c6f0dae3bd05ec846 to your computer and use it in GitHub Desktop.
list.js - Infinite Scroll with Pagination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Infinite Scroll Example</title> | |
<!-- Styles --> | |
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> | |
<link rel="stylesheet" href="styles.css"> | |
<!-- Scripts --> | |
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> | |
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script> | |
<script src="script.js"></script> | |
</head> | |
<body> | |
<!-- Really Simple Example --> | |
<div id="top-section"> | |
<h4 class="display-4">Infinite Pagination Example!</h4> | |
<p> | |
In the following example, 5 items are initially loaded.<br/> | |
Each time you scroll down past towards the bottom, the next 5 items are retrieved. | |
</p> | |
<hr /> | |
<div id="info">Total Items: 0</div> | |
</div> | |
<div id="items-container" class="border" onscroll="scrollHandler()"> | |
<ul class="list"></ul> | |
<ul class="pagination" hidden></ul> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* =============================================================================== | |
// Setup with list.js | |
// =============================================================================*/ | |
let itemList; // Set when the page is loaded. | |
const itemsPerPage = 5; // Total number of items you want to render on each page | |
window.addEventListener("load", () => { | |
itemList = new List("items-container", { | |
pagination: true, // Required for pagination to work | |
page: itemsPerPage, // Items per page | |
valueNames: [ // Properties to extract from JSON object and be inserted into our item template below | |
"name", | |
"category", | |
"subcategory", | |
{ name: "thumbnail", attr: "src" }, | |
{ name: "link", attr: "href" }, | |
], | |
item: `<li> | |
<img class="mr-3 img-thumbnail thumbnail" src="" width="125px" height="125px" /> | |
<div class="media-body"> | |
<div class="name display-6 mt-2 mb-1"></div> | |
<div class="mt-auto"> | |
<div class="category badge badge-primary"></div> > | |
<div class="subcategory badge badge-secondary"></div> | |
</div> | |
<a class="link" href="" target="_blank">View Info</a> | |
</div> | |
</li>`, | |
}); | |
// Load items (see bottom of page to view the items) | |
itemList.add(items, () => { | |
$("#info").text(`Total Items: ${itemList.items.length}`); | |
}); | |
}); | |
/* =============================================================================== | |
// Infinite Pagination v(⌒o⌒)v | |
// =============================================================================*/ | |
let scrolling = false; // Current state (are we currently scrolling or not?) | |
let page = 1; // Starting page | |
const scrollThrottle = 250; // Interval between scroll checks. | |
// Event which is binded to the unordered list element's onscroll event. | |
// Simply updates the current state. | |
function scrollHandler() { | |
scrolling = true; | |
} | |
// Infinite Scroll with Pagination | |
setInterval(() => { | |
// Only bother checking if we can load next page items if the user is currently scrolling | |
if (scrolling) { | |
const container = $("#items-container"); | |
const containerPosY = container.height(); // Y position of the container top | |
const scrollPosY = container.scrollTop(); // Scroll position Y | |
const containerList = $("#items-container > .list"); // The actual list containing the items | |
const containerListY = containerList.height(); // Container list height size | |
const offsetY = 15; // Distance from bottom or top that is considered within range to | |
// items on the next page | |
// Can paginate, near the bottom of the list of items | |
if (scrollPosY + containerPosY > containerListY - offsetY) { | |
console.log("REACHED BOTTOM! Loading More Items!"); | |
page++; | |
itemList.show(0, page * itemsPerPage); | |
} | |
// Near the top of the list (not used for infinite scroll, but | |
// if you need to do something here, feel free to...) | |
else if (scrollPosY + containerPosY < containerPosY + offsetY) { | |
console.log("REACHED TOP!"); | |
// Do stuff | |
} | |
scrolling = false; | |
} | |
}, scrollThrottle); | |
/* =============================================================================== | |
// Random Data | |
// =============================================================================*/ | |
const items = [ | |
{ | |
name: "Iroha Isshiki", | |
category: "Anime", | |
subcategory: "Character", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Elden Ring", | |
category: "Video Games", | |
subcategory: "Miyazaki Plz", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Dark Souls", | |
category: "Video Games", | |
subcategory: "JRPG", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Bioshock", | |
category: "Video Games", | |
subcategory: "Shooter", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Kirby", | |
category: "Video Games", | |
subcategory: "Character", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "ICE +Caffeine", | |
category: "Drink", | |
subcategory: "Energy Drinks", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Demon Slayer", | |
category: "TV", | |
subcategory: "Anime", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Deadmau5", | |
category: "Music", | |
subcategory: "Music Artist", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Daft Punk", | |
category: "Music", | |
subcategory: "Music Artist", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "League of Legends", | |
category: "Games", | |
subcategory: "Cancer", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Mark Zuckerberg", | |
category: "Robots", | |
subcategory: "Evil", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Nhato", | |
category: "Music Artist", | |
subcategory: "EDM", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Python", | |
category: "Tech", | |
subcategory: "Programming Language", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Tik Tok", | |
category: "Spyware", | |
subcategory: "Cancer", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Portal 2", | |
category: "Video Games", | |
subcategory: "Puzzler", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Lack of a Better Name", | |
category: "Music", | |
subcategory: "Song", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
{ | |
name: "Lucid Dream", | |
category: "Music", | |
subcategory: "Song", | |
thumbnail: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", | |
link: "https://www.google.com", | |
}, | |
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
overflow-y: hidden; | |
} | |
#top-section { | |
margin-left: 8px; | |
} | |
#items-container { | |
overflow-y: scroll; | |
height: 400px; | |
} | |
#items-container > .list { | |
background: darkslategrey; | |
padding: 8px 8px; | |
} | |
#items-container .list li { | |
background: grey; | |
color: white; | |
margin-bottom: 8px; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I couldn't really find anything covering infinite scrolling using list.js other than a closed issue made 2 years ago, so I decided to make my own utilizing pagination! The best part is that you can still perform searches and can filter the data, it just requires resetting the
page
variable.I tested it on a list of over 6000 entries in a separate project that also contained images that were around 250px x 250px, an image size that is too small to be lazy loaded automatically by chrome but the sheer number of requests still made the browser very laggy and unresponsive. This infinite scrolling example solved almost all of my performance issues as it won't request 6000 images immediately. Instead it only loads the next
itemsPerPage
number of items on each scroll near the bottom of the container. As long as this value is a reasonable amount (i.e. 60) you shouldn't see much of a performance hit.The above code uses jquery, bootstrap, and list.js although it can certainly be done without jquery and bootstrap. Hopefully it helps anyone else out who is facing similar challenges!
Test It Live
jsfiddle
Feel free to add any suggestions, feedback, or comments. I'm relatively new to this gist stuff.