分享人:禚洪宇
目录
1.背景介绍
2.知识剖析
3.常见问题
4.解决方案
5.编码实战
6.扩展思考
7.参考文献
8.更多讨论
正常来讲,浏览器接受到事件后会执行对应的回调函数, 这将进入 JavaScript 上下文; 一旦回调函数完成,浏览器将离开 JavaScript 上下文并根据 DOM 更改重新呈现视图, 等待更多的事件。 AngularJS 拓展了这个循环,生成一个Angular context。
Scopes provide APIs ($watch) to observe model mutations.
User: ‹input type="text" ng-model="user"›
Password: ‹input type="password" ng-model="pass"›
$watch('user',function(){})
$watch('pass',function(){})
app.controller('MainCtrl', function($scope) {
$scope.foo = "Foo";
$scope.world = "World";
});
html:
Hello, {{ World }}
也就是说,$watch方法只有在html中绑定才会创建,在controller中添加变量并不会创建
假如$scope.people中有10条数据,那么这段代码中
会生成多少条$watch呢?
app.controller('MainCtrl', function($scope) {
$scope.people = [...];
});
index.html:
<'ul>
<'li ng-repeat="person in people">
{{person.name}} - {{person.age}}
<'/li>
<'/ul>
每一个绑定到了UI(user interface:用户界面)上的数据都会生成一个$watch
当浏览器接收到可以被angular context处理的事件时,$digest循环就会触发
例如:
controllers.js
app.controller('MainCtrl', function() {
$scope.name = "Foo";
$scope.changeFoo = function() {
$scope.name = "Bar";
}
});
index.html
{{ name }}
<'button ng-click="changeFoo()">Change the name<'/button>
过程:
Tip:每一个进入angular context的事件都会触发$digest loop;
Scopes provide APIs ($apply) to propagate any model changes through the system into the view from outside of the "AngularJS realm" (controllers, services, AngularJS event handlers).
谁来决定哪些事件进入angualr context,哪些不进入呢?
当用n-click触发点击事件时,angular会将事件封装到$apply中执行
如果有一个ng-model="foo"的input,然后敲一个f,事件就会这样调用$apply("foo = 'f';")。
Angular什么时候不会自动为我们$apply呢?
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++;
});
}
}
});
app.controller('MainCtrl', function($scope) {
$scope.foo = 0;
$scope.bar = 0;
});
Tip:
如果想使用一个jQuery插件,并且要执行$digest循环来更新DOM的话,要确保调用了$apply。
使用$watch来监视你自己的东西
app.controller('MainCtrl', function($scope) {
$scope.name = "Angular";
$scope.updated = -1;
$scope.$watch('name', function() {
$scope.updated++;
//controller执行到这个$watch时,
//它会立即执行一次,因此我们设置updated为-1
});
});
index.html
<'body ng-controller="MainCtrl">
<'input ng-model="name" />
Name updated: {{updated}} times.
<'/body>
app.controller('MainCtrl', function($scope) {
$scope.name = "Angular";
$scope.updated = 0;
$scope.$watch('name', function(newValue, oldValue) {
if (newValue === oldValue) { return; } // AKA first run
$scope.updated++;
});
});
index.html
<'body ng-controller="MainCtrl">
<'input ng-model="name" />
Name updated: {{updated}} times.
<'/body>
app.controller('MainCtrl', function($scope) {
$scope.user = { name: "Fox" };
$scope.updated = 0;
$scope.$watch('user', function(newValue, oldValue) {
if (newValue === oldValue) { return; }
$scope.updated++;
});
});
index.html
<'body ng-controller="MainCtrl">
<'input ng-model="user.name" />
Name updated: {{updated}} times.
<'/body>
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);
});
index.html
<'body ng-controller="MainCtrl">
<'input ng-model="user.name" />
Name updated: {{updated}} times.
<'/body>
参考一: $watch How the $apply Runs a $digest
参考二: Angular 官方文档
BY :禚洪宇