下面将要介绍的指令会以父级作用域为原型生成子作用域。这种继承的机制可以创建一个隔离层,用来将需要协同工作的方法和数据模型对象放置在一起。
ng-app
和ng-controller
是特殊的指令,因为它们会修改嵌套在它们内部的指令作用域。
ng-app
为AngularJS应用创建$rootScope, ng-controller则会以$rootScope或另外一个ng-controller的作用域为
原型创建新的子作用域。
任何具有ng-app属性的DOM元素将标记为$rootScope的起始点。
$rootScope是作用域链的起始点,任何嵌套在ng-app内的指令都会继承它。
在JavaScript代码中通过run方法来访问$rootScope.
HTML
<thml ng-app="myAPp">
<body>
{{ someProperty }}
<button ng-click="someAction()"></button>
</body>
</thml>
JAVASCRIPT
angular.module('myApp', [])
.run(function($rootScope) {
$rootScope.someProperty = 'hello computer';
$rootScope.someAction = function() {
$rootScope.someProperty = 'hello human';
};
});
内置指令ng-controller的作用域是为在其中的指令创建一个子作用域,避免将所有操作和模型都定义在$rootScope上。
用这个指令可以在一个DOM元素上放置控制器。
ng-controller接受一个参数expression,这个参数是必须的。
expression参数是一个AngularjS表达式。子$scope只是一个JavaScript对象,其中含有从父级$scope中通过原型继承得到的方法和属性,包括应用的$rootScope。
嵌套在ng-controller中的指令有访问新子$scope的权限,但是要牢记每个指令都应该遵守的和作用域相关的规则。
回想一下,$scope对象的职责是承载DOM中指令所共享的操作和模型。
操作指的是$scope上的标准JavaScript方法。
模型指的是$scope上保存的包含瞬时状态数据的JavaScript对象。持久化状态的数据应该保存到服务中,服务的作用是处理模型的持久化。
出于技术和架构方面的原因,绝对不要直接将控制器中的$scope赋值为值类型对象(字符串、布尔值或数字)。DOM中应该始终通过点操作符.来访问数据。遵守这个规则将使你远离不可预期的麻烦。
控制器应该尽可能简单。虽然可以用控制器来组织所有功能,但是将业务逻辑移到服务和指令中是非常好的主意。
有了控制器,我们可以将之前的例子改造一下,把数据和操作放到子作用域中:
<div ng-controller="SomeController">
{{ someModel.someProperty }}
<button ng-click="someAction()">Communicate</button>
</div>
angular.module('myApp', [])
.controller('SomeController', function($scope) {
//创建模型
$scope.someModel = {
// 添加属性
someProperty: 'hello computer'
}
// 设置$scope自身的操作
$scope.someAction = function() {
$scope.someModel.someProperty = 'hello human';
};
});
我们使用了$rootScope的子作用域,它提供了一个干净的对象供我们操作。使用子作用域意味着其上的数据模型和操作在应用的其他地方是无法访问的,只能被这个作用域内的指令及其子作用域访问。其次,显式声明了数据模型,我们说过,这非常重要。为了展示这为什么重要,看一下这个例子的变体。这个例子中,在已有的控制器中嵌套了第二个控制器,并且没有设置模型对象的属性:
<div ng-controller="SomeController">
{{ someBareValue }}
<button ng-click="someAction()">Communicate to child</button>
<div ng-controller="ChildController">
{{ someBareValue }}
<button ng-click="childAction()">Communicate to parent</button>
</div>
</div>
angular.module('myApp', [])
.controller('SomeController', function($scope) {
// 反模式,裸值
$scope.someBareValue = 'hello computer';
// 设置$scope 本身的操作,这样没问题
$scope.someAction = function() {
// 在SomeController和ChildController中设置{{ someBareValue }}
$scope.someBareValue = 'hello human, from parent';
};
})
.controller('ChildController', function($scope) {
$scope.childAction = function() {
// 在ChildController中设置{{ someBareValue }}
$scope.someBareValue = 'hello human, from child';
};
});
由于原型继承的关系,修改父级对象中的someBareValue会同时修改子对象中的值,但反之则不行。