AngularJS应用的任何一个部分,无论它渲染在哪个上下文中,都有父级作用域存在。对于
ng-app所处的层级来讲,它的父级作用域就是$rootScope。有一个例外:在指令内部创建的作用域被称作孤立作用域。
除了孤立作用域外,所有的作用域都通过原型继承而来,也就是说它们都可以访问父级作用域。如果熟悉面向对象编程,对这个机制应该不会陌生。
默认情况下,AngularJS在当前作用域中无法找到某个属性时,便会在父级作用域中进行查找。如果AngularJS找不到对应的属性,会顺着父级作用域一直向上寻找,直到抵达$rootScope为止。如果在$rootScope中也找不到,程序会继续运行,但视图无法更新。
通过例子来看一下这个行为。创建一个ParentController,其中包含一个user对象,再创建一个ChildController来引用这个对象:
app.controller('ParentController', function($scope) {$scope.person = {greeted: false};
});
app.controller('ChildController', function($scope) {
$scope.sayHello = function() {
$scope.person.name = 'Ari Lerner';
};
});
如果我们将ChildController置于ParentController内部,那ChildController的$scope对象的父级作用域就是ParentController的$scope对象。根据原型继承的机制,我们可以在子作用域中访问ParentController的$scope对象。
例如,我们可以在ChildController的DOM元素中访问定义在ParentController中的person对象,如图5-2所示。
<div ng-controller="ParentController">
<div ng-controller="ChildController">
<a ng-click="sayHello()">Say hello</a>
</div>
{{ person }}
</div>
控制器的这种嵌套结构和DOM的嵌套结构很相似。我们看到,点击按钮时,可以在ChildController中访问ParentController中$scope.person的
值,就好像person对象定义在ChildController的$scope中一样。
图5-2 控制器嵌套控制器应该尽可能保持短小精悍,而在控制器中进行DOM操作和数据操作则是一个不好的
实践。例如,下面这个例子中的控制器包含了过于臃肿的逻辑用于控制视图,并且还操作了DOM。臃肿的控制器:
angular.module('myApp', [])
.controller('MyController', function($scope) {
$scope.shouldShowLogin = true;
$scope.showLogin = function () {
$scope.shouldShowLogin = !$scope.shouldShowLogin;
};
123456789
$scope.clickButton = function() {
$('#btn span').html('Clicked'); 10
};
$scope.onLogin = function(user) {
}
}).success(function(data) {
// user});
};});
$http({
method: 'POST',
url: '/login',
data: {
11user: user 12
设计良好的应用会将复杂的逻辑放到指令和服务中。通过使用指令和服务,我们可以将控制器重构成一个轻量且更易维护的形式:
简洁的控制器:
angular.module('myApp', []).controller('MyController', function($scope,UserSrv) {
// 内容可以被指令控制$scope.onLogin = function(user) {
UserSrv.runLogin(user);
};
});