日常总结之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()的指令
需要注意的一点是,在angularjs中内置的服务service比如$timeout会自动调用$apply(),不需要手动调用$apply()。
下例是自己创建的类似angularjs的数据双向绑定的过程:
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();
相关文章推荐
- angularJS权威教程自动化测试笔记(一)
- Angular2组件开发—表单输入(一)
- Angular2组件开发—属性与事件(二)
- Angular2组件开发—属性与事件(一)
- 在 Angular 中实现搜索关键字高亮
- AngularJS进阶(二十一)Angularjs中scope与rootscope区别及联系
- AngularJS进阶(二十一)Angularjs中scope与rootscope区别及联系
- AngularJs parent index
- Angular 学习笔记——ng-Resource1
- Angular 学习笔记——ng-Resource
- AngularJS中service,factory,provider的区别
- AngularJs自定义指令大全
- 快速搭建Web环境 Angularjs + Express3 + Bootstrap3
- AngularJS 学习路线
- 【angularjs学习】简单的语法
- angular发送multipart/form-data文件的方法
- 基于SWFUpload的angular上传组件
- 构建兼容浏览器的Angularjs web应用
- angularjs使用总结
- AngularJS(02)---控制器