在AngularJS中过滤具有无限滚动的页面

5

我在我的AngularJS+Node.js应用程序中实现了无限滚动功能。

它基于这个JSfiddle,工作方式相同:http://jsfiddle.net/vojtajina/U7Bz9/ HTML:

<div id="fixed" when-scrolled="loadMore()">
  <ul>
   <li ng-repeat="i in items">{{i.id}}</li>
  </ul>  
</div>​

Javascript:

function Main($scope) {
  $scope.items = [];

  var counter = 0;
   $scope.loadMore = function() {
     for (var i = 0; i < 5; i++) {
        $scope.items.push({id: counter});
        counter += 10;
     }
   };

  $scope.loadMore();
}

angular.module('scroll', []).directive('whenScrolled', function() {
  return function(scope, elm, attr) {
    var raw = elm[0];

    elm.bind('scroll', function() {
        if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
            scope.$apply(attr.whenScrolled);
        }
    });
  };
});

我实现无限滚动的原因是为了节省用户的带宽,不会加载所有1000个结果及其相应的图像,除非用户想查看所有内容。
然而,当使用AngularJS过滤器在结果中搜索时,我遇到了问题,因为并非所有结果都在那里(除非用户滚动到底部),所以搜索只会返回一部分所需的结果。
我随后去掉了无限滚动功能,以便让搜索功能正常工作,但这在Chrome上出现了新问题(在Firefox上没有),当我打开页面时,浏览器开始从顶部加载图像。如果我通过搜索以“z”开头的内容(在结果的最底部)来筛选结果,Firefox会切换焦点并首先加载以“z”开头的结果(因为它们是唯一被显示的结果)。然而,Chrome继续按列表顺序加载,因此用户只能在应用程序中的所有图像加载完成后才能看到他们搜索的结果("z")。
我正在寻找一种方法,使Angular同时提供无限滚动和正确的搜索结果过滤器。如果这不可能,则需要一种方法让Chrome先加载可见的图像。
我目前正在尝试使用一堆不同的范围内数组进行一些奇怪的操作,但到目前为止我还没有成功。

使用案例的另一个示例是在AngularJS教程中。如果此页面有100万个结果,图像具有高分辨率,并且用户搜索ZZZOOM Phone 5000,则我如何确保Chrome在加载其他手机的所有图像之前加载ZZZOOM PHone 5000的图像。(IE,Firefox和Safari已经自动完成的方式。) - Rick Kleinhans
2个回答

8

由于有几个人遇到了类似的问题,而我自己也在挣扎,所以我花时间创建了一个可行的代码片段(适用于我的情况)。

https://jsfiddle.net/lisapfisterer/Lu4sbxps/

主要思路是使用无限滚动的函数调用动态扩展limitTo值

<div infinite-scroll="loadMore()" infinite-scroll-distance="20">
    <tr data-ng-repeat="logEvent in logEventFilter = (logEvents | filter:searchTerm | limitTo:numberToDisplay) track by $index">
        <td> {{$index}} </td>
        <td> {{logEvent.name}} </td>
        <td> {{numberToDisplay}} </td>
    </tr>
</div>

loadMore只是增加了限制。

$scope.loadMore = function() {
    if ($scope.numberToDisplay + 5 < $scope.logEvents.length) {
        $scope.numberToDisplay += 5;
    } else {
        $scope.numberToDisplay = $scope.logEvents.length;
    }
};

这对我确实有所帮助,但只是部分地。因为我只有在“deviceReady”被触发时才加载“logEvents”,所以我不能在此之前执行它。我的问题是当代码被执行时,$scope.logEvents是未定义的。我尝试将“loadMore”作用域函数放在“deviceReady”内部,但它不起作用。有什么想法吗?谢谢。 - Mariano Argañaraz
现在我已经测试了一段时间,发现loadMore()不应该在那个时候触发,它只有在滚动时才会触发,这就是我的问题,也许我正在错误地给infinite-scroll="loadMore()"标记错误的HTML标签。 - Mariano Argañaraz
1
请检查您是否正在使用最新版本的infinite-scroll.js v1.2.2 (https://cdnjs.cloudflare.com/ajax/libs/ngInfiniteScroll/1.2.2/ng-infinite-scroll.js)。该网站仅链接v1.0.0,但新版本修复了一些问题。此外,请将“if ($scope.logEvents) { ... }”添加到您的函数中,以便仅在列表填充时执行。 - lisa p.
实际上,我发现cdnjs中的那个也过时了,我从github(https://raw.githubusercontent.com/sroze/ngInfiniteScroll/master/build/ng-infinite-scroll.min.js)获取了一个并将进行测试。 关于需要在设备准备好后声明loadMore()的问题,我通过在具有infinite-scroll="loadMore()"的标记中添加ng-if="!isLoading"来修复它,这使得html在我获取数据后加载...但我仍然认为loadMore()是在列表的DOM呈现之前触发的,因为它在开始时只触发一次 :/ - Mariano Argañaraz

1

你想做的并不是“不可能”的事情,但肯定会有一些复杂度。

  • 让你的服务器执行所有的“过滤”操作,以确保返回的分页值是符合筛选条件的正确值。
  • 当服务器返回结果时,将所有HTML呈现到屏幕上,除了图像标签的src属性。这样就不会加载任何图像。
  • 滚动到正确的“页面”。
  • 确保在图像加载之前的所有高度都相同,然后进行一些JS魔法来确定哪些是可见的。
  • 仅设置可见图像的src属性,订阅它们的“load”事件并创建一个完成所有加载的$q promise。
  • 在该promise完成后,设置其余图像的src属性,以便加载其余图像。

2
感谢您的帖子。最终解决方案非常简单,我只需要改变无限滚动的方式即可。我不是在作用域中推送到缩短的数组,而是在过滤器中执行。该过滤器以完整数组作为其参数,并且看起来像这样 - searchFilter:text:count该过滤器基于计数限制返回数组的长度,每次滚动到页面底部时计数都会增加。我稍后会发布一个工作的JSFiddle,以便其他人可以看到它。 - Rick Kleinhans
12
碰一下... RickKleinhans那把小提琴在哪里?嘿嘿 :) - jribeiro

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