۱۶ ژوئیه ۲۰۲۳

اسکرول کردن (Scrolling)

ایونت scroll اجازه می‌دهد به یک صفحه یا المنت واکنش نشان دهید. چندین کار جالب وجود دارد که می‌توانیم انجام دهیم.

برای مثال:

  • نمایش دادن یا پنهان کردن کنترل‌ های اضافی یا اطلاعات، با توجه به این که کاربر کجای داکیومنت است.
  • بارگذاری کردن بیشتر داده، هنگامی که کاربر درحال اسکرول به سمت انتهای پیج است.

اینجا یک تابع کوچک برای نمایش دادن اسکرول فعلی می‌باشد:

window.addEventListener('scroll', function() {
  document.getElementById('showScroll').innerHTML = window.pageYOffset + 'px';
});

در عمل:

اسکرول فعلی = اسکرول window

ایونت scroll در window و المنت‌های قابل اسکرول کار می‌کند.

جلوگیری از اسکرول کردن

چطور می‌توانیم چیزی را غیر قابل اسکرول کنیم؟

ما نمی‌توانیم اسکرول کردن را توسط ()event.preventDefault در onscroll listener جلوگیری کنیم چون پس از اسکرولی که قبلا اتفاق افتاده است رخ می‌دهد.

اما می‌توانیم توسط ()event.preventDefault از ایونتی که باعث اسکرول می‌شود جلوگیری کنیم. برای مثال: ایونت keydown برای pageUp و pageDown

اگر ما یک ایونت هندلر به این ایونت‌ها و درون آن ()event.preventDefault اضافه کنیم، اسکرول شروع نخواهد شد.

راه های زیادی برای شروع کردن یک اسکرول وجود دارد پس استفاده از ویژگی CSS overflow خیلی قابل اطمینان‌تر است.

اینجا چند تمرین وجود دارد که شما می‌توانید آنها را حل کنید یا نگاهی به اپلیکیشن های onscroll بیندازید.

تمارین

اهمیت: 5

یک صفحه بی پایان ایجاد کنید. وقتی یک بیننده به انتهای آن اسکرول می‌کند صفحه به طور خودکار تاریخ فعلی را به طور متنی اضافه می‌کند (پس اینطوری کاربر می‌تواند بیشتر اسکرول کند)

مثل این:

لطفا به دو ویژگی مهم اسکرول توجه داشته باشید:

  1. اسکرول “قابل ارتجاع” است. ما می‌توانیم کمی فرانتر از شروع یا پایان داکیومنت، در برخی از مرورگر‌ها و دستگاه‌ها اسکرول کنیم (فضای خالی زیر نشان داده شده است و سپس داکیومنت به طور خودکار به حالت عادی بر می‌گردد.).

  2. اسکرول دقیق نیست… هنگامی که به انتهای صفحه اسکرول می‌کنیم ممکن است در حقیقت از document bottom بین 0 تا 50 پیکسل فاصله داشته باشیم.

پس “اسکرول کردن به انتها” باید به این معنا باشد که بیننده بیش از 100 پیکسل به پایان داکیومنت فاصله ندارد…

در واقعیت ممکن است بخواهیم “پیام‌های بیشتر” یا “کالاهای بیشتر” را نمایش دهیم.

باز کردن یک sandbox برای تمرین.

هسته راه‌حل تابعی است که تاریخ های بیشتر را هنگامی که در انتهای صفحه هستیم به صفحه اضافه می‌کند (یا در واقعیت بارگذاری اجناس بیشتر).

ما می‌توانیم بلافاصله آن را فراخوانی کنیم و به عنوان هندلر window.onscroll اضافه‌اش کنیم.

مهم‌ترین سوال این است که: “چگونه تشخیص دهیم که صفحه به پایین اسکرول شده است؟”

بیایید از مختصات مربوط به window استفاده کنیم.

داکیومنت در تگ <html> نمایش داده می‌شود که آن document.documentElement است.

ما می‌توانیم مختصات مروبط به window کل داکیومنت را به صورت ()document.documentElement.getBoundingClientRect دریافت کنیم. ویژگی bottom، مختصات مربوط به window document bottom خواهد بود.

برای مثال اگر ارتفاع کل داکیومنت 2000px HTML است سپس:

// when we're on the top of the page
// window-relative top = 0
document.documentElement.getBoundingClientRect().top = 0

// window-relative bottom = 2000
// the document is long, so that is probably far beyond the window bottom
document.documentElement.getBoundingClientRect().bottom = 2000

اگر ما 500px به پایین اسکرول کنیم سپس:

// document top is above the window 500px
document.documentElement.getBoundingClientRect().top = -500
// document bottom is 500px closer
document.documentElement.getBoundingClientRect().bottom = 1500

