您的位置:首页 > Web前端 > AngularJS

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

2015-12-16 14:49 686 查看
前几天各种看关于依赖注入的书,分析了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();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: