Javascript jQuery 滚动事件:如何以像素为单位确定滚动量(滚动增量)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26990986/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:35:42  来源:igfitidea点击:

jQuery scroll event: how to determine amount scrolled (scroll delta) in pixels?

javascriptjquery

提问by Andrey Vorobyev

I have this event:

我有这个事件:

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

I want to know, how much I have scroll value in pixels, because I think, scroll value depends from window size and screen resolution.

我想知道,我有多少像素滚动值,因为我认为,滚动值取决于窗口大小和屏幕分辨率。

Function parameter edoes not contains this information.
I can store $(window).scrollTop()after every scroll and calculate difference, but can I do it differently?

函数参数e不包含此信息。
我可以$(window).scrollTop()在每次滚动后存储并计算差异,但我可以做不同的事情吗?

回答by nothingisnecessary

The "scroll value" does not depend on the window size or screen resolution. The "scroll value" is simply the number of pixels scrolled.

“滚动值”不取决于窗口大小或屏幕分辨率。“滚动值”只是滚动的像素数。

However, whether you are able to scroll at all, and the amount you canscroll is based on available real estate for the container and the dimensions of the content within the container (in this case the container is document.documentElement, or document.bodyfor older browsers).

但是,您是否能够滚动以及您可以滚动的数量取决于容器的可用空间和容器内内容的尺寸(在这种情况下,容器是document.documentElement,或者document.body对于较旧的浏览器)。

You are correct that the scrollevent does not contain this information. It does not provide a deltaproperty to indicate the number of pixels scrolled. This is true for the native scrollevent and the jQuery scrollevent. This seems like it would be a useful feature to have, similar to how mousewheelevents provide properties for X and Y delta.

您是正确的,该scroll事件不包含此信息。它不提供delta指示滚动像素数的属性。对于本机scroll事件和 jQueryscroll事件来说都是如此。这似乎是一个有用的功能,类似于mousewheel事件如何为 X 和 Y delta 提供属性。

I do not know, and will not speculate upon, why the powers-that-be did not provide a deltaproperty for scroll, but that is out of scope for this question (feel free to post a separate question about this).

我不知道,也不会推测,为什么权力没有为 提供delta属性scroll,但这超出了这个问题的范围(请随意发布一个关于此的单独问题)。

The method you are using of storing scrollTopin a variable and comparing it to the current scrollTopis the best (and only) method I have found. However, you can simplify this a bit by extending jQuery to provide a new custom event, per this article: http://learn.jquery.com/events/event-extensions/

您使用的存储scrollTop变量并将其与当前进行比较的scrollTop方法是我发现的最好(也是唯一)的方法。但是,您可以通过扩展 jQuery 以提供新的自定义事件来简化这一点,根据这篇文章:http: //learn.jquery.com/events/event-extensions/

Here is an example extension I created that works with window / document scrolling. It is a custom event called scrolldeltathat automatically tracks the X and Y delta (as scrollLeftDeltaand scrollTopDelta, respectively). I have not tried it with other elements; leaving this as exercise for the reader. This works in currrent versions of Chrome and Firefox. It uses the trick for getting the sum of document.documentElement.scrollTopand document.body.scrollTopto handle the bug where Chrome updates body.scrollTopinstead of documentElement.scrollTop(IE and FF update documentElement.scrollTop; see https://code.google.com/p/chromium/issues/detail?id=2891).

这是我创建的适用于窗口/文档滚动的示例扩展。这是一个调用的自定义事件scrolldelta,可自动跟踪 X 和 Y 增量(分别为scrollLeftDeltascrollTopDelta)。我还没有尝试过其他元素;将此作为练习留给读者。这适用于当前版本的 Chrome 和 Firefox。它使用技巧来获取总和document.documentElement.scrollTopdocument.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/

JSFiddle 演示:http: //jsfiddle.net/tew9zxc1/

Runnable Snippet (scroll down and click Run code snippet):

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>

Note that you may want debounce the event depending on what you are doing. You didn't provide very much context in your question, but if you give a better example of what you are actually using this info for we can provide a better answer. (Please show more of your code, and how you are using the "scroll value").

请注意,您可能希望根据您正在执行的操作对事件进行去抖。您在问题中没有提供太多背景信息,但是如果您提供一个更好的示例说明您实际使用此信息的目的,我们可以提供更好的答案。(请显示更多您的代码,以及您如何使用“滚动值”)。

回答by somethinghere

To detemine how many pixels were scrolled you have to keep in mind that the scrollevent gets fired almost every pixel that you move. The way to accomplish it is to save the previous scrolled value and compare that in a timeout. Like this:

要确定滚动了多少像素,您必须记住,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);
});

This way you will get the amount of scrolled a second after scrolling (this is adjustable but you have to keep in mind that the smooth scrolling that is so prevalent today has some run-out time and you dont want to trigger before a full stop).

通过这种方式,您将在滚动后获得一秒钟的滚动量(这是可调整的,但您必须记住,当今如此普遍的平滑滚动有一些用完时间,您不想在句号之前触发) .

回答by iamawebgeek

The other way to do this? Yes, possible, with jQuery Mobile
I do not appreciate this solution, because it is necessary to include heavy jQuery mobile. Solution:

另一种方法来做到这一点?是的,可能,使用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);
});

回答by Fabrizio

To reduce the used processing power by adding a timer to a Jquery scroll method is probably not a great idea. The visual effect is indeed quite bad.

通过向 Jquery 滚动方法添加计时器来减少使用的处理能力可能不是一个好主意。视觉效果确实很差。

The whole web browsing experience could be made much better by hiding the scrolling element just when the scroll begins and making it slide in (at the right position) some time after. The scrolling even can be checked with a delay too. This solution works great.

通过在滚动开始时隐藏滚动元素并使其在一段时间后滑入(在正确的位置),可以使整个 Web 浏览体验变得更好。滚动甚至可以延迟检查。这个解决方案效果很好。

$(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");});
    });
});

Live demo here

现场演示在这里