什么是控制器
在angularJS中,controller是一个javascript函数/类,用于操作作用域中,各个对象的初始状态以及相应的行为。
在HTML中,绑定ng-controller的那个DOM节点内的所有子标签,将会是当前controller的作用域。在大型项目中,如果HTML DOM 中有多个作用域,这时你就需要知道你使用的 scope 对应的作用域是哪一个。
使用controller可以初始化$scope
作用域对象、为作用域对象添加行为
初始化 $scope 对象
<!DOCTYPE html>
<html ng-app="myApp">
<body>
<div ng-controller="GreetingController">
{{ greeting }}
</div>
<script src="../angular.min.js"></script>
<script>
var myApp = angular.module("myApp", []);
myApp.controller("GreetingController", [
"$scope",
function ($scope) {
$scope.greeting = "Hola!";
}
]);
</script>
</body>
</html>
在以上案例中,首先在作用域{{ greeting }}
上通过ng-controller
绑定了一个控制器GreetingController
,然后定义了一个控制器构造函数,我们在控制器所创建的scope中添加了一个greeting
属性
为 $scope 对象添加行为
为了对事件作出响应,或是在视图中执行计算,我们需要为 scope 提供相关的行为操作的逻辑。上面一节中,我们为 scope 添加属性来让模板可以访问数据模型,现在,我们为 $scope 添加方法来让它提供相关的交互逻辑。添加完之后,这些方法就可以在模板/视图中被调用了。
下面的例子将演示为控制器的 scope 添加方法,它用来使一个数字翻倍:
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<body>
<div ng-controller="DoubleController">
Two times <input ng-model="num"> equals {{ double(num) }}
</div>
<script src='../angular.min.js'></script>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('DoubleController', ['$scope', function ($scope) {
$scope.double = function (value) {
return value * 2;
};
}])
</script>
</body>
</html>
如 概述 部分所指出的一样,任何对象(或者原生类型的变量)被添加到 scope 后都将成为 scope 的属性,作为数据模型供模板/视图调用。任何方法被添加到 scope 后,也能在模板/视图中通过Angular表达式或是Angular的事件处理器(如:ngClick)调用
正确使用控制器
通常情况下,控制器不应被赋予太多的责任和义务,它只需要负责一个单一视图所需的业务逻辑。
最常见的保持控制器“纯度”的方法是将那些不属于控制器的逻辑都封装到服务(services)中,然后在控制器中通过依赖注入调用相关服务。
注意,下面的场合千万不要用控制器:
- 任何形式的DOM操作:控制器只应该包含业务逻辑。DOM操作则属于应用程序的表现层逻辑操作,向来以测试难度之高闻名于业界。把任何表现层的逻辑放到控制器中将会大大增加业务逻辑的测试难度。ng提供数据绑定 (数据绑定) 来实现自动化的DOM操作。如果需要手动进行DOM操作,那么最好将表现层的逻辑封装在 指令 中
- 格式化输入:使用angular表单控件 代替
- 过滤输出:使用 angular过滤器 代替 在控制器间复用有状态或无状态的代码:使用angular服务 代替
- 管理其它部件的生命周期(如手动创建 service 实例)
Scope 继承
我们常常会在不同层级的DOM结构中添加控制器。由于 ng-controller
指令会创建新的子级 scope ,这样我们就会获得一个与DOM层级结构相对应的的基于继承关系的 scope 层级结构。
底层的$scope
能够访问最近的上一层的$scope
的属性和方法
<div ng-app="scopeInheritance" class="spicy">
<div ng-controller="MainCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<div ng-controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}} !</p>
<div ng-controller="GrandChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
</div>
</div>
</div>
</div>
var myApp = angular.module("scopeInheritance", []);
myApp.controller("MainCtrl", [
"$scope",
function($scope) {
$scope.timeOfDay = "morning";
$scope.name = "Nikki";
}
]);
myApp.controller("ChildCtrl", [
"$scope",
function($scope) {
$scope.timeOfDay = "noon";
// $scope.name = "Mattie";
}
]);
myApp.controller("GrandChildCtrl", [
"$scope",
function($scope) {
$scope.name = "Gingerbreak Baby";
}
]);
注意,上面例子中我们在HTML模板中嵌套了三个 ng-controller 指令,这导致我们的视图中有4个 scope:
- root scope,所有作用域的“根”
- MainCtrl 控制器管理的 scope (简称 MainCtrl scope),拥有 timeOfDay 和 name 两个属性
- ChildCtrl 控制器管理的 scope (简称 ChildCtrl scope),继承了 MainCtrl scope 中的 timeOfDay 属性,但重写了它的 name 属性
- GrandChildCtrl 控制器管理的 scope (简称 GrandChildCtrl scope),重写了 MainCtrl scope 中的 timeOfDay 属性和 ChildCtrl scope 中的 name 属性
控制器中,方法继承和属性继承的工作方式是一样的,所以,上面例子中的所有属性,我们也可以改写成能够返回字符串值的方法,同样有效。