日常总结之angularjs的双向绑定全透析

前几天各种看关于依赖注入的书,分析了angularjs的依赖注入原理。这几天又重新复习了一下ng的双向数据绑定。

angularjs中关于数据双向绑定的几个关键api有$watch()、$apply()以及$digest()。

$watch()用于视图向模型的检测,$apply()用于模型向视图的渲染。

$watch()监测模型是否发生变化,而在模型发生变化真正执行后续操作需要执行$digest()对watch队列进行循环检测。然而只有进入angular 的上下文环境才能执行$digest()循环检测,而进入angular的上下文环境需要执行$apply()。也就是说$scope.$apply()执行会自动触发$rootScope.$digest(),

如果我们写的指令在运行时没有进入到angular的上下文环境中,$watch()只会将模型的值进行保存而不会将model渲染进view中。常用的angular封装好的指令例如ng-click在执行后会自动进行数据的双向绑定,原因就是已经在指令中执行了$apply()。

下面创建自己的指令,观察$apply()的作用

不使用$apply()的指令

<body ng-controller="MainCtrl" ng-app="app">
<clickable foo="foo" bar="bar"></clickable>
<hr />
{{ hello }}
<button ng-click="setHello()">Change hello</button>
</body>
<script>
app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
  $scope.foo = 0;
  $scope.bar = 0;
  
  $scope.hello = "Hello";
  
  $scope.setHello = function() {
    $scope.hello = "World";
  };
});

app.directive('clickable', function() {
  
  return {
    restrict: "E",
    scope: {
      foo: '=',
      bar: '='
    },
    template: '<ul style="background-color: lightblue"><li>{{foo}}</li><li>{{bar}}</li></ul>',
    link: function(scope, element, attrs) {
      element.bind('click', function() {
        scope.foo++;
        scope.bar++;
      });
    }
  };
});
</script>
使用$apply()的指令

<body ng-controller="MainCtrl" ng-app="app">
<clickable foo="foo" bar="bar"></clickable>
</body>

<script>
app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
  $scope.foo = 0;
  $scope.bar = 0;
});
app.directive('clickable', function() {
  return {
    restrict: "E",
    scope: {
      foo: '=',
      bar: '='
    },
    template: '<ul style="background-color: lightblue"><li>{{foo}}</li><li>{{bar}}</li></ul>',
    link: function(scope, element, attrs) {
      element.bind('click', function() {
        scope.foo++;
        scope.bar++;   
        scope.$apply();
      });
    }
  };
});
</script>

需要注意的一点是,在angularjs中内置的服务service比如$timeout会自动调用$apply(),不需要手动调用$apply()。

下例是自己创建的类似angularjs的数据双向绑定的过程:

var Scope = function( ) {
	this.$$watchers = [];	
};

Scope.prototype.$watch = function( watchExp, listener ) {
	this.$$watchers.push( {
		watchExp: watchExp,
		listener: listener || function() {}
	} );
};

Scope.prototype.$digest = function( ) {
	var dirty;

	do {
            dirty = false;
        
			for( var i = 0; i < this.$$watchers.length; i++ ) {
				var newValue = this.$$watchers[i].watchExp(),
					oldValue = this.$$watchers[i].last;

				if( oldValue !== newValue ) {
					this.$$watchers[i].listener(newValue, oldValue);

					dirty = true;

					this.$$watchers[i].last = newValue;
				}
			}
	} while(dirty);
};

var $scope = new Scope();

$scope.name = 'test';

$scope.$watch(function(){
    return $scope.name;
}, function( newValue, oldValue ) {
    console.log(newValue, oldValue);
} );

$scope.$digest();



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值