5

У меня есть ng-repeat, который загружает тысячи записей с некоторой сложностью, которая может иметь высоту между 100px и 1200px. Излишне говорить, что спектакль получает настоящий удар.AngularJS бесконечная прокрутка (ng-repeat) - удаление верхних элементов из DOM

Infinite scrolling модуль будет работать нормально, в большинстве случаев, пока вы не нажмете край, где вы прокрутили вниз, и большинство элементов были загружены в DOM, что возвращает меня к квадрату.

Angular-vs-repeat был бы идеальным для моего случая, но я не понял, как вычислить каждую следующую высоту элемента, так как они не фиксированы.

Который возвращает меня к бесконечной прокрутке. Я предполагаю, что если верхние элементы (над окном просмотра) будут заменены пустой DIV с вычисленной высотой, равной их общей сумме высоты, производительность не будет проблемой. Пока прокрутка вернет их обратно в dom и вычитает пустую высоту DIV.

Неужели кто-то решил это раньше? Какие-либо предложения? Фрагменты кода были бы замечательными.

+1

Трудно, чтобы вы помогли без примера. Cany вы воспроизводите имитационный случай через codepen/...? –

+0

Я сам искал ту же самую технику прокрутки, но никогда не реализовывал ее, поскольку это было бы чрезмерным. У меня также были элементы различной высоты, поэтому существующие плагины должны быть изменены. Если нам удастся указать, в какой производительности будет работать, и мне нужно будет реализовать виртуальную прокрутку, я бы очень внимательно посмотрел на вышеупомянутую директиву +, вероятно, добавлю дополнительные функции, такие как сохранить 1.5 страницы элементов сверху и снизу (люди могут нанести удар по дому и концу ключи) и текущие элементы представления. Между ними были бы пустые контейнеры-макеты, скорректированные по высоте. –

+0

Checkout vs-repeat demo page, у него есть демонстрация с использованием элементов с переменным размером http://kamilkp.github.io/angular-vs-repeat/#?tab=6 –

ответ

0

ng-repeat имеет довольно крутую производительность с длинными списками из-за накладных расходов, связанных с привязками. Одна из групп, представляющих интерес, особенно мне нравится ag-grid, которая имеет an example с переменной высотой строки. Вы могли бы увидеть, будет ли это работать для ваших целей.

Если ничто из этого не соответствует вашим потребностям в этом, вы всегда можете перевернуть свою собственную директиву и обработать манипуляции с DOM самостоятельно, как приведенный ниже фрагмент кода. Он не охватывает все, что вы упомянули, но включает бесконечную прокрутку и удаляет старые элементы, заменяя их высоту пустым <div>, не используя ng-repeat.

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

Как бы вы разрешили или добавили элементы назад, если вы прокрутите назад? – karma

 Смежные вопросы

  • Нет связанных вопросов^_^