Событие прокрутки jQuery: как определить количество прокрутки (прокрутка delta) в пикселях?

У меня есть это событие:

$(window).scroll(function(e){    
    console.log(e);
})

Я хочу знать, насколько у меня есть значение прокрутки в пикселях, потому что я думаю, что значение прокрутки зависит от размера окна и разрешения экрана.

Функциональный параметр e не содержит эту информацию.
Я могу хранить $(window).scrollTop() после каждого прокрутки и вычислять разницу, но могу ли я сделать это по-другому?

Ответ 1

Значение "прокрутки" не зависит от размера окна или разрешения экрана. "Прокрутка" - это просто число прокрутки пикселей.

Однако, можете ли вы вообще прокручивать, а сумма, которую вы можете прокручивать, основана на доступной недвижимости для контейнера и размерах содержимого в контейнере (в этом случае контейнер равен document.documentElement, или document.body для старых браузеров).

Вы правы, что событие scroll не содержит этой информации. Он не предоставляет свойство delta для указания количества прокрученных пикселей. Это относится к собственному событию scroll и событию jQuery scroll. Кажется, что это была бы полезная функция, похожая на то, как события mousewheel предоставляют свойства для X и Y дельта.

Я не знаю и не буду размышлять о том, почему полномочия, которые не предоставили свойство delta для scroll, но это выходит за рамки этого вопроса (не стесняйтесь публиковать отдельный вопрос об этом).

Метод, который вы используете для хранения scrollTop в переменной и сравнивая его с текущим scrollTop, является лучшим (и единственным) методом, который я нашел. Однако вы можете упростить это, расширив jQuery, чтобы предоставить новое настраиваемое событие в этой статье: http://learn.jquery.com/events/event-extensions/

Вот пример расширения, который я создал, который работает с прокруткой окна/документа. Это настраиваемое событие под названием scrolldelta, которое автоматически отслеживает дельта X и Y (как scrollLeftDelta и scrollTopDelta, соответственно). Я не пробовал это с другими элементами; оставляя это как упражнение для читателя. Это работает в точных версиях Chrome и Firefox. Он использует трюк для получения суммы document.documentElement.scrollTop и document.body.scrollTop для обработки ошибки, в которой Chrome обновляет body.scrollTop вместо documentElement.scrollTop (обновление IE и FF documentElement.scrollTop, см. https://code.google.com/p/chromium/issues/detail?id=2891).

JSFiddle demo: http://jsfiddle.net/tew9zxc1/

Runnable Snippet (прокрутите вниз и нажмите Run code snippet):

// custom 'scrolldelta' event extends 'scroll' event
jQuery.event.special.scrolldelta = {
    delegateType: "scroll",
    bindType: "scroll",
    handle: function (event) {
        var handleObj = event.handleObj;
        var targetData = jQuery.data(event.target);
        var ret = null;
        var elem = event.target;
        var isDoc = elem === document;
        var oldTop = targetData.top || 0;
        var oldLeft = targetData.left || 0;
        targetData.top = isDoc ? elem.documentElement.scrollTop + elem.body.scrollTop : elem.scrollTop;
        targetData.left = isDoc ? elem.documentElement.scrollLeft + elem.body.scrollLeft : elem.scrollLeft;
        event.scrollTopDelta = targetData.top - oldTop;
        event.scrollTop = targetData.top;
        event.scrollLeftDelta = targetData.left - oldLeft;
        event.scrollLeft = targetData.left;
        event.type = handleObj.origType;
        ret = handleObj.handler.apply(this, arguments);
        event.type = handleObj.type;
        return ret;
    }
};

// bind to custom 'scrolldelta' event
$(window).on('scrolldelta', function (e) {
    var top = e.scrollTop;
    var topDelta = e.scrollTopDelta;
    var left = e.scrollLeft;
    var leftDelta = e.scrollLeftDelta;
  // do stuff with the above info; for now just display it to user
    var feedbackText = 'scrollTop: ' + top.toString() + 'px (' + (topDelta >= 0 ? '+' : '') + topDelta.toString() + 'px), scrollLeft: ' + left.toString() + 'px (' + (leftDelta >= 0 ? '+' : '') + leftDelta.toString() + 'px)';
    document.getElementById('feedback').innerHTML = feedbackText;
});
#content {
    /* make window tall enough for vertical scroll */
    height: 2000px;
    /* make window wide enough for horizontal scroll */
    width: 2000px;
    /* visualization of scrollable content */
    background-color: blue;
}
#feedback {
    border:2px solid red;
    padding: 4px;
    color: black;
    position: fixed;
    top: 0;
    height: 20px;
    background-color: #fff;
    font-family:'Segoe UI', 'Arial';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='feedback'>scrollTop: 0px, scrollLeft: 0px</div>
<div id='content'></div>

Ответ 2

Чтобы определить, сколько пикселей было прокручено, вы должны иметь в виду, что событие scroll запускается почти каждый пиксель, который вы перемещаете. Для этого нужно сохранить предыдущее прокручиваемое значение и сравнить его с таймаутом. Вот так:

var scrollValue = 0;
var scrollTimeout = false

$(window).scroll(function(event){
    /* Clear it so the function only triggers when scroll events have stopped firing*/
    clearTimeout(scrollTimeout);
    /* Set it so it fires after a second, but gets cleared after a new triggered event*/
    scrollTimeout = setTimeout(function(){
        var scrolled = $(document).scrollTop() - scrollValue;
        scrollValue = $(document).scrollTop();
        alert("The value scrolled was " + scrolled);
    }, 1000);
});

Таким образом вы получите количество прокрутки секунды после прокрутки (это настраивается, но вы должны иметь в виду, что гладкая прокрутка, которая так распространена сегодня, имеет некоторое время выбега, и вы не хотите запускать ее до полная остановка).

Ответ 3

Другой способ сделать это? Да, возможно, с jQuery Mobile
Я не понимаю этого решения, потому что необходимо включить тяжелый jQuery mobile. Решение:

var diff, top = 0;
$(document).on("scrollstart",function () {
  // event fired when scrolling is started
  top = $(window).scrollTop();
});
$(document).on("scrollstop",function () {
  // event fired when scrolling is stopped
  diff = Math.abs($(window).scrollTop() - top);
});

Ответ 4

Чтобы уменьшить используемую мощность обработки, добавив таймер в метод прокрутки Jquery, вероятно, не очень хорошая идея. Визуальный эффект действительно очень плохой.

Весь опыт просмотра веб-страниц можно было бы сделать намного лучше, спрятав элемент прокрутки сразу же после начала прокрутки и запустив его (в правильном положении) некоторое время спустя. Прокрутка даже может быть проверена с задержкой тоже. Это решение отлично работает.

$(document).ready(function() {

    var element = $('.movable_div'),
    originalY = element.offset().top;
    element.css('position', 'relative');

    $(window).on('scroll', function(event) {
        var scrollTop = $(window).scrollTop();
        element.hide();
        element.stop(false, false).animate({
            top: scrollTop < originalY
                    ? 0
                    : scrollTop - originalY + 35
        }, 2000,function(){element.slideDown(500,"swing");});
    });
});

Демо-версия здесь