在$scope内置的所有函数中,用得最多的可能就是$watch 函数了。当你的数据模型中某一部分发生变化时,$watch函数可以向你发出通知。
你可以监控单个对象的属性,也可以监控需要经过计算的结果(函数)。
实际上只要能够被当作属性访问到,或者可以当作一个JavaScript函数被计算出来,就可以被$watch 函数监控。
它的函数签名为$watch(watchFn, watchAction, deepWatch)
- watchFn
该参数是一个带有Angular表达式或者函数的字符串,它会返回被监控的数据模型的当前值。这个表达式将会被执行很多次,所以你要保证它不会产生 其他副作用。也就是说,要保证它可以被调用很多次而不会改变状态。基于同样的原因,监控表达式应该很容易被计算出来。如果你使用字符串传递了一个 Angular表达式,那么它将会针对调用它的那个作用域中的对象而执行。
- watchAction
这是一个函数或者表达式,当watchFn 发生变化时会被调用。如果是函数的形式,它将会接收到watchFn的新旧两个值,以及作用域对象的引用。
其函数签名为function(newValue, oldValue, scope)。
- deepWatch
如果设置为true,这个可选的布尔型参数将会命令Angular去检查被监控对象的每个属性是否发生了变化。如果你想要监控数组中的元素,或者对象上的所有属性,而不只是监控一个简单的值,你就可以使用这个参数。由于Angular需要遍历数组或者对象,如果集合比较大,那么运算负担就会比较重。
注销监控器
$watch 函数会返回一个函数,当你不再需要接收变更通知时,可以用这个返回的函数注销监控器。
如果我们需要监控一个属性,然后接着注销监控,我们可以使用以下代码:
...
var dereg = $scope.$watch('someModel.someProperty', callbackOnChange());
…
dereg();
示例代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="js/angular.min.js"></script> <link href="css/bootstrap.min.css" rel="stylesheet" /> </head> <body ng-app="myApp"> <div style="padding: 100px 500px 100px;" ng-controller="CartController"> <form class="form" role="form"> <div class="form-group" ng-repeat="item in items"> <span class="label label-default">{{item.title}}</span> <input class="form-control" ng-model="item.quantity"> <span class="label-success"><div class="label label-info">单价:</div>{{item.price | currency}}</span> <span class="label-success"><div class="label label-info">总价:</div>{{item.price * item.quantity | currency}}</span> </div><br /> <div class="label label-primary">Total: {{totalCart() | currency}}</div> <div class="label label-danger">Discount: {{discount | currency}}</div> <div class="label label-primary">Subtotal: {{subtotal() | currency}}</div> </form> </div> <script src="js/CartController.js"></script> </body> </html>
CartController.js
var app = angular.module('myApp', []); app.controller('CartController', CartController); CartController.$inject = ['$scope']; function CartController($scope) { $scope.items = [{ title: 'Paint pots', quantity: 8, price: 3.95 }, { title: 'Polka dots', quantity: 17, price: 12.95 }, { title: 'Pebbles', quantity: 5, price: 6.95 }]; $scope.totalCart = function() { var total = 0; for (var i = 0, len = $scope.items.length; i < len; i++) { total = total + $scope.items[i].price * $scope.items[i].quantity; } return total; } $scope.subtotal = function() { return $scope.totalCart() - $scope.discount; }; function calculateDiscount(newValue, oldValue, scope) { $scope.discount = newValue > 100 ? 10 : 0; } var dereg = $scope.$watch($scope.totalCart, calculateDiscount); // dereg(); }