angularJs 进阶

$watch $apply $digest angular context dirty checking


####angular context

浏览器一直等待事件触发,当在页面触发事件(点击等),事件的回调函数便开始在javascript 解释器中执行,对dom进行操作,回调函数完成后,页面变出现了变化


####$watch 队列

每一个绑定到了UI上的数据,就会生成一个$watch

	app.controller('MainCtrl', function($scope) {
	  $scope.foo = "Foo";
	  $scope.world = "World";
	});
	app.controller('MainCtrl', function($scope) {
	 Hello, 
	});

上面的例子生成了1个$watch

模板加载完毕时(linking阶段)Angular解释器会寻找每个directive,然后生成每个需要的$watch。


####$digest

过程(dirty checking):


	app.controller('MainCtrl', function() {
	$scope.name = "Foo";
	$scope.changeFoo = function() {
      $scope.name = "Bar";
	  }
	});
	
	<button ng-click="changeFoo()">Change the name</button>

每一个进入angular context的事件都会执行一个$digest循环

####$apply

为什么我的jQuery不会更新我绑定的东西呢?因为jQuery没有调用$apply,事件没有进入angular context,$digest循环永远没有执行。

app.directive('clickable', function() {

return {
  restrict: "E",
  scope: {
    foo: '=',
    bar: '='
  },
  template: '<ul style="background-color: lightblue"><li></li><li></li></ul>',
  link: function(scope, element, attrs) {
    element.bind('click', function() {
      scope.foo++;
      scope.bar++;
    });
  }
}

});

app.controller('MainCtrl', function($scope) {
  $scope.foo = 0;
  $scope.bar = 0;
});

那我们点击元素的时候会发生什么呢?我们能看到更新吗?答案是否定的。因为点击事件是一个没有封装到$apply里面的常见的事件,这意味着我们会失去我们的计数吗?不会

真正的结果是:$scope确实改变了,但是没有强制$digest循环,监视foo 和bar的$watch没有执行。也就是说如果我们自己执行一次$apply那么这些$watch就会看见这些变化,然后根据需要更新DOM。

		element.bind('click', function() {
	  scope.$apply(function() {
	      scope.foo++;
	      scope.bar++;
	  });
	})

这样就可以了(手动调用apply)


####$watch扩展

app.controller('MainCtrl', function($scope) {
  $scope.user = { name: "Fox" };

  $scope.updated = 0;

  $scope.$watch('user', function(newValue, oldValue) {
    if (newValue === oldValue) { return; }
    $scope.updated++;
  });
});
app.controller('MainCtrl', function($scope) {
  $scope.user = { name: "Fox" };

  $scope.updated = 0;

  $scope.$watch('user', function(newValue, oldValue) {
    if (newValue === oldValue) { return; }
    $scope.updated++;
  }, true);
});