هنگامی که ما تا انتها اسکرول می‌کنیم فرض می‌کنیم ارتفاع 600px window است:

// document top is above the window 1400px
document.documentElement.getBoundingClientRect().top = -1400
// document bottom is below the window 600px
document.documentElement.getBoundingClientRect().bottom = 600

لطفا توجه داشته باشید که bottom نمی‌تواند 0 باشد چون هیچوقت به بالای window نمی‌رسد. پایین‌ترین حد مختصات bottom ارتفاع window است (ما فرض کردیم 600 است)، ما نمی‌توانیم دیگر بیشتر اسکرول کنیم.

ما می‌توانیم ارتفاع window را به صورت document.documentElement.clientHeight به دست آوریم.

برای تمرین‌مان، ما باید بدانیم تا پایین داکیومنت چه زمانی بیشتر از 100px فاصله دارد (آن: 600px-700px است اگر ارتفاع 600 باشد)

پس این تابع است:

function populate() {
  while(true) {
    // document bottom
    let windowRelativeBottom = document.documentElement.getBoundingClientRect().bottom;

    // if the user hasn't scrolled far enough (>100px to the end)
    if (windowRelativeBottom > document.documentElement.clientHeight + 100) break;

    // let's add more data
    document.body.insertAdjacentHTML("beforeend", `<p>Date: ${new Date()}</p>`);
  }
}

باز کردن راه‌حل درون sandbox.

اهمیت: 5

یک دکمه “به بالا” برای کمک به اسکرول کردن صفحه بسازید

باید مانند این کار کند:

  • هنگامی که کاربر به انتهای صفحه نرسیده است مخفی باشد.
  • وقتی صفحه بیشتر از ارتفاع window اسکرول شد علامت فلش “به بالا” در گوشه چپ بالا ظاهر شود. اگر به عقب اسکرول شد آن ناپدید شود.
  • وقتی که بر روی دکمه کلیک شد صفحه به بالا اسکرول شود.

مثل این (گوشه چپ بالا، اسکرول کنید تا ببینید)

باز کردن یک sandbox برای تمرین.

اهمیت: 4

بیایید فرض کنیم یک کلاینت که سرعت پایینی دارد داریم و می‌خواهیم ترافیک موبایل آن را ذخیره کنیم.

برای این کار ما تصمیم می‌گیریم بلافاصله تصاویر را نمایش ندهیم اما درعوض جای آن را با placeholderها پر کنیم مانند این:

<img src="placeholder.svg" width="128" height="128" data-src="real.jpg">

پس در ابتدا تمام تصاویر placeholder.svg هستند. هنگامی که صفحه به موقعیتی کاربر می‌تواند تصویر را ببیند اسکرول شد ما src را به آن data-src تغییر می‌دهیم و تصویر بارگذاری می‌شود.

اینجا در iframe یک مثال است:

اسکرول کنید تا تصویر بارگذاری شود.

الزامات:

  • هنگامی که صفحه بارگذاری می‌شود تصاویری که روی صفحه هستند بدون هیچ اسکرولی بلافاصله باید بارگذاری شوند.
  • برخی تصاویر ممکن است عادی و بدون data-src باشند. کد نباید آنها را تحت تاثیر قرار دهد.
  • وقتی تصویری بارگذاری شد نباید با اسکرول مجدد دوباره تصویر بارگذاری شود.

اگر می‌توانید پاسخ پیشرفته‌تری ایجاد کنید که تصاویری که در پایین/بعد از موقعیت فعلی هستند از قبل بارگذاری شوند.

.فقط اسکرول عمودی پیاده شود نه اسکرول افقی

باز کردن یک sandbox برای تمرین.

The onscroll handler should check which images are visible and show them.

We also want to run it when the page loads, to detect immediately visible images and load them.

The code should execute when the document is loaded, so that it has access to its content.

Or put it at the <body> bottom:

// ...the page content is above...

function isVisible(elem) {

  let coords = elem.getBoundingClientRect();

  let windowHeight = document.documentElement.clientHeight;

  // top elem edge is visible?
  let topVisible = coords.top > 0 && coords.top < windowHeight;

  // bottom elem edge is visible?
  let bottomVisible = coords.bottom < windowHeight && coords.bottom > 0;

  return topVisible || bottomVisible;
}

The showVisible() function uses the visibility check, implemented by isVisible(), to load visible images:

function showVisible() {
  for (let img of document.querySelectorAll('img')) {
    let realSrc = img.dataset.src;
    if (!realSrc) continue;

    if (isVisible(img)) {
      img.src = realSrc;
      img.dataset.src = '';
    }
  }
}

showVisible();
window.onscroll = showVisible;

P.S. The solution also has a variant of isVisible that “preloads” images that are within 1 page above/below the current document scroll.

باز کردن راه‌حل درون sandbox.

نقشه آموزش