正如我在评论中提到的,元素可见/隐藏(即使看不见,元素仍然布局并占用空间)与显示块/无之间存在区别。我并不是说使用基于可见性的选择器是你的根本问题,但给你的两个容器提供唯一的id并始终隐藏其中一个会更干净。所以,在修改后的代码中,这就是我所做的。
我发现我认为代码有两个问题。然而,第一个不是核心,是你需要注意的事情。InfiniteScoll可能会,事实上确实会,调用您的端点
getEndpoint
方法连续进行,但从未生成
"load.infiniteScroll"
活动。因为它在
“加载无限滚动”
事件处理程序指示您的代码在下次页面检索时递增页码,您将错误地多次检索同一页面。当请求页面时,此页码需要立即递增。一个解决方案是
Endpoint
类本身维护当前页码,该页码由
getEndpoint
方法。因此,在下面的代码页1中,只是一遍又一遍地加载。我相信在某个时候,你只是一遍又一遍地加载第2页。
另一个问题是,我相信
“加载无限滚动”
事件处理程序本身使用了错误的循环限制。我已对原始陈述进行了评论以供比较:
以下是我用于测试的完整代码:
$(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>
更新
我坚持我上面的评论,认为这是需要解决的问题,但我相信现在的问题与你使用多个无限卷轴无关。我已经更新了上面的代码片段,只使用了一个无限滚动,并恢复了代码来增加页面数量。我已经用调试器逐步完成了代码,尽管代码清楚地调用了
Endpoints.getEndPoint
对于page=1、page=2和page=3(具有零长度数据数组)的方法,似乎只对第三个空页面进行了实际的页面提取,因此没有显示任何数据。即使不使用调试器,这也可以在控制台日志中显示。我甚至尝试了一个不使用jQuery的代码版本,并得到了相同的结果。从页面请求返回的标头是:
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
这个特定的请求导致了Infinite Scroll的问题,我认为这与缓存相关的一个或多个标头标签有关。在下面的代码片段中,代码已被修改为仅加载第2页,通过查看控制台日志可以看到,它仅在第三次调用后才加载
getEndPoint
触发实际的“加载”处理程序事件。请注意,尽管对页面2进行了3次调用,但Infinite Scroll自己的调试输出仅显示了对页面2的一次请求
getEndPoint
用于调用URL以获取下一页的方法。
$(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");
}
.集装箱{
颜色:黑色;
宽度:50%;
边距:0自动;
}
<脚本src=“https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js“></script>
<脚本src=“https://unpkg.com/infinite-scroll@3/dist/无限滚动.pkgd.js“></script>
<div class=“包装器”>
<div id=“c1”class=“容器”></div>
</div>
更新2
下面的代码段已被修改为仅使用当前
(this.loadCount + 1)
价值。这个
endPoint
因此,方法被调用3次
this.loadCount
值0三次。
$(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%;
}
<脚本src=“https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js“></script>
<脚本src=“https://unpkg.com/infinite-scroll@3/dist/无限滚动.pkgd.js“></script>
<div class=“包装器”>
<div id=“c1”class=“容器”></div>
</div>
在下面的代码片段中,实际返回的数据被忽略,只有页码被重复100次。代码设置为显示第2页之后没有更多页面。为什么它叫
getEndpoint
第1页3次,第2页2次仍然是个谜。还有一个问题。似乎当页面的第80个左右的条目滚动到视图中时,就会触发对下一页的调用。之后
getEndpoint
该方法不返回表示没有更多页面的URL,内容永远不会将第96-99行滚动到视图中。这似乎是这个代码段环境的一个错误,因为所有行都会在我的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");
}
.集装箱{
颜色:黑色;
宽度:50%;
边距:0自动;
}
<脚本src=“https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js“></script>
<脚本src=“https://unpkg.com/infinite-scroll@3/dist/无限滚动.pkgd.js“></script>
<div class=“包装器”>
<div id=“c1”class=“容器”></div>
</div>
最后是一个不使用jQuery但使用
Intersection Observer
和
fetch
在中实现的API
现代的
浏览器。这工作得很好。我的结论是,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>