无限滚动jQuery插件

72

我正在使用Coldfusion开发网站,想要设置无限滚动。由于我对Javascript和JQuery不太熟悉,所以在理解这些方面遇到了一些问题。是否需要在我的网站上添加分页才能使用无限滚动插件,或者有没有其他方法可以实现呢?


@francis,你所说的“costly”是什么意思?你不必将所有内容都绑定到滚动条上。这取决于你想要做什么。这只是一个通用的例子。滚动条在各种浏览器中都得到支持。 - Hussein
1
尝试这个很棒的无限滚动 - https://github.com/yairEO/infinite - vsync
@vsync 不是怪你,但是当我滚动时,它似乎有点不稳定,对我来说,当我滚动时,它会从20跳到40?Moz Firefox fyi - Shaun Moore
@ShaunMoore - 这取决于操作系统以及是否启用了某些平滑滚动。我在六年前设计它,用于隐藏滚动条的设计中,这样行为更有意义。 - vsync
7个回答

141

你不需要无限滚动插件来实现这个功能。使用jQuery可以检测滚动条是否到达页面底部,如下:

$(window).scroll(function () { 
   if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
      //Add something at the end of the page
   }
});

JsFiddle上的演示


2
为什么是-10这个常数?它是滚动条箭头的大小吗? - brunosp86
8
当页面滚动到距离底部10像素时就会发生滚动,而不一定是到达页面的最底部才发生。这并非必需,但可以更好地控制页面滚动时的位置。 - Hussein
3
可以将其应用于固定的DIV而不是页面吗? - Mark Vital
@Hussein 谢谢,这很简单又不错,我可以在上面的代码中直接调用我的 ajax。 - kobe
太棒了!我不得不对更大的滚动区域触发器进行了一些小修改。基本上,我设置了一个触发器,以防止连续追加,直到最后一个追加成功为止。答案在这里:https://dev59.com/p2445IYBdhLWcg3wDWGc#18090897 - Nick
显示剩余3条评论

26

我正在使用Hussein的回答进行AJAX请求。我修改了代码,将其触发点从10px改为300px,但由于在300px范围内滚动调用频率比10px范围内更高,所以它开始导致我的附加内容倍增而AJAX请求尚未完成。

为了解决这个问题,我添加了一个在成功加载AJAX时会被触发的触发器。我的代码看起来更像是这样:

var scrollLoad = true;

$(window).scroll(function () { 
  if (scrollLoad && $(window).scrollTop() >= $(document).height() - $(window).height() - 300) {
    scrollLoad = false;
    //Add something at the end of the page
  }
});

然后在我的 AJAX 响应中,我将 scrollLoad 设置为 true


我也不得不添加分页代码来完成效果。虽然不难,但需要注意。 - thekingoftruth
我使用了这种方法,它很好用。谢谢。但在页面末尾会出现闪烁。那是数据库的最后一条记录。但是当用户尝试加载更多时,页面会闪烁。如何解决这个问题? - Prageeth Liyanage

10

我在Hussein的示例基础上构建了一个jQuery小部件。 它支持localStorage以临时保存附加的结果,并具有暂停功能,以便每隔一段时间停止附加,需要单击才能继续。

试试吧:

http://www.hawkee.com/snippet/9445/


1
仅提供链接是不够的。请复制/粘贴您的文章在这里。 - aloisdg

3
$(function(){ 
    $(window).scroll(function(){
           if($(document).height()<=$(window).scrollTop()+$(window).height()+100){
               alert('end of page');
           }
       });
});

有人要求解释,所以这里是解释:

$(document).height()-->是整个文档的高度。在大多数情况下,这等于当前文档的 元素。

$(window).height()-->是窗口(浏览器)的高度,表示在浏览器中看到的任何内容的高度。

$(window).scrollTop()-->Element.scrollTop 属性获取或设置元素向上滚动的像素数。元素的 scrollTop 是元素顶部到其最顶部可见内容的距离的测量值。当元素内容不生成垂直滚动条时,其 scrollTop 值默认为 0。

$(document).height()<=$(window).scrollTop()+$(window).height()+100

将 $(window).scrollTop() 与 $(window).height() 相加,现在检查结果是否等于您的文档高度。如果相等,表示您已经到达了底部。我们添加了100,因为我想在离文档底部100像素之前进行检查(请注意条件中的 <=)。

如果我有错误,请纠正我。


1
虽然这个答案可能是正确和有用的,但最好还是附上一些解释来解释它如何帮助解决问题。如果将来发生了变化(可能与此无关),导致它停止工作并且用户需要了解它曾经如何工作,这将变得尤为有用。谢谢! - Hatchet
非常感谢您的解释。我现在理解了代码工作背后的逻辑,而不是简单地复制粘贴代码。否则的话,这几乎会成为我的噩梦。再次感谢! - Formula12

