اسکرول بی نهایت چیست؟
پیمایش بی نهایت قابلیتی است که برای بارگذاری پویا محتوای بیشتر در یک صفحه پس از پیمایش کاربر به انتهای صفحه استفاده می شود.
مفهوم اسکرول بی نهایت برای بارگیری داده ها از یک سرور به گونه ای استفاده می شود که برای کاربر احساس “یکپارچگی” داشته باشد اما با درخواست داده های بیش از حد در یک بار سرور را بارگذاری نمی کند.
در یک آموزش قبلی، ما یک ویژگی صفحهبندی را پیادهسازی کردیم که به ما امکان میداد محتوای خود را به بخشهای قابل پیمایش به نام صفحات تقسیم کنیم. این آموزش از پیاده سازی مشابهی استفاده خواهد کرد.
مزایای جاوا اسکریپت وانیلی
یک مزیت قابل توجه استفاده از جاوا اسکریپت این است که پیاده سازی ما چارچوب-آگنوستیک است، یعنی به هیچ چارچوبی وابسته نیست، بنابراین می توان آن را طوری اصلاح کرد که در همه آنها کار کند.
همچنین، از آنجایی که ما این ویژگی را خودمان میسازیم و به یک افزونه وابسته نیستیم، میتوانیم اطمینان حاصل کنیم که پیادهسازی آن سبک است و کاملاً با نیازهای ما سازگار است.
در اینجا نگاهی به محصول نهایی داریم، برای بارگیری محتوای بیشتر به پایین قلم بروید:
1. نشانه گذاری با HTML
ما با قرار دادن ظرف کارت های خود در صفحه شروع می کنیم. ما کارت ها را با استفاده از جاوا اسکریپت به ظرف اضافه می کنیم تا div خالی شود.
<div id="card-container"></div>
لودر هم داریم div
برای نمایش یک انیمیشن قبل از اضافه کردن دسته بعدی کارت ها و یک کارت-اکشن div
برای نمایش تعداد کارت و کل کارت.
<div id="loader"> <div class="skeleton-card"></div> <div class="skeleton-card"></div> <div class="skeleton-card"></div> </div> <div class="card-actions"> <span>Showing <span id="card-count"></span> of <span id="card-total"></span> cards </span> </div>



