长数组列表渲染使 Angular.js 中的页面滚动变慢

Posted

技术标签:

【中文标题】长数组列表渲染使 Angular.js 中的页面滚动变慢【英文标题】:Long array list rendering makes page scrolling slow in Angular.js 【发布时间】:2017-06-25 14:51:50 【问题描述】:

当尝试从一个数组(带有图像)呈现超过 120 个项目时,列表的滚动会变慢。基本上,当我在无限滚动中加载新数据时,我将旧数组数据与新数组数据连接起来。

另一方面,像 dribbble、behance 这样的流行网站似乎没有这个问题。也许这个问题是 Angular.js 特有的?有人在他们的项目中遇到过这个问题吗?

【问题讨论】:

这里要了解的要点是您是从服务器还是本地加载数据?如果它在本地,您可以使用 limitTo 过滤而不是连接 也许看看像ngInfiniteScroll 这样的指令来逐步加载您需要的项目,而不是一次全部加载 当我使用ng-repeat 但没有track by 渲染一个庞大的数组时,我遇到了这种情况。看看你是否错过了 如果您正在寻找提高性能的技巧,这是我之前发布的一篇文章,其中讨论了您可以尝试的一些事情:***.com/a/38349146/841804 ng-repeat 很棒,但是当 Array 有超过 20-30 个元素时,它会变得非常缓慢。我在某处读到是因为在每次更新中重新渲染所有项目。您可以尝试使用一次性绑定,但它只提供一点帮助。当我们构建 Chat App 而不是 Angular 的 ng-repeat 时,我们必须使用纯 JS 来列出消息。 【参考方案1】:

ANGULARJS 中的无限滚动

不需要任何额外的插件。

app = angular.module("demo", []);

app.controller("MainController", function($scope, $http)
  
  // the array which represents the list
  $scope.items = ["1. Scroll the list to load more"];
  $scope.loading = true;
  
  // this function fetches a random text and adds it to array
  $scope.more = function()
    $http(
      method: "GET",
      url: "https://baconipsum.com/api/?type=all-meat&paras=2&start-with-lorem=1"
    ).success(function(data, status, header, config)
      
      // returned data contains an array of 2 sentences
      for(line in data)
        newItem = ($scope.items.length+1)+". "+data[line];
        $scope.items.push(newItem);
      
      $scope.loading = false;
    );
  ;
  
  // we call the function twice to populate the list
  $scope.more();
);

// we create a simple directive to modify behavior of <ul>
app.directive("whenScrolled", function()
  return
    
    restrict: 'A',
    link: function(scope, elem, attrs)
    
      // we get a list of elements of size 1 and need the first element
      raw = elem[0];
    
      // we load more elements when scrolled past a limit
      elem.bind("scroll", function()
        if(raw.scrollTop+raw.offsetHeight+5 >= raw.scrollHeight)
          scope.loading = true;
          
        // we can give any function which loads more elements into the list
          scope.$apply(attrs.whenScrolled);
        
      );
    
  
);
li
  display:block;
  list-style-type:none;
  margin-bottom: 1em;


ul
  height:250px;
  background: #44E394;
  color: #fff;
  overflow:auto;
  width:550px;
  border-radius: 5px;
  margin:0 auto;
  padding: 0.5em;
  border: 1px dashed #11BD6D;
  &::-webkit-scrollbar
    width:8px;
    background-color:transparent;
  ;
  &::-webkit-scrollbar-thumb
    background-color:#b0fccd;
    border-radius:10px;
  
  &::-moz-scrollbar
    width:8px;
    background-color:transparent;
  ;
  &::-moz-scrollbar-thumb
    background-color:#b0fccd;
    border-radius:10px;
  
  &::-ms-scrollbar
    width:8px;
    background-color:transparent;
  ;
  &::-ms-scrollbar-thumb
    background-color:#b0fccd;
    border-radius:10px;
  


body
  text-align:center;
  font-size:1.2em;
  font-family: "Helvetica";
  color: #44E394;
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAG0lEQVQIW2P88OHDfwY0wAgSFBAQYEQWp1AQAKUbE9XRpv7GAAAAAElFTkSuQmCC) repeat;
  padding: 2em;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app='demo'>
  <div data-ng-controller='MainController'>
    <ul class='hello' when-scrolled='more()'>
      <li data-ng-repeat='item in items'>
        item
      </li>
    </ul>
    <div data-ng-show='loading'>Loading</div>
  </div>
</div>
<h1>INFINITE SCROLLING IN ANGULARJS</h1>

【讨论】:

这应该是答案!鉴于指令实施略有变化但很好的答案,解决滚动列表问题的更好方法。【参考方案2】:

ngInfiniteScroll只是一个指令,可以用来实现无限滚动,不会影响这个问题。

以下是一些加快应用程序速度的提示

尽可能避免在重复部分使用观察者

使用一次性绑定:::model 使用ng-* 减少:所有这些都添加了$watch。 使用$watchCollection$watch 减少 使用 ng-if 而不是 ng-show :它会删除 dom 并销毁其中的观察者。 使用track by:对于大型集合,这会显着提高渲染性能。

在串联中:

你可以看到your problem in plunker 和下一个命令

    [].push.apply($scope.list,getNewList());

优于

    $scope.list=$scope.list.concat(getNewList());

但是以上所有提示都可以让用户在列表中拥有更多项目,但是当列表中的项目数量超过(比如说 1000)时,滚动会再次变慢

对于这个问题,我们可以使用 Angular Material md-virtual-repeat,它只是按需加载可见项目,就像我在 your problem with virtual repeat 中使用的那样。

【讨论】:

【参考方案3】:

我认为您应该考虑优化您的应用程序,而不仅仅是选择更好的指令或插件,太多的作用域也会降低应用程序的速度。

【讨论】:

以上是关于长数组列表渲染使 Angular.js 中的页面滚动变慢的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序开发——列表渲染 & 条件渲染 & tabBar & 页面跳转

微信小程序--渲染页面(列表渲染,条件渲染)

从另一个页面添加数据库(couchbase)中的项目后,如何从 angular.js 中的页面更新列表?

用纯js在网页中渲染一个列表,列表中的数据用js定义一个数组,存储在数组中,至少要有两个字段

小程序长列表渲染优化另一种解决方案

Angular.js:使变量在页面重新加载后存活