代码之家  ›  专栏  ›  技术社区  ›  user2896120

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

  •  0
  • user2896120  · 技术社区  · 4 年前

    我在用 Infinite Scroll 我举了个例子 CodePen 我的问题。我已经开始做饲料了。。。就其本身而言,它工作得很完美。但是,我有两个按钮,一个请求提要1,另一个请求feed 2。

    如果你加载页面时根本不滚动,并请求提要2(也不要滚动提要2),然后返回提要1,然后滚动,它可能会让你滚动浏览一些页面,但随后会停止。有时它会停在第2页,有时它会停止在第4页,以此类推。 如果你想转到下一页(当你在底部时),你必须向上滚动以获得下一页。按钮隐藏一个提要并显示另一个提要。

    为什么会发生这种行为,我该如何解决?

    $(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>
    0 回复  |  直到 4 年前
        1
  •  1
  •   Booboo    4 年前

    正如我在评论中提到的,元素可见/隐藏(即使看不见,元素仍然布局并占用空间)与显示块/无之间存在区别。我并不是说使用基于可见性的选择器是你的根本问题,但给你的两个容器提供唯一的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>