2

我曾经遇到过同样的问题,但没有找到适合我需求的插件。因此,我编写了以下代码。这段代码通过使用ajax和分页获取数据,并将模板附加到元素上。 为了检测用户何时滚动到div底部,我使用了以下条件:

var t = $("#infiniteContent").offset().top;
var h = $("#infiniteContent").height();
var ws = $(window).scrollTop();
var dh = $(document).height();
var wh = $(window).height();

if (dh - (wh + ws) < dh - (h + t)) {
    //now you are at bottom of #infiniteContent element
}

$(document).ready(function(){
 $.getJSON("https://jsonplaceholder.typicode.com/comments", { _page: 1, _limit:3 }, function (jsonre) {
        appendTemplate(jsonre,1);
    });
});

function appendTemplate(jsonre, pageNumber){
 //instead of this code you can use a templating plugin like "Mustache"
 for(var i =0; i<jsonre.length; i++){
   $("#infiniteContent").append("<div class='item'><h2>"+jsonre[i].name+"</h2><p>"+jsonre[i].body+"</p></div>");
  }

  if (jsonre.length) {
    $("#infiniteContent").attr("data-page", parseInt(pageNumber)+1);
    $(window).on("scroll", initScroll);
    
    //scroll event will not trigger if window size is greater than or equal to document size
    var dh = $(document).height() , wh = $(window).height();
    if(wh>=dh){
     initScroll();
    }
  }
  else {
    $("#infiniteContent").attr("data-page", "");
  }
}

function initScroll() {
    var t = $("#infiniteContent").offset().top;
    var h = $("#infiniteContent").height();
    var ws = $(window).scrollTop();
    var dh = $(document).height();
    var wh = $(window).height();

    if (dh - (wh + ws) < dh - (h + t)) {
        $(window).off('scroll');
        var p = $("#infiniteContent").attr("data-page");
        if (p) {
            $.getJSON("https://jsonplaceholder.typicode.com/comments", { _page: p, _limit:3 }, function (jsonre) {
                appendTemplate(jsonre, p);
            });
        }
    }
}
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<div id="infiniteContent"></div>


这非常有用。不要低估这个答案,只因为它不是最佳答案。它能够正常工作,并且速度非常快。 - mkdavor

1
如果您有一个可以滚动的元素,比如一个带有滚动溢出的div,但没有可滚动的文档/页面,您可以采用这种方式。
       $(function () {
            var s = $(".your-scrollable-element");
            var list = $("#your-table-list");

            /* On element scroll */
            s.scroll(function () {
                /* The scroll top plus element height equals to table height */
                if ((s.scrollTop() + s.height()) == list.height()) {
                    /* you code */
                }
            });
        });

0
我使用Hussein和Nick的想法编写了这个函数,但我希望它使用 promises作为回调函数。如果将div发送到选项对象中,则还希望无限滚动区域位于固定的div上而不仅仅是窗口。我的第二个链接中有一个示例。如果要支持旧浏览器,请使用像 Q这样的promise库。cb方法可能是promise,也可能不是,但它都能正常工作。
它的使用方式如下:
html
<div id="feed"></div>

js

var infScroll = infiniteScroll({
    cb: function () {
        return doSomethingPossiblyAnAJAXPromise();     
    }
});

如果您想暂时停止该源,可以在cb方法中返回false。如果您已经到达了该源的末尾,则此方法非常有用。您可以通过调用infiniteScroll返回的对象方法“setShouldLoad”,并传入true和示例来重新启动它。

infScroll.setShouldLoad(true);

无限滚动的函数是这个

function infiniteScroll (options) {
    // these options can be overwritten by the sent in options
    var defaultOptions = {
        binder: $(window), // parent scrollable element
        loadSpot: 300, //
        feedContainer: $("#feed"), // container
        cb: function () { },
    }

    options = $.extend(defaultOptions, options);
    options.shouldLoad = true;

    var returnedOptions = {
        setShouldLoad: function (bool) { options.shouldLoad = bool; if(bool) { scrollHandler(); } },
    };

    function scrollHandler () { 
        var scrollTop = options.binder.scrollTop();
        var height = options.binder[0].innerHeight || options.binder.height();
        if (options.shouldLoad && scrollTop >= (options.binder[0].scrollHeight || $(document).height()) - height - options.loadSpot) {
            options.shouldLoad = false;
            if(typeof options.cb === "function") {
                new Promise(function (resolve) {resolve();}).then(function() { return options.cb(); }).then(function (isNotFinished) {
                    if(typeof isNotFinished === "boolean") {
                        options.shouldLoad = isNotFinished;
                    }
                });
            }
        }
    }

    options.binder.scroll(scrollHandler);

    scrollHandler();

    return returnedOptions;

}

使用窗口作为滚动条的1个示例

使用Feed作为滚动条的2个示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接