يمكّن الحدث scroll
من الاستجابة لتمرير الصفحة أو عنصرٍ ما. يمكننا فعل العديد من الأمور الجيّدة في هذا الباب. على سبيل المثال:
- إظهار/إخفاء أزرار التحكّم أو معلوماتٍ إضافيّة حسب مكان المستخدم في المستند.
- تحميل المزيد من البيانات عندما يمرّر المستخدم الصفحة حتى النهاية.
إليك دالّة صغيرة تعرض الموضع الحاليّ للتمرير:
window.addEventListener('scroll', function() { document.getElementById('showScroll').innerHTML = window.pageYOffset + 'px'; });
عند اشتغالها:
يعمل الحدث scroll
سواءً مع النافذة window
أو العناصر القابلة للتمرير.
منع التمرير
كيف يمكن أن نجعل شيئا ما غير قابل للتمرير؟
لا يمكن منع التمرير بمجرّد استخدام event.preventDefault()
في منصت الحدث onscroll
، لأنّ هذا الحدث يقع بعد حصول التمرير.
لكن يمكننا منع التمرير باستخدام event.preventDefault()
مع الحدث الذي يتسبّب في التمرير، مثل حدث keydown
عند الضغط على المفاتيح pageUp
وpageDown
. فإذا وضعنا معالجات لهذه اﻷحداث مع event.preventDefault()
داخلها، لن يحصل التمرير.
هناك عدّة طرق لحصول التمرير، لذا يجدر استخدام الخاصّيّة overflow
في CSS.
هذه بعض التمارين التي يمكنك حلّها أو النظر فيها للاطلاع على بعض تطبيقات onscroll
.
التمارين
صفحة لا متناهية
أنشئ صفحة لا متناهية. عندما يقوم الزائر بالتمرير حتى النهاية، يُلحَق التاريخ والوقت الحاليّان بالنصّ تلقائيّا (ليستطيع الزائر تمرير المزيد)، كما يمكنك مشاهدة ذلك من هنا.
يُرجى التنبّه إلى ميزتين مهمّتين للتمرير:
- التمرير "متمدّد". يمكننا مواصلة التمرير قليلا إلى ما وراء بداية أو نهاية المستند في بعض المتصفّحات/الأجهزة (تظهر مساحة فارغة في اﻷسفل، قبل أن "يرتدّ" المستند كما كان).
- التمرير غير دقيق. عندما نمرّر الصفحة حتى النهاية، قد نكون في الواقع على بعد حوالي 0-50px من نهاية المستند الحقيقيّة.
وبذلك، فإنّ "التمرير حتى النهاية" يعني أنّه لا بدّ للزائر ألّا يبعد أكثر من 100px من نهاية المستند.
ملاحظة: قد يكون الغرض في الحالات الواقعيّة عرض "المزيد من الرسائل" أو "المزيد من السلع".
أنجز التمرين في البيئة التجريبيّة.
الحلّ
يكمن الحلّ في إنشاء دالّة تضيف المزيد من التواريخ إلى الصفحة (أو تحمّل المزيد من الأشياء في الحالات الواقعيّة) عندما نكون في آخر الصفحة. يمكننا استدعاؤها مباشرة وإضافتها كمعالج window.onscroll
.
لكنّ أهمّ سؤال هو: "كيف نعرف أنّ الصفحة قد وصلت إلى اﻷسفل؟".
لنستخدم في ذلك الإحداثيّات بالنسبة إلى النافذة.
يمكننا الحصول على الإحداثيّات بالنسبة إلى النافذة في كامل المستند بواسطة document.documentElement.getBoundingClientRect()
، وتكون الخاصيّة bottom
هي إحداثيّات أسفل المستند بالنسبة إلى النافذة.
على سبيل المثال، إذا افترضنا أنّ ارتفاع كامل مستند HTML هو 2000px
، يكون لدينا:
// عندما نكون في أعلى الصفحة // القمّة بالنسبة للنافذة = 0 document.documentElement.getBoundingClientRect().top = 0 // الأسفل بالنسبة للنافذة = 2000 // المستند طويل، لذا فإنّه يتجاوز على اﻷرجح أسفل النافذة بكثير document.documentElement.getBoundingClientRect().bottom = 2000
إذا مرّرنا 500px
، فإنّ:
// 500px أعلى المستند فوق النافذة بـ document.documentElement.getBoundingClientRect().top = -500 // 500px أسفل المستند أقرب بـ document.documentElement.getBoundingClientRect().bottom = 1500
إذا مرّرنا إلى النهاية، بافتراض أنّ ارتفاع النافذة هو 600px
:
// 1400px أعلى المستند فوق النافذة بـ document.documentElement.getBoundingClientRect().top = -1400 // 600px أسفل المستند تحت النافذة بـ document.documentElement.getBoundingClientRect().bottom = 600
يُرجى التنبّه أنّ اﻷسفل bottom
لا يمكن أن يكون 0
لأنّه لا يرتقي إلى أعلى النافذة أبدا. أقلّ حدّ للإحداثيّة bottom
هو ارتفاع النافذة (افترضنا أنّها 600
)، لا نستطيع تمريرها أعلى من ذلك.
يمكننا الحصول على ارتفاع النافذة بواسطة document.documentElement.clientHeight
.
في هذا التمرين، نحتاج أن نعرف متى نبعد عن أسفل المستند بأقلّ من 100px
(بمعنى يكون أسفل المستند 600-700px
بالنسبة للنافذة، إذا كان ارتفاعها 600
).
هذه هي الدالّة إذًا:
function populate() { while(true) { // أسفل المستند let windowRelativeBottom = document.documentElement.getBoundingClientRect().bottom; // على النهاية) 100px إذا لم يمرّر المستخدم بعيدا بما يكفي (أكثر من if (windowRelativeBottom > document.documentElement.clientHeight + 100) break; // لنُضف المزيد من البيانات document.body.insertAdjacentHTML("beforeend", `<p>Date: ${new Date()}</p>`); } }
شاهد الحلّ في البيئة التجريبيّة.
زرّ اﻷعلى/اﻷسفل
اﻷهميّة:5
أنشئ زرّ "الانتقال نحو اﻷعلى" للمساعدة على تمرير الصفحة. يجب أن يعمل كالتالي:
- إذا لم تُمرَّر النافذة نحو اﻷسفل بمقدار ارتفاع النافذة على اﻷقلّ، فإنّه لا يظهر.
- إذا مُرّرت الصفحة نحو اﻷسفل بمقدار يزيد على ارتفاع النافذة، يظهر سهم يشير نحو اﻷعلى في الزاوية العليا من اليسار. إذا أعيد تمرير الصفحة نحو اﻷعلى، فإنّه يختفي.
- عند الضغط على السهم، فإنّ الصّفحة تُمرّر حتى القمّة. كما هو مبيّن هنا (في الزاوية العليا من اليسار، مرّر الصفحة لتراه).
أنجز التمرين في البيئة التجريبيّة.
الحل
شاهد الحلّ في البيئة التجريبيّة.
حمّل الصور المرئيّة
اﻷهميّة: 4
لنفترض أنّ لدينا عميلا ذا سرعة قليلة ونريد أن نحفظ له بيانات الجوّال. فقرّرنا لهذا الغرض ألّا نظهر الصور فورا، بل نضع مكانها نائبًا (placeholder)، بهذا الشكل:
<img src="placeholder.svg" width="128" height="128" data-src="real.jpg">
في البداية، تكون كلّ الصّور placeholder.svg
. وعندما تُمرّر الصفحة إلى موضع يمكن للمستخدم فيه أن يرى الصورة، نغيّر قيمة src
إلى القيمة الموجودة في data-src
، فتُحمَّل الصّورة.
يمكن مشاهدة المثال حيّا من هنا. قم بالتمرير لترى الصور تُحمّل "حسب الطلب".
المتطلّبات:
- عندما تُحمّل الصفحة، يجب أن تُحمّل الصور التي على الشاشة فورا، قبل حصول التمرير.
-
قد تكون بعض الصور عاديّة، دون
data-src
. يجب أن تتركها الشيفرة على حالها. - بعد انتهاء تحميل الصورة، يجب ألّا يُعاد تحميلها مرّة أخرى عند تمريرها إلى اﻷسفل/اﻷعلى.
ملاحظة: إذا أمكن، أنجز حلّا أكثر تقدّما يتيح "التحميل المسبق" للصور التي تكون قبل/بعد الموضع الحاليّ بمقدار صفحة.
ملاحظة أخرى: ينبغي فقط معالجة التمرير العموديّ، لا التمرير الأفقيّ.
أنجز التمرين في البيئة التجريبيّة.
الحل
يجب أن يعمل المعالجُ onscroll
على تحديد الصّور مرئيّة وعرضها. نريده أيضا أن يشتغل عند تحميل الصفحة، لاكتشاف الصور المرئيّة فورا وعرضها. يجب أن تشتغل الشيفرة بعد الانتهاء من تحميل المستند، لتتمكّن من الوصول إلى محتواه. أو توضع أسفل العنصر <body>
.
// ...محتوى الصفحة الفوق... function isVisible(elem) { let coords = elem.getBoundingClientRect(); let windowHeight = document.documentElement.clientHeight; // مرئيّ؟ elem هل الحدّ العلويّ لـ let topVisible = coords.top > 0 && coords.top < windowHeight; // مرئيّ؟ elem هل الحدّ السفليّ لـ let bottomVisible = coords.bottom < windowHeight && coords.bottom > 0; return topVisible || bottomVisible; }
تستخدم الدالّةُ showVisible()
اختبارَ الرؤية، المُنفَّذ بواسطة isVisible()
، لتحميل الصور المرئيّة:
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;
ملاحظة: هناك أيضا حلّ بديل حيث تعمل فيه isVisible
" على "التحميل المسبق" للصور الموجودة ضمن صفحة واحدة أعلى/أسفل موضع التمرير الحاليّ للمستند.
ترجمة -وبتصرف- للمقال Scrolling من سلسلة Browser: Document, Events, Interfaces لصاحبها Ilya Kantor
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.