2

我想在一個複雜的angular.js web應用程序中以樹的形式實現分層結構。我正在使用嵌套的ng-repeats來呈現結構,但我在IE 10中遇到了與性能相關的重大問題,並且在Chrome中出現了一些次要的性能問題。將使用的數據將包含最終級別的多達5,000個條目。 根據我的研究,我認爲以下可能是原因背後:守望元素如何在angularjs中處理樹狀結構?

  1. 大量。 爲了解決這個問題,我已經實現了一次數據綁定,並且觀察者的數量並不是那麼高。
  2. 瀏覽器重繪時間: ng-repeat將元素逐個添加到DOM中。這可能導致瀏覽器引擎超載,導致複雜的HTML多次,導致大量的滯後。 爲了解決這個問題,我通過僅在一個節點被摺疊時渲染子節點來應用延遲加載排序技術。不過,我在呈現節點的渲染節點時出現可觀察的延遲,其中渲染節點的數量很大。
  3. CSS類: 我嘗試通過剝離節點元素的所有類來實現樹結構。這導致了顯着的改善,但刪除班級並不是真正的選擇。另外,如果我給內聯風格的元素,那麼它也會導致更好的性能。
  4. 角材料的性能問題: 角材料是我的網絡應用程序的組成部分。在深入研究角色素材用戶提交的大量ng-repeats所提交的問題後,已經推出了哪些修補程序。但升級到最新版本也沒有幫助。

refer轉到此圖像的表設計。用於創建樹的模板如下:

<li ng-repeat="item in ::item.childLevelDetails" > 
<div > 
    <a ng-click="toggle(this)" class="icon icon-stream-add-2"> 
     <span></span> 
    </a> 
    <div class="unitTextDiv">{{::item.title}}</div> 
</div> 
<ol ng-include= "'tree_node'"> 
</li> 

請求您對此問題提出任何可能的解決方案。

回答

0

你可以試試這個遞歸的示例中,我爲你所做的。 使用ng-if顯示/隱藏元素將減少手錶的數量。

這裏找到Fiddler

