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

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

本文关键字:滚动 像素 为单位 何确定 jQuery 事件      更新时间:2023-09-26

我有这个事件:

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

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

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

"滚动值"不依赖于窗口大小或屏幕分辨率。"滚动值"只是滚动的像素数。

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

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

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

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

这是我创建的示例扩展,适用于窗口/文档滚动。它是一个名为 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 演示:http://jsfiddle.net/tew9zxc1/

可运行代码段(向下滚动并单击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>

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

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

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

另一种方法呢?是的,可能,使用 jQuery Mobile
我不欣赏这个解决方案,因为它有必要包括大量的jQuery移动。溶液:

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);
});

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

通过在滚动开始时隐藏滚动元素并在一段时间后使其滑入(在正确的位置),可以使整个 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");});
    });
});

现场演示在这里