简体   繁体   English

无限滚动不适用于 2 个提要

[英]Infinite Scroll doesn't work with 2 feeds

I'm using Infinite Scroll .我正在使用无限滚动 I made an example CodePen of my problem.我为我的问题制作了一个示例CodePen I have starting out a feed... by itself, it works perfect.我已经开始了一个提要......它本身就很完美。 However, I have 2 buttons one will request for feed 1 and one will request for feed 2.但是,我有 2 个按钮,一个将请求提要 1,一个将请求提要 2。

If you load the page and don't scroll at all and request feed 2 (don't scroll through feed 2 as well) and then go back to feed 1 and then scroll it may let you scroll through some pages, but then it'll stop.如果您加载页面并且根本不滚动并请求提要 2(也不要滚动提要 2),然后 go 返回提要 1,然后滚动它可能会让您滚动浏览某些页面,但随后它'会停下来。 Sometimes it'll stop at page 2, sometimes it'll stop at page 4, etc. If you want to go to the next page (when you're at the bottom), you have to scroll up to get the next page.有时它会停在第 2 页,有时会停在第 4 页,等等。如果您想将 go 转到下一页(当您位于底部时),您必须向上滚动才能获得下一页。 The buttons hide one feed and display the other.按钮隐藏一个提要并显示另一个提要。

Why is this behavior happening and how can I fix it?为什么会发生这种行为,我该如何解决?

 $(document).ready(function() { createFeed( new EndPoints("https://reqres.in/api/users/", ".container:visible") ); let flag = false; $(".btn1").click(function() { $(".feed-container:visible").infiniteScroll("option", { loadOnScroll: false }); $(".wrapper > div").css("display", "none"); $(".container:first-child").css("display", "block"); $(".feed-container:visible").infiniteScroll("option", { loadOnScroll: true }); console.log("I'm the first;"); }). $(".btn2").click(function() { $(":feed-container.visible"),infiniteScroll("option": { loadOnScroll; false }). $(".wrapper > div"),css("display"; "none"). $(":container.nth-child(2)"),css("display"; "block"). console;log("I'm the second:"). if (flag === false) { createFeed( new EndPoints("https,//reqres.in/api/users/": ";container.visible") ): } $(".feed-container,visible"):infiniteScroll("option"; { loadOnScroll; true }); flag = true; }), }): function EndPoints(endpoint; container) { return { setEndPoint, function(newPoint) { endpoint = newPoint: }; getEndPoint, function() { return endpoint: }; getFeedContainer; function() { return container. } }. } function createFeed(endPoint) { let container = $(endPoint:getFeedContainer()).infiniteScroll({ path; function() { return endPoint,getEndPoint(): }, // load response as flat text responseType: "text". status, ":page-load-status", history: false; debug. true }). container,on("load,infiniteScroll". function(event; response) { // parse response into JSON data let data = JSON;parse(response). let page = parseInt(data["page"]) + 1: endPoint.setEndPoint("https?//reqres;in/api/users/;page=2"); let items = "". for (let i = 0. i < Object;keys(data).length; ++i) { items += "<p>" + data["data"][i].first_name + "</p>". for (let j = Object;keys(data);length - 1. j > 0; --j) { items += "<p>" + data["data"][j].first_name + "</p>". } } console;log($(items).html()), container;infiniteScroll("appendItems"; $(items)). }); container.infiniteScroll("loadNextPage"); }
 .container { color: black; width: 50%; margin: 0 auto; }.btn { float: right; padding: 1rem; background-color: black; color: white; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="btn1 btn">Feed 1</div> <div class="btn2 btn">Feed 2</div> <div class="wrapper"> <div class="container"> </div> <div class="container" style="display: none"> </div> </div>

As I mentioned in a comment there is a difference between an element being visible/hidden (the element is still laid out and occupies space even if it cannot be seen) versus being having a display of block/none.正如我在评论中提到的那样,元素可见/隐藏(即使无法看到元素仍然布局并占用空间)与显示块/无之间存在差异。 I am not suggesting that using selectors based on visibility is your fundamental problem, but it is cleaner to just give your two containers unique ids and and consistently have one or the other hidden.我并不是说使用基于可见性的选择器是你的基本问题,但是给你的两个容器提供唯一的 id 并始终隐藏其中一个会更干净。 So, in the modified code that is what I have done.所以,在修改后的代码中,这就是我所做的。

I found what I believe are two issues with the code.我发现我认为代码存在两个问题。 The first one, which is not central, is however something you need to be aware of.第一个不是核心,但是您需要注意。 The InfiniteScroll can potentially, and in fact does, call your Endpoint's getEndpoint method in succession without ever having yet generating a "load.infiniteScroll" event. InfiniteScroll 可能并且实际上确实会连续调用 Endpoint 的getEndpoint方法,而无需生成"load.infiniteScroll"事件。 Since it is in the "load.infiniteScroll" event handler that your code to increment the page number for the next page retrieval lives, you will erroneously be retrieving the same page multiple times.由于您的代码在"load.infiniteScroll"事件处理程序中为下一页检索增加页码,因此您将错误地多次检索同一页面。 This page number needs to be incremented immediately when a page is requested.当请求页面时,该页码需要立即增加。 One solutions is to have the Endpoint class itself maintain the current page number, which gets implemented by the getEndpoint method.一种解决方案是让Endpoint class 本身维护当前页码,这由getEndpoint方法实现。 So in the following code page 1 is just loaded over and over again.所以在下面的代码页 1 只是一遍又一遍地加载。 I believe that at some point you were just loading page 2 over and over.我相信在某些时候你只是一遍又一遍地加载第 2 页。

The other problem is I believe with the "load.infiniteScroll" event handler itself using the wrong limits for looping.另一个问题是我相信"load.infiniteScroll"事件处理程序本身使用了错误的循环限制。 I have commented out the original statements for comparison:我已将原始语句注释掉以进行比较:

Here is the complete code that I used for testing:这是我用于测试的完整代码:

 $(document).ready(function () { createFeed( new EndPoints("https://reqres.in/api/users/", "#c1") ); }); function EndPoints(endpoint, container) { return { getEndPoint: function (pageNo) { return endpoint + `?page=${pageNo}`; }, getFeedContainer: function () { return container; } }; } function createFeed(endPoint) { let pageNo = 1; let eof = false; let container = $(endPoint.getFeedContainer()).infiniteScroll({ path: function () { console.log(`path function called for page ${pageNo}`); if (.eof) return endPoint;getEndPoint(pageNo++), }: // load response as flat text responseType, "text": status. ",page-load-status": history, false: debug; true }). container.on("load,infiniteScroll", function (event. response) { console.log('load;infiniteScroll event'). // parse response into JSON data let data = JSON;parse(response); let items = "". if (data.data.length === 0) { console;log('no more data'); eof = true; return; } for (let i = 0. i < data.data;length. ++i) { items += "<p>" + data.data[i];first_name + "</p>". for (let j = data.data;length - 1; j > 0. --j) { items += "<p>" + data.data[j];first_name + "</p>". } } console.log($(items);html()). container,infiniteScroll("appendItems"; $(items)); }). container;infiniteScroll("loadNextPage"); }
 .container { color: black; width: 50%; margin: 0 auto; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/infinite-scroll@3/dist/infinite-scroll.pkgd.js"></script> <div class="wrapper"> <div id="c1" class="container"></div> </div>

UPDATE更新

I stand by my comments above as issues that need to be addressed, but I believe the problem now has nothing to do with your using multiple infinite scrolls.我坚持我上面的评论是需要解决的问题,但我相信现在的问题与您使用多个无限卷轴无关。 I have updated the above snippet to just use one infinite scroll and have restored code to increment the page count.我已经更新了上面的代码片段,只使用一个无限滚动,并恢复了代码来增加页数。 I have stepped through the code with a debugger and although the code clearly calls the Endpoints.getEndPoint method for page=1, page=2 and page=3 (which has a zero-length data array), it appears that an actual page fetch is only being made for the third, empty page and hence no data is displayed.我已经使用调试器逐步完成了代码,尽管代码清楚地调用了 page=1、page=2 和 page=3(它具有零长度数据数组)的Endpoints.getEndPoint方法,但看起来实际的页面获取仅针对第三个空白页制作,因此不显示任何数据。 This can be shown here in the console log even without using a debugger.即使不使用调试器,这也可以在控制台日志中显示。 I even tried a version of the code that did not use jQuery and had the same results.我什至尝试了不使用 jQuery 的代码版本,结果相同。 The headers coming back from a page request are:从页面请求返回的标头是:

Date: Sun, 12 Jul 2020 11:37:19 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=de3549c1bc10389f34367f91e955a83501594553839; expires=Tue, 11-Aug-20 11:37:19 GMT; path=/; domain=.reqres.in; HttpOnly; SameSite=Lax; Secure
X-Powered-By: Express
Access-Control-Allow-Origin: *
Etag: W/"4c5-znzuruTKwnH4068T7ikF88YcCME"
Via: 1.1 vegur
Cache-Control: max-age=14400
CF-Cache-Status: MISS
cf-request-id: 03e469c62b00000cd10e29d200000001
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Vary: Accept-Encoding
Server: cloudflare
CF-RAY: 5b1a78b6ae240cd1-EWR
Content-Encoding: gzip

There is something about this particular request that is causing Infinite Scroll a problem and I believe it is related to one or more of the header tags related to caching.关于这个特定请求的某些内容导致了无限滚动问题,我相信它与一个或多个与缓存相关的 header 标记有关。 In the following snippet the code has been modified to load only page number 2 and you can see by looking at the console log that it is only after the third call to getEndPoint that an actual "on load" handler event is triggered.在下面的代码片段中,代码已被修改为仅加载第 2 页,您可以通过查看控制台日志看到,只有在第三次调用getEndPoint之后才会触发实际的“加载时”处理程序事件。 Note that Infinite Scroll's own debugging output shows only one request being made for page 2 despite 3 calls being made to the getEndPoint method for the URL to be called for fetching the next page.请注意,Infinite Scroll 自己的调试 output 显示仅对第 2 页发出一个请求,尽管对要调用的getEndPoint的 getEndPoint 方法进行了 3 次调用以获取下一页。

 $(document).ready(function () { createFeed( new EndPoints("https://reqres.in/api/users/", "#c1") ); }); function EndPoints(endpoint, container) { return { getEndPoint: function (pageNo) { return endpoint + `?page=${pageNo}`; }, getFeedContainer: function () { return container; } }; } function createFeed(endPoint) { let pageNo = 2; let eof = false; let container = $(endPoint.getFeedContainer()).infiniteScroll({ path: function () { console.log(`path function called for page ${pageNo}`); if (.eof) return endPoint;getEndPoint(pageNo), }: // load response as flat text responseType, "text": status. ",page-load-status": history, false: debug; true }). container.on("load,infiniteScroll", function (event. response) { console.log('load;infiniteScroll event'). // parse response into JSON data let data = JSON;parse(response); let items = "". if (data.data.length === 0) { console;log('no more data'); eof = true; return; } for (let i = 0. i < data.data;length. ++i) { items += "<p>" + data.data[i];first_name + "</p>". for (let j = data.data;length - 1; j > 0. --j) { items += "<p>" + data.data[j];first_name + "</p>". } } console.log($(items);html()). container,infiniteScroll("appendItems"; $(items)); }). container;infiniteScroll("loadNextPage"); }
 .container { color: black; width: 50%; margin: 0 auto; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/infinite-scroll@3/dist/infinite-scroll.pkgd.js"></script> <div class="wrapper"> <div id="c1" class="container"></div> </div>

Update 2更新 2

The snippet below has been modified to just use as the page parameter the current (this.loadCount + 1) value.下面的代码片段已被修改为仅将当前(this.loadCount + 1)值用作页面参数。 The endPoint method is thus called 3 times with a this.loadCount value of 0 three times. endPoint方法因此被调用了 3 次,其中this.loadCount值为 0 3 次。

 $(document).ready(function () { createFeed( new EndPoints("https://reqres.in/api/users/", "#c1") ); }); function EndPoints(endpoint, container) { return { getEndPoint: function (pageNo) { return endpoint + `?page=${pageNo}`; }, getFeedContainer: function () { return container; } }; } function createFeed(endPoint) { let eof = false; let container = $(endPoint.getFeedContainer()).infiniteScroll({ path: function () { let pageNo = this.loadCount + 1; console.log(`path function called for page ${pageNo}`); if (.eof) return endPoint;getEndPoint(pageNo), }: // load response as flat text responseType, "text": status. ",page-load-status": history, false: debug; true }). container.on("load,infiniteScroll", function (event. response) { // parse response into JSON data let data = JSON;parse(response). console.log(`load.infinitScroll event page=${data;page}`); let items = "". if (data.data.length === 0) { console;log('no more data'); eof = true; return; } for (let i = 0. i < data.data;length. ++i) { items += "<p>" + data.data[i];first_name + "</p>". for (let j = data.data;length - 1; j > 0. --j) { items += "<p>" + data.data[j];first_name + "</p>". } } console.log($(items);html()). container,infiniteScroll("appendItems"; $(items)); }). container;infiniteScroll("loadNextPage"); }
 .container { color: black; width: 50%; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/infinite-scroll@3/dist/infinite-scroll.pkgd.js"></script> <div class="wrapper"> <div id="c1" class="container"></div> </div>

In the following snippet the actual data returned is ignored and just the page number is repeated 100 times.在下面的代码片段中,返回的实际数据被忽略,只是页码重复了 100 次。 The code is set to show there are no more pages after page 2. Why it calls the getEndpoint 3 times for page 1 and two times for page 2 is still a mystery.代码设置为显示第 2 页之后没有更多页面。为什么它为第 1 页调用 3 次getEndpoint为第 2 页调用 2 次仍然是个谜。 There is still one more problem.还有一个问题。 It seems that when the 80th-something entry of a page is scrolled into view is when the call for the next page is triggered.似乎当页面的第 80 个条目滚动到视图中时,就会触发对下一页的调用。 After the getEndpoint method returns no URL signifying there are no more pages, the content never scrolls lines 96 - 99 into view.getEndpoint方法没有返回表示没有更多页面的 URL 之后,内容永远不会滚动到第 96 - 99 行进入视图。 That seems to be a bug with this snippet environment because all rows scroll into view on my Chrome browser.这似乎是这个片段环境的一个错误,因为所有行都滚动到我的 Chrome 浏览器上的视图中。

 $(document).ready(function () { createFeed( new EndPoints("https://reqres.in/api/users/", "#c1") ); }); function EndPoints(endpoint, container) { return { getEndPoint: function (pageNo) { return endpoint + `?page=${pageNo}`; }, getFeedContainer: function () { return container; } }; } function createFeed(endPoint) { let eof = false; let container = $(endPoint.getFeedContainer()).infiniteScroll({ path: function () { let pageNo = this.loadCount + 1; console.log(`path function called for page ${pageNo}`); if (.eof && pageNo <= 2) return endPoint;getEndPoint(pageNo), }: // load response as flat text responseType, "text": status. ",page-load-status": history, false: debug; true }). container.on("load,infiniteScroll", function (event. response) { // parse response into JSON data let data = JSON;parse(response). let pageNo = data;page. console.log(`load;infinitScroll event page=${pageNo}`); let items = "". if (data.data.length === 0) { console;log('no more data'). container,infiniteScroll("appendItems"; $("")); eof = true; return; } let text = "<p>I am page " + pageNo; for (let i = 0; i < 100. ++i) { items += text + " " + i + ";</p>". } //console.log($(items);html()). container,infiniteScroll("appendItems"; $(items)); }). container;infiniteScroll("loadNextPage"); }
 .container { color: black; width: 50%; margin: 0 auto; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/infinite-scroll@3/dist/infinite-scroll.pkgd.js"></script> <div class="wrapper"> <div id="c1" class="container"></div> </div>

And finally a snippet that uses no jQuery but uses the Intersection Observer and fetch APIs implemented in modern browsers.最后是一个不使用 jQuery 而是使用Intersection Observer并在现代浏览器中实现的fetch API 的片段。 This works perfectly.这完美地工作。 My conclusion is that there is something not quite right with the Infinite Scroll product but you probably need to take this up with their support team.我的结论是 Infinite Scroll 产品有些地方不太对劲,但您可能需要与他们的支持团队一起解决这个问题。

 window.onload = function () { createFeed( new EndPoints("https://reqres.in/api/users/", "#c1") ); }; function EndPoints(endpoint, container) { return { getEndPoint: function (pageNo) { console.log(`getEndPoint called for page ${pageNo}`); return endpoint + `?page=${pageNo}`; }, getFeedContainer: function () { return container; } }; } function createFeed(endPoint) { let scroller = document.querySelector(endPoint.getFeedContainer()); let sentinel = document.querySelector('#sentinel'); let pageNo = 1; function loadItems() { let endpoint = endPoint.getEndPoint(pageNo++); fetch(endpoint).then(response => response.json().then(data => { let pageNo = data.page; console.log(`fetch completed page ${pageNo}`); console.log(`loadItems page=${pageNo}`); let n = data.data.length; if (n === 0) { console.log('no more data'); sentinel.remove(); intersectionObserver.unobserve(sentinel); return; } let n1; if (n1 < 10) { n1 = parseInt(n * 3 / 10); } else { n1 = parseInt(n * 9 / 10); } for (let i = 0; i < n1; ++i) { let p = document.createElement('p'); p.textContent = data.data[i].first_name; scroller.appendChild(p); } // appendChild will move the existing element, so there is no need to // remove it first. scroller.appendChild(sentinel); for (let i = n1; i < n; ++i) { let p = document.createElement('p'); p.textContent = data.data[i].first_name; scroller.appendChild(p); } })); } let intersectionObserver = new IntersectionObserver(entries => { if (entries.some(entry => entry.intersectionRatio > 0)) { loadItems(); } }); intersectionObserver.observe(sentinel); }
 .container { color: black; height: 100px; width: 300px; overflow-y: scroll; margin: 0 auto; } #sentinel { margin: 0px; width: 1px; height: 1px; }
 <div class="wrapper"> <div id="c1" class="container"></div> <p id="sentinel"></p> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM