5

Mam powtarzanie ng, które ładuje tysiące rekordów z pewną złożonością, która może mieć wysokość między 100 a 1200 pikseli. Nie trzeba dodawać, że spektakl jest dość trafiony.AngularJS nieskończone przewijanie (ng-powtórzenie) - usuwanie najlepszych elementów z DOM

Infinite scrolling Moduł będzie działał dobrze w większości przypadków, dopóki nie trafisz na skrajną skrzynkę, w której przewinąłeś się do dołu i większość elementów została załadowana do DOM, co przywraca mnie do kwadratu.

Angular-vs-repeat byłby idealny do mojego przypadku, ale nie wiem, jak obliczyć wysokość każdego następnego elementu, ponieważ nie są one poprawione.

Co prowadzi mnie z powrotem do Nieskończonego przewijania. Zakładam, że jeśli górne elementy (nad rzutnią) zostałyby zastąpione pustym DIV z wyliczoną wysokością równą całkowitej sumie wysokości, wydajność nie byłaby problemem. Podczas przewijania do góry przywróci je do domu i odejmie pustą wysokość DIV.

Czy ktoś wcześniej to rozwiązał? Jakieś sugestie? Fragmenty kodu byłyby cudowne.

+1

Trudno Ci pomógł bez przykładu. Czy możesz odtworzyć przypadek symultaniczny za pośrednictwem codepen/...? –

+0

Sam patrzyłem na tę samą wirtualną technikę przewijania, ale nigdy tak naprawdę jej nie implementowałem, ponieważ byłoby to nadmierne inżynieria. Miałem też przedmioty o różnej wysokości, więc istniejące wtyczki musiałyby zostać zmienione. Gdybyśmy mieli wskazać, gdzie zostanie uderzona wydajność i będę musiał wdrożyć wirtualne przewijanie, z pewnością przyjrzę się bardzo dokładnie wspomnianej dyrektywie + prawdopodobnie wprowadzę dodatkowe funkcje, takie jak utrzymywanie 1,5 strony elementów na górze i na dole (ludzie mogą uderzyć w Dom i Koniec klucze) i bieżące elementy widoku. Pomiędzy nimi znajdowałyby się puste pojemniki manekinowe o regulowanej wysokości. –

+0

Strona sprawdzania kontra-powtórzyć demo, ma demonstrację z użyciem elementów o zmiennym rozmiarze http://kamilkp.github.io/angular-vs-repeat/#?tab=6 –

Odpowiedz

0

ng-repeat ma bardzo stromy spadek wydajności z długich list ze względu na obciążenie związane z jego powiązań. Jedną z najbardziej świadomych wydajności bibliotek, którą szczególnie lubię, jest ag-grid, która wygodnie ma an example ze zmiennymi wysokościami rzędów. Możesz zobaczyć, czy będzie to działać dla twoich celów.

Jeśli nic nie wydaje się pasować do twoich potrzeb, zawsze możesz rzucić własną dyrektywę i poradzić sobie z manipulacją DOM, tak jak fragment kodu, który zrzuciłem poniżej. Nie obejmuje wszystkiego, o czym wspomniałeś, ale zawiera nieskończone przewijanie i usuwa stare elementy, zastępując ich wysokość pustym <div>, bez użycia powtarzania ng.

