无限滚动不适用于2个提要 [英] Infinite Scroll doesn't work with 2 feeds

查看:77
本文介绍了无限滚动不适用于2个提要的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用无限滚动.我举例说明了我的问题 CodePen .我已经开始制作一个供稿...就其本身而言,它的工作原理非常完美.但是,我有2个按钮,一个将请求提要1,一个将请求提要2.

I'm using Infinite Scroll. I made an example CodePen of my problem. 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(也不要滚动浏览提要2),然后返回到提要1,然后再滚动它,可能会使您滚动某些页面,但是然后它会停止.有时它会停在第2页,有时会停在第4页,依此类推. 如果要转到下一页(位于底部),则必须向上滚动以获取下一页.这些按钮可隐藏一个供稿,并显示另一个供稿.

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. 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. 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>

推荐答案

正如我在评论中所提到的,可见/隐藏元素之间存在区别(该元素仍然布局并且即使看不见也占用空间) )而不是显示阻止/无显示.我不建议您使用基于可见性的选择器是您的根本问题,但是只给两个容器提供唯一的ID并始终隐藏一个或另一个是比较干净的方法.因此,在修改后的代码中,这就是我所做的.

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. So, in the modified code that is what I have done.

我发现我认为代码有两个问题.但是,第一个(不是中心的)是您需要注意的. InfiniteScroll可以并且实际上确实可以连续调用Endpoint的getEndpoint方法,而无需生成"load.infiniteScroll"事件.由于在"load.infiniteScroll"事件处理程序中,用于增加下一页检索的页码的代码有效,因此您将错误地多次检索同一页.请求页面时,此页面编号需要立即增加.一种解决方案是让Endpoint类本身维护当前的页码,该页码由getEndpoint方法实现.因此,在下面的代码页1中,将一遍又一遍地加载.我相信在某个时候,您只是一遍又一遍地加载第2页.

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. 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. 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. So in the following code page 1 is just loaded over and over again. I believe that at some point you were just loading page 2 over and over.

另一个问题是我相信"load.infiniteScroll"事件处理程序本身使用了错误的循环限制.我已注释掉原始语句以供比较:

The other problem is I believe with the "load.infiniteScroll" event handler itself using the wrong limits for looping. 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>

更新

对于需要解决的问题,我坚持我的意见,但我认为问题现在与您使用多个无限滚动无关.我已将上面的代码段更新为仅使用一个无限滚动,并恢复了代码以增加页数.我已经使用调试器逐步执行了代码,尽管代码清楚地为page = 1,page = 2和page = 3(具有零长度的数据数组)调用了Endpoints.getEndPoint方法,但似乎是实际的页面提取仅在第三个空白页上创建,因此不会显示任何数据.即使不使用调试器,也可以在控制台日志中显示此内容.我什至尝试了一个不使用jQuery并具有相同结果的代码版本.页面请求返回的标题是:

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. 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. 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

有关此特定请求的某些问题导致无限滚动"问题,我认为这与一个或多个与缓存相关的标头标签有关.在以下代码段中,代码已被修改为仅加载第2页,并且您可以通过查看控制台日志来看到,只有在第三次调用getEndPoint之后,才实际加载加载".处理程序事件被触发.请注意,尽管对getEndPoint方法进行了3次调用,以调用URL来获取下一页,但Infinite Scroll自己的调试输出仅显示对第2页的一个请求.

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. 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. 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.

$(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>

更新2

下面的代码段已被修改为仅将当前(this.loadCount + 1)值用作页面参数.因此,将endPoint方法调用3次,将this.loadCount值设置为0的3次.

The snippet below has been modified to just use as the page parameter the current (this.loadCount + 1) value. The endPoint method is thus called 3 times with a this.loadCount value of 0 three times.

$(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>

在以下代码段中,返回的实际数据将被忽略,仅页面号会重复100次.代码设置为显示在第2页之后没有更多的页面.为什么它对第1页调用getEndpoint 3次,对第2页调用两次getEndpoint仍然是一个谜.还有一个问题.看来,当页面的第80层条目滚动到视图中时,就是触发了下一页的调用.在getEndpoint方法没有返回表示没有更多页面的URL之后,内容将永远不会在视图中滚动第96-99行.在此摘要环境中,这似乎是一个错误,因为所有行都在我的Chrome浏览器中滚动到视图中.

In the following snippet the actual data returned is ignored and just the page number is repeated 100 times. 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. 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. After the getEndpoint method returns no URL signifying there are no more pages, the content never scrolls lines 96 - 99 into view. That seems to be a bug with this snippet environment because all rows scroll into view on my Chrome browser.

$(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>

最后是不使用jQuery但使用在现代浏览器中实现的Intersection Observerfetch API的代码段.这完美地工作.我的结论是Infinite Scroll产品有些不对劲,但您可能需要与他们的支持团队接洽.

And finally a snippet that uses no jQuery but uses the Intersection Observer and fetch APIs implemented in modern browsers. 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.

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>

这篇关于无限滚动不适用于2个提要的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