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>
這看起來像一個很好的解決方案,它的確是一個非常方便的模塊...謝謝 –