angular.module('SuperList', []) 
 
    .controller('mainCtrl', ['$scope', '$compile', 
 
    function($scope, $compile) { 
 

 
     // Magic numbers 
 
     var itemsPerLoad = 4; 
 
     var thresholdPx = 1200; 
 
     var removeThresholdPx = 1600; 
 

 
     // Options to control your directive are cool 
 
     $scope.listOptions = { 
 
     items: [], 
 
     renderer: renderer, 
 
     threshold: thresholdPx, 
 
     removeThreshold: removeThresholdPx, 
 
     loadFn: loadNewItems 
 
     }; 
 

 
     // This function creates a div for each item in our dataset whenever 
 
     // it's called by the directive 
 
     function renderer(item) { 
 
     var itemElem = angular.element('<div></div'); 
 
     itemElem.css('height', item.height + 'px'); 
 
     itemElem.html(item.text); 
 
     return itemElem; 
 

 
     // If each row needs special angular behavior, you can compile it with 
 
     // something like the following instead of returning basic html 
 
     // return $compile(itemElem)($scope); 
 
     } 
 

 
     // This gets called by the directive when we need to populate more items 
 
     function loadNewItems() { 
 
     // Let's do it async like we're getting something from the server 
 
     setTimeout(function() { 
 
      for (var i = 0; i < itemsPerLoad; i++) { 
 
      // Give each item random text and height 
 
      $scope.listOptions.items.push({ 
 
       text: Math.random().toString(36).substr(2, Infinity), 
 
       height: Math.floor(100 + Math.random() * 1100) 
 
      }); 
 
      } 
 
      // Call the refresh function to let the directive know we've loaded 
 
      // We could, of course, use $watch in the directive and just make 
 
      // sure a $digest gets called here, but doing it this way is much faster. 
 
      $scope.listOptions.api.refresh(); 
 
     }, 500); 
 

 
     // return true to let the directive know we're waiting on data, so don't 
 
     // call this function again until that happens 
 
     return true; 
 
     } 
 
    } 
 
    ]) 
 
    .directive('itemList', function() { 
 
    return { 
 
     restrict: 'A', 
 
     scope: { 
 
     itemList: '=' 
 
     }, 
 
     link: function(scope, element, attrs) { 
 
     var el = element[0]; 
 
     var emptySpace = angular.element('<div class="empty-space"></div>'); 
 
     element.append(emptySpace); 
 

 
     // Keep a selection of previous elements so we can remove them 
 
     // if the user scrolls far enough 
 
     var prevElems = null; 
 
     var prevHeight = 0; 
 
     var nextElems = 0; 
 
     var nextHeight = 0; 
 

 
     // Options are defined above the directive to keep things modular 
 
     var options = scope.itemList; 
 

 
     // Keep track of how many rows we've rendered so we know where we left off 
 
     var renderedRows = 0; 
 

 
     var pendingLoad = false; 
 

 
     // Add some API functions to let the calling scope interact 
 
     // with the directive more effectively 
 
     options.api = { 
 
      refresh: refresh 
 
     }; 
 

 
     element.on('scroll', checkScroll); 
 

 
     // Perform the initial setup 
 
     refresh(); 
 

 
     function refresh() { 
 
      addRows(); 
 
      checkScroll(); 
 
     } 
 

 
     // Adds any rows that haven't already been rendered. Note that the 
 
     // directive does not process any removed items, so if that functionality 
 
     // is needed you'll need to make changes to this directive 
 
     function addRows() { 
 
      nextElems = []; 
 
      for (var i = renderedRows; i < options.items.length; i++) { 
 
      var e = options.renderer(options.items[i]); 
 
      nextElems.push(e[0]) 
 
      element.append(e); 
 
      renderedRows++; 
 
      pendingLoad = false; 
 
      } 
 
      nextElems = angular.element(nextElems); 
 
      nextHeight = el.scrollHeight; 
 

 
      // Do this for the first time to initialize 
 
      if (!prevElems && nextElems.length) { 
 
      prevElems = nextElems; 
 
      prevHeight = nextHeight; 
 
      } 
 
     } 
 

 
     function checkScroll() { 
 
      // Only check if we need to load if there isn't already an async load pending 
 
      if (!pendingLoad) { 
 
      if ((el.scrollHeight - el.scrollTop - el.clientHeight) < options.threshold) { 
 
       console.log('Loading new items!'); 
 
       pendingLoad = options.loadFn(); 
 

 
       // If we're not waiting for an async event, render the new rows 
 
       if (!pendingLoad) { 
 
       addRows(); 
 
       } 
 
      } 
 
      } 
 
      // if we're past the remove threshld, remove all previous elements and replace 
 
      // lengthen the empty space div to fill the space they occupied 
 
      if (options.removeThreshold && el.scrollTop > prevHeight + options.removeThreshold) { 
 
      console.log('Removing previous elements'); 
 
      prevElems.remove(); 
 
      emptySpace.css('height', prevHeight + 'px'); 
 

 
      // Stage the next elements for removal 
 
      prevElems = nextElems; 
 
      prevHeight = nextHeight; 
 
      } 
 
     } 
 
     } 
 
    }; 
 
    });
.item-list { 
 
    border: 1px solid green; 
 
    width: 600px; 
 
    height: 300px; 
 
    overflow: auto; 
 
} 
 
.item-list > div { 
 
    border: 1px solid blue; 
 
} 
 
.item-list > .empty-space { 
 
    background: #aaffaa; 
 
}
<html> 
 

 
<head> 
 
    <link rel="stylesheet" href="test.css"> 
 
</head> 
 

 
<body ng-app="SuperList" ng-controller="mainCtrl"> 
 
    <div class="item-list" item-list="listOptions"></div> 
 

 
    <script src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js"></script> 
 
    <script src="test.js"></script> 
 
</body> 
 

 
</html>

+0

Jak rozwiązać/dodać elementy z powrotem, jeśli przewiniesz wstecz? – karma