2. استایل دهی با CSS
کارتهایی که به قسمت کارت-کانتینر اضافه میکنیم، نام کلاسی «کارت» خواهند داشت.
#card-container { display: flex; flex-wrap: wrap; } .card { height: 55vh; width: calc((100% / 3) - 16px); margin: 8px; border-radius: 3px; transition: all 200ms ease-in-out; display: flex; align-items: center; justify-content: center; } .card:hover { box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); } .card-actions { margin: 8px; padding: 16px 0; display: flex; justify-content: space-between; align-items: center; }
ما همچنین با متحرک کردن ::after
شبه انتخابگر:
#loader { display: flex; } .skeleton-card { height: 55vh; width: calc((100% / 3) - 16px); margin: 8px; border-radius: 3px; transition: all 200ms ease-in-out; position: relative; background-color: #eaeaea; } .skeleton-card::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; left: 0; transform: translateX(-100%); background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, 0.2) 20%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0)); animation: load 1s infinite; } @keyframes load { 100% { transform: translateX(100%); } }
یک ظاهر طراحی در دسترس
هر زمان که یک انیمیشن را در یک صفحه وب قرار می دهیم، مهم است که مفاهیم دسترسی را در نظر بگیریم. برخی از کاربران ممکن است ترجیح دهند که اصلاً انیمیشن نداشته باشند و ما می توانیم با استفاده از قانون رسانه، این اولویت را در استایل خود در نظر بگیریم. prefers-reduced-motion
@media screen and (prefers-reduced-motion: reduce) { .skeleton-card::after { animation: none; } }
3. عملکرد با جاوا اسکریپت
بیایید منطق پشت اسکرول بی نهایت را بشکنیم.
- محدودیت محتوایی که باید در صفحه بارگذاری شود را مشخص کنید.
- تشخیص اینکه چه زمانی کاربر به انتهای محفظه محتوا رسیده است.
- پس از رسیدن به انتهای ظرف، محتوای بیشتری را بارگیری کنید.
- اگر محتوای دیگری برای بارگیری وجود ندارد، اسکرول بی نهایت را متوقف کنید.
تعریف ثابت ها
ابتدا، بیایید تمام عناصر مورد نیاز خود را از DOM خود دریافت کنیم:
const cardContainer = document.getElementById("card-container"); const cardCountElem = document.getElementById("card-count"); const cardTotalElem = document.getElementById("card-total"); const loader = document.getElementById("loader");
اکنون باید متغیرهای جهانی خود را تعریف کنیم.
ما به یک مقدار برای حداکثر تعداد کارتهایی که باید به صفحه اضافه شوند نیاز داریم. اگر داده های خود را از سرور دریافت می کنید، این مقدار طول پاسخ سرور است. بیایید یک محدودیت کارت 99 را مقداردهی اولیه کنیم.
const cardLimit = 99;
را cardTotalElem
عنصری برای نمایش حداکثر تعداد کارت در صفحه است تا بتوانیم آن را تنظیم کنیم innerHTML
به cardLimit
ارزش؛
cardTotalElem.innerHTML = cardLimit;
سپس یک متغیر برای تعداد کارت هایی که می خواهیم صفحه را افزایش دهیم تعریف می کنیم:
const cardIncrease = 9;
ما می خواهیم بدانیم چند “صفحه” خواهیم داشت، یعنی چند بار می توانیم محتوا را افزایش دهیم تا به حداکثر محدودیت برسیم. به عنوان مثال، با تعریف ما cardLimit
و cardIncrease
متغیرها، میتوانیم محتوا را 10 برابر افزایش دهیم (با فرض اینکه 9 عنصر اول را قبلاً بارگذاری کردهایم) تا زمانی که به حد مجاز برسیم. ما این کار را با تقسیم کردن انجام خواهیم داد cardLimit
توسط cardIncrease
.
const pageCount = Math.ceil(cardLimit / cardIncrease);
سپس مقداری را برای تعیین اینکه در کدام صفحه هستیم تعریف می کنیم:
let currentPage = 1;
ایجاد یک کارت جدید
اکنون همه ثابت های خود را داریم، بیایید یک تابع ایجاد کنیم تا یک کارت جدید به ظرف کارت اضافه کنیم. را تنظیم می کنیم innerHTML
از کارت های ما به مقدار شاخص، بنابراین ما می توانیم تعداد کارت هایی را که اضافه می کنیم پیگیری کنیم.
یکی از ویژگی های سرگرم کننده در این نسخه ی نمایشی این است که هر کارت یک رنگ پس زمینه به طور تصادفی ایجاد می کند.
const getRandomColor = () => { const h = Math.floor(Math.random() * 360); return `hsl(${h}deg, 90%, 85%)`; }; const createCard = (index) => { const card = document.createElement("div"); card.className = "card"; card.innerHTML = index; card.style.backgroundColor = getRandomColor(); cardContainer.appendChild(card); };
اضافه کردن کارت به کانتینر
اکنون با استفاده از عملکردی مشابه با آموزش صفحهبندی، کارتهای خود را به ظرف خود اضافه میکنیم.
ابتدا محدوده کارت هایی که باید به صفحه اضافه شوند را مشخص کنید. را addCards
تابع a را می پذیرد pageIndex
پارامتر، که جهانی را به روز می کند currentPage
ارزش. اگر در صفحه 1 هستیم، کارت های 1 تا 9 را اضافه می کنیم. اگر در صفحه 2 هستیم، کارت های 10 تا 18 و غیره را اضافه می کنیم.
از نظر ریاضی می توانیم آن را به صورت زیر تعریف کنیم:
const addCards = (pageIndex) => { currentPage = pageIndex; const startRange = (pageIndex - 1) * cardIncrease; const endRange = pageIndex * cardIncrease; for (let i = startRange + 1; i <= currRange; i++) { createCard(i); } };
در این تابع، محدوده شروع ما همیشه یک کمتر از مقداری است که میخواهیم به دست آوریم (یعنی در صفحه 1، محدوده شروع 0 است، در صفحه 2، محدوده شروع 9 است) بنابراین ما آن را محاسبه میکنیم. با تنظیم مقدار شاخص حلقه for ما به startRange + 1
.
تشخیص زمانی که به محدودیت کارت رسیده است
محدودیتی که باید به آن توجه کنیم این است endRange
عدد. اگر در صفحه آخر هستیم، میخواهیم محدوده پایانی ما مانند صفحه باشد cardLimit
. به عنوان مثال، اگر ما یک cardLimit
از 75 و الف cardIncrease
از 10 و ما در صفحه 8 هستیم، شاخص شروع ما 70 و ما خواهد بود endRange
مقدار باید 75 باشد.
ما خود را اصلاح خواهیم کرد addCards
تابع برای محاسبه این:
const addCards = (pageIndex) => { currentPage = pageIndex; const startRange = (pageIndex - 1) * cardIncrease; const endRange = currentPage == pageCount ? cardLimit : pageIndex * cardIncrease; for (let i = startRange + 1; i <= endRange; i++) { createCard(i); } };
نسخه ی نمایشی ما همچنین شامل یک cardTotal
عنصری که تعداد کارت هایی را که در حال حاضر در صفحه نشان داده شده اند نشان می دهد، بنابراین ما آن را تنظیم می کنیم innerHTML
این عنصر به عنوان محدوده پایانی.
const addCards = (pageIndex) => { currentPage = pageIndex; const startRange = (pageIndex - 1) * cardIncrease; const endRange = currentPage == pageCount ? cardLimit : pageIndex * cardIncrease; cardCountElem.innerHTML = endRange; for (let i = startRange + 1; i <= endRange; i++) { createCard(i); } };
بارگیری کارت های اولیه
ما یک ویژگی برای افزودن کارتها به ظرف تعریف کردهایم، بنابراین a را اضافه میکنیم window.onload
عملکردی برای تنظیم کارت های اولیه برای اضافه شدن به صفحه.
window.onload = function () { addCards(currentPage); };
دست زدن به اسکرول بی نهایت
ما با افزایش اسکرول بی نهایت خود را مدیریت خواهیم کرد currentPage
شماره برای افزودن کارت های جدید به ظرف زمانی که به انتهای صفحه رسیدیم. با افزودن عبارت می توانیم تشخیص دهیم که چه زمانی به انتهای صفحه رسیده است innerHeight
از پنجره به مقدار اسکرول pageYOffset
و مقایسه آن با سند offsetHeight
که ارتفاع کل صفحه است.
در اینجا یک نمایش بصری از آنچه به نظر می رسد آمده است:
هنگامی که به انتهای صفحه رسیدیم، می خواهیم با تماس با ما صفحه جدیدی را بارگذاری کنیم addCards
عملکرد با currentPage + 1.
const handleInfiniteScroll = () => { const endOfPage = window.innerHeight + window.pageYOffset >= document.body.offsetHeight; if (endOfPage) { addCards(currentPage + 1); } };
سپس یک رویداد شنونده برای اسکرول پنجره ایجاد می کنیم و تابع بالا را به آن منتقل می کنیم:
window.addEventListener("scroll", handleInfiniteScroll);
بهینه سازی عملکرد
از آنجایی که ما با شنونده رویداد پیمایش کار می کنیم، محدود کردن تعداد تماس های برقرار شده برای عملکرد صفحه وب مفید است. با استفاده از عملکرد دریچه گاز می توانیم تعداد تماس ها را کاهش دهیم.
عملکرد دریچه گاز خود را به این صورت تعریف می کنیم:
var throttleTimer; const throttle = (callback, time) => { if (throttleTimer) return; throttleTimer = true; setTimeout(() => { callback(); throttleTimer = false; }, time); };
و سپس تابع دریچه گاز را وارد می کنیم handleInfiniteScroll
عملکرد
const handleInfiniteScroll = () => { throttle(() => { const endOfPage = window.innerHeight + window.pageYOffset >= document.body.offsetHeight; if (endOfPage) { addCards(currentPage + 1); } }, 1000); };
توقف اسکرول بی نهایت
در این مرحله، ما توابع خود را طوری تنظیم کردهایم که پس از رسیدن به انتهای صفحه، محتوای بیشتری اضافه کنیم. اکنون، اجازه دهید مطمئن شویم که عملکرد ما زمانی که محتوای بیشتری برای اضافه کردن وجود ندارد، اجرا نمیشود cardLimit
رسیده است.
ابتدا بیایید خودمان را تعریف کنیم removeInfiniteScroll
عملکرد. در این تابع، ما را حذف می کنیم handleInfiniteScroll
از شنونده رویداد اسکرول کار کنید و همچنین loader div را حذف کنید.
const removeInfiniteScroll = () => { loader.remove(); window.removeEventListener("scroll", handleInfiniteScroll); };
حالا ما خودمان را اصلاح می کنیم handleInfiniteScroll
اگر محتوای دیگری برای اضافه کردن وجود ندارد، یعنی ما در آخرین صفحه محتوا هستیم.
const handleInfiniteScroll = () => { throttle(() => { const endOfPage = window.innerHeight + window.pageYOffset >= document.body.offsetHeight; if (endOfPage) { addCards(currentPage + 1); } if (currentPage === pageCount) { removeInfiniteScroll(); } }, 1000); };
نتیجه
و حالا ما آن را در اختیار داریم! ما یک پیاده سازی کارآمد و قابل دسترس از ویژگی اسکرول بی نهایت ساخته ایم. کد کامل جاوا اسکریپت را با زدن دکمه بررسی کنید JS برگه در نسخه ی نمایشی تعبیه شده در زیر: