什么是作用域?
作用域是引用应用程序模型的对象。 它是表达式的执行上下文。 作用域以层次结构排列,模仿应用程序的DOM结构,它可以观察表达式和传播事件。
作用域的特征
Scope提供API($watch)来观察模型改变。
Scope提供API($apply),通过系统将任何模型更改传播到"AngularJS领域"(控制器,服务,AngularJS事件处理程序)外部的视图中。
Scope可以嵌套以限制对应用程序组件的属性的访问,同时提供对共享模型属性的访问。 嵌套的作用域是“子作用域”或“隔离作用域”。 “子作用域”(原型)从其父作用域继承属性。 “隔离作用域”不从父作用域中继承属性。
Scope提供对其评估表达式的上下文。 例如{{username}}表达式没有意义,除非根据定义username属性的特定作用域进行求值。
作用域作为数据模型
Scope是应用程序控制器和视图之间的粘合剂。 在模板链接阶段,指令在作用域上设置$watch表达式。 $watch允许通知属性更改的指令,这允许指令将更新的值呈现给DOM。
控制器和指令都涉及作用域,但不是互相。 这种措施将控制器与指令以及DOM隔离。 这是一个重要的点,因为它使控制器被视为不存在,这极大地改善了应用程序的测试环节。
script.js
angular.module('scopeExample', [])
.controller('MyController', ['$scope', function($scope) {
$scope.username = 'World';
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.username + '!';
};
}]);
index.html
<div ng-controller="MyController" ng-app="scopeExample">
Your name:
<input type="text" ng-model="username">
<button ng-click='sayHello()'>greet</button>
<hr>
{{greeting}}
</div>
在上面的示例中,注意MyController将World指定给作用域的username属性。 作用域然后通知输入的分配,然后呈现输入用用户名预填充。 这演示了控制器如何将数据写入作用域。
类似地,控制器可以将行为分配给作用域,如sayHello方法所示,当用户单击"greet"按钮时调用。 sayHello方法可以读取username属性并创建一个greeting属性。这表明作用域上的属性在绑定到HTML的input控件时自动更新。
逻辑上{{greeting}}的渲染包括:
- 检索与在模板中定义{{greeting}}的DOM节点相关联的作用域。在这个示例中,这是与传递到MyController的作用域相同的作用域。 (稍后我们将讨论作用域层次结构。)
- 根据上面检索的作用域计算greeting语表达式,并将结果分配给包含的DOM元素的文本。
可以将作用域及其属性视为用于呈现视图的数据。作用域是所有视图相关的单一真实来源。
从可测试性的角度来看,控制器和视图的分离是可取的,因为它允许我们测试行为而不会被渲染细节分散注意力。
protractor.js
it('should say hello', function() {
var scopeMock = {};
var cntl = new MyController(scopeMock);
// 预测用户名已预填
expect(scopeMock.username).toEqual('World');
// 预测我们读新的用户名和问候
scopeMock.username = 'angular';
scopeMock.sayHello();
expect(scopeMock.greeting).toEqual('Hello angular!');
});
作用域层次
每个AngularJS应用程序只有一个根作用域,但可以有任意数量的子作用域。
应用程序可以有多个作用域,因为指令可以创建新的子作用域。 创建新作用域时,它们被认为是添加到父作用域的子作用域。 这创建了一个树结构,它与它们附加的DOM平行。
当AngularJS计算{{name}}时,它首先查看与name属性的给定元素相关联的作用域。 如果没有找到这样的属性,它搜索父作用域,等等,直到达到根作用域。 在JavaScript中,这种行为被称为原型继承,而子作用域原型继承自他们的父母。
此示例说明了应用程序中的作用域,以及属性的原型继承。示例后面是描述作用域边界的图。
index.html
<div class="show-scope-demo" ng-app="scopeExample">
<div ng-controller="GreetController">
Hello {{name}}!
</div>
<div ng-controller="ListController">
<ol>
<li ng-repeat="name in names">{{name}} from {{department}}</li>
</ol>
</div>
</div>
script.js
angular.module('scopeExample', [])
.controller('GreetController', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'AngularJS';
}])
.controller('ListController', ['$scope', function($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}]);
style.css
.show-scope-demo.ng-scope,
.show-scope-demo .ng-scope {
border: 1px solid red;
margin: 3px;
}
请注意,AngularJS自动将ng-scope类放置在附加了作用域的元素上。 此示例中的