控制器
AngularJS中的控制器是一个函数,用来向视图的作用域中添加额外的功能。我们用它来给作用域对象设置初始状态,并添加自定义行为。
当我们在页面上创建一个新的控制器时, AngularJS会生成并传递一个新的scope给这个控制器。可以在这个控制器里初始化$scope。由于AngularJS会负责处理控制器的实例化过程,我们只需编写构造函数即可。下面的例子展示了控制器初始化:
我们是在全局作用域中创建的这个函数。这样做并不合适,因为会污染全局命名空间。更合理的方式是创建一个模块,然后在模块中创建控制器,如下所示:
只需创建控制器作用域中的函数,就能创建可以在视图中使用的自定义操作,AngularJS允许我们在视图中像调用普通数据一样调用$scope上的函数。
用内置指令ng-click可以将按钮、链接等其他任何DOM元素同点击事件进行绑定。 ng-click指令将浏览器中的mouseup事件,同设置在DOM元素上的事件处理程序绑定在一起(例如,当浏览器在某个DOM元素上触发了点击事件,函数就会被调用)。
AngularJS通过作用域将视图、控制器和指令(本书后面会介绍)隔离开来,这样就很容易为功能的具体部分编写测试。
- 控制器嵌套(作用域包含作用域)
AngularJS应用的任何一个部分,无论它渲染在哪个上下文中,都有父级作用域存在。对于ng-app所处的层级来讲,它的父级作用域就是$rootScope。(有一个例外:在指令内部创建的作用域被称作孤立作用域。)
默认情况下,AngularJS在当前作用域中无法找到某个属性时,便会在父级作用域中进行查找。如果AngularJS找不到对应的属性,会顺着父级作用域一直向上寻找,直到抵达$rootScope为止。如果在$rootScope中也找不到,程序会继续运行,但视图无法更新。
下面看一个例子,创建一个ParentController,其中包含一个user对象,再创建一个ChildController来引用这个对象:
如果我们将ChildController置于ParentController内部,那ChildController的scope对象的父级作用域就是ParentController的$scope对象。根据原型继承的机制,我们可以在子作用域中访问ParentController的$scope对象。
See the Pen MwPXNq
表达式
表达式和eval(javascript)非常相似,但是由于表达式由AngularJS来处理,它们有以下显著不同的特性:
- 所有的表达式都在其所属的作用域内部执行,并有访问本地$scope的权限;
- 如果表达式发生了TypeError和ReferenceError并不会抛出异常;
- 不允许使用任何流程控制功能(条件控制,例如if/eles);
- 可以接受过滤器和过滤器链。
对表达式进行的任何操作,都会在其所属的作用域内部执行,因此可以在表达式内部调用那些限制在此作用域内的变量,并进行循环、函数调用、将变量应用到数学表达式中等操作。
- 解析 AngularJS 表达式
AngularJS通过$parse这个内部服务来进行表达式的运算,这个服务能够访问当前所处的作用域。这个过程允许我们访问定义在$scope上的原始JavaScript数据和函数。
将$parse服务注入到控制器中,然后调用它就可以实现手动解析表达式。举例来说,如果页面上有一个输入框绑定到了expr变量上,如下所示:
我们可以在MyController中给expr这个表达式设置一个$watch并解析它:
- 插值字符串
在AngularJS中,我们的确有手动运行模板编译的能力。例如,插值允许基于作用域上的某个条件实时更新文本字符串。要在字符串模板中做插值操作,需要在你的对象中注入$interpolate服务。在下面的例子中,我们将会将它注入到一个控制器中:
$interpolate服务是一个可以接受三个参数的函数,其中第一个参数是必需的。
- text(字符串):一个包含字符插值标记的字符串。
- mustHaveExpression(布尔型):如果将这个参数设为true,当传入的字符串中不含有表达式时会返回null。
- trustedContext(字符串): AngularJS会对已经进行过字符插值操作的字符串通过$sec.getTrusted()方法进行严格的上下文转义。
$interpolate服务返回一个函数,用来在特定的上下文中运算表达式。设置好这些参数后,就可以在控制器中进行字符插值的操作了。例如,假设我们希望可以在电子邮件的正文中进行实时编辑,当文本发生变化时进行字符插值操作并将结果展示出来。