[英]Looking for a better (more efficient) way to test for scroll position
這是一個 Javascript 項目,使用 jQuery 庫。
當瀏覽器窗口低於某個頁面位置時,我想顯示一個粘性欄,否則將其隱藏。 它的 ID 是#sticky-atc-bar
。
頁面位置由類.product-section
的元素的頂部確定。
基於對如何做到這一點的研究,我最初想出了以下 JS。
$( document ).ready(function() {
$('#sticky-atc-bar').hide();
var section = $(".product-section");
var offsetSection = section.offset().top; //check for top property
$(function() {
$(window).scroll(function() {
console.log('Scroll Event');
if ($(window).scrollTop() >= offsetSection) { // reached product section
console.log('True:');
$('#sticky-atc-bar').show();
} else { // not reached product section
console.log('False');
$('#sticky-atc-bar').hide();
}
});
});
});
這行得通。 然而,我知道它會在用戶與頁面互動的整個過程中產生很多滾動事件。 知道這是非常低效的,我去尋找替代方法。 在此過程中,我閱讀了這篇名為“從 Twitter 學習”的文章,這完全有道理。
我也遇到了類似要求的解決方案。 我的代碼版本是:
var target = $(".product-section").offset().top,
timeout = null;
$('#sticky-atc-bar').hide();
$(window).scroll(function () {
if (!timeout) {
timeout = setTimeout(function () {
console.log('scroll');
clearTimeout(timeout);
timeout = null;
if ($(window).scrollTop() >= target) {
$('#sticky-atc-bar').show();
} else {
$('#sticky-atc-bar').hide();
}
}, 250);
}
});
我在這個 jsFiddle上設置了它,它可以工作。
但是......它仍然會產生大量事件。 它們被簡單地減少為每 250 毫秒一個事件,因此每秒 4 個。
我想知道是否有更好的方法來解決這個問題? 換句話說,除了更改第二段代碼的超時之外,我可以將此操作減少到更少的事件嗎? 在這一點上這甚至是必要的,還是每 250 毫秒發生一個事件不會產生重大影響?
給你: https ://jsfiddle.net/son0azfj/
var productEl = document.querySelector('.product-section')
var stickyEl = document.querySelector('#sticky-atc-bar')
// check if we have elements
if (productEl && stickyEl) {
// create an observer object, binding toggleDisplayFactory to it
var observer = new IntersectionObserver(toggleDisplayFactory(stickyEl))
// observe the product element
observer.observe(productEl)
}
// [1] create a named function which accepts an element...
function toggleDisplayFactory(element) {
// and returns a function - the handler that IntersectionObserver expects
return function handler(entries) {
// determine if the observed element is in the viewport or not
var isInViewPort = Boolean(entries.find(entry => entry.intersectionRatio > 0))
/**
* if in the viewport:
* we want the element passed in at [1] to use it's own styles, i.e. remove the inline style property
* else:
* we want the element to inherit its default display property (e.g. block, inline, inline-block, etc.) and thus be visible
*/
var display = isInViewPort ? null : 'inherit'
// set the display property of the element passed in at [1]
element.style.display = display
}
}
InterSectionObserver
觀察元素相對於視口的位置。 使用該元素在視口中的位置來“做其他事情”,即顯示/隱藏另一個元素setTimeout
來操作 DOM - 改用requestAnimationFrame
(此處不需要)推理:
IntersectionObserver
允許您觀察任意元素相對於其在視口中的位置,而不是在滾動時快速觸發的滾動事件。 觀察到的元素觸發的事件僅在其相對於視口的位置發生變化時觸發
setTimeout
- 如果您要使用超時,您需要考慮一些適合在使用setTimeout
時使用的數字。 你怎么做到這一點? 好吧,你只能猜測......你必須使用一個幻數。 requestAnimationFrame
而是知道 DOM 何時准備好重新渲染和計算布局 - 不需要幻數
鏈接:
編輯:隨意用$(selector)
替換document.querySelector
- 其余代碼將按原樣工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.