var myApp = angular.module('myApp',[]); 
 

 
myApp.controller('MyCtrl', ['$scope','$timeout', 'getWatchCount' , function ($scope ,$timeout, getWatchCount){ 
 

 
$scope.tree = [ 
 
\t {title:'Element level 1', 
 
    elements: [ 
 
     \t { title: 'Element level 1.1'}, 
 
     { title: 'Element level 1.2', 
 
      elements: [ 
 
\t \t \t { title: 'Element level 1.2.2'}, 
 
\t \t \t { title: 'Element level 1.2.2'}, 
 
      ]} 
 
    ]}, 
 
    {title:'Element level 2'} 
 
    \t ] 
 
    
 
    
 
//NEXT CODE ONLY USED FOR COUNTING WATCHES// 
 
$scope.countWatches = function(){ 
 
    \t $scope.numberOfWatches = getWatchCount(); 
 
} 
 
    
 
$timeout(function(){$scope.countWatches()} , 0); 
 
    
 
     
 
// I return the count of watchers on the current page. 
 
function getWatchCount() { 
 

 
    // Keep track of the total number of watch bindings on the page. 
 
    var total = 0; 
 

 
    // There are cases in which two different ng-scope markers will actually be referencing 
 
    // the same scope, such as with transclusion into an existing scope (ie, cloning a node 
 
    // and then linking it with an existing scope, not a new one). As such, we need to make 
 
    // sure that we don't double-count scopes. 
 
    var scopeIds = {}; 
 

 
    // AngularJS denotes new scopes in the HTML markup by appending the classes "ng-scope" 
 
    // and "ng-isolate-scope" to appropriate elements. As such, rather than attempting to 
 
    // navigate the hierarchical Scope tree, we can simply query the DOM for the individual 
 
    // scopes. Then, we can pluck the watcher-count from each scope. 
 
    // -- 
 
    // NOTE: Ordinarily, it would be a HUGE SIN for an AngularJS service to access the DOM 
 
    // (Document Object Model). But, in this case, we're not really building a true AngularJS 
 
    // service, so we can break the rules a bit. 
 
    angular.forEach(
 
     document.querySelectorAll(".ng-scope , .ng-isolate-scope"), 
 
     countWatchersInNode 
 
    ); 
 

 
    return(total); 
 

 

 
    // --- 
 
    // PRIVATE METHODS. 
 
    // --- 
 

 

 
    // I count the $watchers in to the scopes (regular and isolate) associated with the given 
 
    // element node, and add the count to the running total. 
 
    function countWatchersInNode(node) { 
 

 
     // Get the current, wrapped element. 
 
     var element = angular.element(node); 
 

 
     // It seems that in earlier versions of AngularJS, the separation between the regular 
 
     // scope and the isolate scope where not as strong. The element was flagged as having 
 
     // an isolate scope (using the ng-isolate-scope class); but, there was no .isolateScope() 
 
     // method before AngularJS 1.2. As such, in earlier versions of AngularJS, we have to 
 
     // fall back to using the .scope() method for both regular and isolate scopes. 
 
     if (element.hasClass("ng-isolate-scope") && element.isolateScope) { 
 

 
      countWatchersInScope(element.isolateScope()); 
 

 
     } 
 

 
     // This class denotes a non-isolate scope in later versions of AngularJS; but, 
 
     // possibly an isolate-scope in earlier versions of AngularJS (1.0.8). 
 
     if (element.hasClass("ng-scope")) { 
 

 
      countWatchersInScope(element.scope()); 
 

 
     } 
 

 
    } 
 

 

 
    // I count the $$watchers in the given scope and add the count to the running total. 
 
    function countWatchersInScope(scope) { 
 

 
     // Make sure we're not double-counting this scope. 
 
     if (scopeIds.hasOwnProperty(scope.$id)) { 
 

 
      return; 
 

 
     } 
 

 
     scopeIds[ scope.$id ] = true; 
 

 
     // The $$watchers value starts out as NULL until the first watcher is bound. As such, 
 
     // the $$watchers collection may not exist yet on this scope. 
 
     if (scope.$$watchers) { 
 

 
      total += scope.$$watchers.length; 
 

 
     } 
 

 
    } 
 

 
} 
 
    
 
}]); 
 

 
myApp.factory(
 
\t \t \t "getWatchCount", 
 
\t \t \t function() { 
 

 
\t \t \t \t // I return the count of watchers on the current page. 
 
\t \t \t \t function getWatchCount() { 
 

 
\t \t \t \t \t var total = 0; 
 

 
\t \t \t \t \t // AngularJS denotes new scopes in the HTML markup by appending the 
 
\t \t \t \t \t // class "ng-scope" to appropriate elements. As such, rather than 
 
\t \t \t \t \t // attempting to navigate the hierarchical Scope tree, we can simply 
 
\t \t \t \t \t // query the DOM for the individual scopes. Then, we can pluck the 
 
\t \t \t \t \t // watcher-count from each scope. 
 
\t \t \t \t \t // -- 
 
\t \t \t \t \t // NOTE: Ordinarily, it would be a HUGE SIN for an AngularJS service 
 
\t \t \t \t \t // to access the DOM (Document Object Model). But, in this case, 
 
\t \t \t \t \t // we're not really building a true AngularJS service, so we can 
 
\t \t \t \t \t // break the rules a bit. 
 
\t \t \t \t \t angular.element(".ng-scope").each(
 
\t \t \t \t \t \t function ngScopeIterator() { 
 

 
\t \t \t \t \t \t \t // Get the scope associated with this element node. 
 
\t \t \t \t \t \t \t var scope = $(this).scope(); 
 

 
\t \t \t \t \t \t \t // The $$watchers value starts out as NULL. 
 
\t \t \t \t \t \t \t total += scope.$$watchers 
 
\t \t \t \t \t \t \t \t ? scope.$$watchers.length 
 
\t \t \t \t \t \t \t \t : 0 
 
\t \t \t \t \t \t \t ; 
 

 
\t \t \t \t \t \t } 
 
\t \t \t \t \t); 
 
\t \t \t \t \t 
 
\t \t \t \t \t return(total); 
 

 
\t \t \t \t } 
 

 
\t \t \t \t // For convenience, let's serialize the above method and convert it to 
 
\t \t \t \t // a bookmarklet that can easily be run on ANY AngularJS page. 
 
\t \t \t \t getWatchCount.bookmarklet = ( 
 
\t \t \t \t \t "javascript:alert('Watchers:'+(" + 
 
\t \t \t \t \t getWatchCount.toString() 
 
\t \t \t \t \t \t .replace(/\/\/.*/g, " ") 
 
\t \t \t \t \t \t .replace(/\s+/g, " ") + 
 
\t \t \t \t \t ")());void(0);" 
 
\t \t \t \t); 
 

 
\t \t \t \t return(getWatchCount); 
 

 
\t \t \t } 
 
\t \t);
ul{ 
 
    list-style-type: none; 
 
} 
 

 
li{ 
 
    font-size:13px; 
 
} 
 
.arrow{ 
 
    width: 0; 
 
    height: 0; 
 
    border-top: 7px solid transparent; 
 
    border-bottom: 7px solid transparent; 
 
    border-right: 7px solid transparent; 
 
    cursor: pointer; 
 
    margin-left: 5px; 
 
    border-left: 7px solid #000; 
 
    display: inline-block; 
 
    transition:all 0.3s; 
 
} 
 

 
.arrow.expand { 
 
    transform: rotate(45deg); 
 
    transform-origin: 20% 50%; 
 
    margin-top: 0; 
 
} 
 

 
.arrow.none { 
 
    border-left: 7px solid #ccc; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<div ng-app="myApp" ng-controller="MyCtrl" > 
 

 
    <p> 
 
\t \t <strong>Watch Count:</strong> {{ numberOfWatches }} 
 
    </p> 
 
    
 
    <script type="text/ng-template" id="elementTree"> 
 
     <li> 
 
      <div class="arrow" 
 
        
 
       ng-class="{expand:element.isOpen,none:!element.elements}" 
 
       ng-click="$apply(element.isOpen = !element.isOpen) ; countWatches()"> 
 
      </div> 
 
      {{element.title}} 
 
     </li> 
 
     <div ng-if="element.isOpen"> 
 
      <ul 
 
       ng-repeat="element in element.elements" 
 
       ng-include="'elementTree'"> 
 
      </ul 
 
     </div> 
 
     
 
    </script> 
 
    
 
    <ul ng-repeat="element in tree" 
 
     ng-include="'elementTree'"> 
 
    </ul> 
 
    
 
    
 
</div>

+0

通過使用angular的一次性綁定功能,手錶數量從來都不是問題。主要問題是元素渲染的延遲。這裏是你的[Fiddler]的分支(http://jsfiddle.net/93agvdoj/),我修改了它展示了渲染問題 –