第5章 作用域与事件
5.1 AngularJS作用域详解
从本书的第一个案例开始,我们就已经接触到了AngularJS的作用域,并且前面的每一个案例都和作用域息息相关,本章就对AngularJS作用域进行更深入的介绍。
众所周知,JavaScript对象是基于key-value键值对的,我们可以把JavaScript对象作为一个map数据结构使用,而AngularJS作用域本质上就是一个普通的JavaScript对象,形式如下:
var obj = { name:'Jane', age:30, walk:function(){ console.info("walk"); } }
AngularJS作用域对象和普通JavaScript对象一样,都可以在作用域对象中增加属性或者方法,不同的是我们不需要手动去构造作用域对象,当HTML页面中出现ng-app和ng-controller指令时,AngularJS框架会自动创建作用域对象,我们只需将其注入即可。
AngularJS程序中作用域的主要功能是存放模型数据,在控制器中,我们可以修改作用域中的模型数据或在作用域中新增模型数据(例如:$scope.address = 'China'),然后在视图中通过AngularJS表达式展示模型数据(例如:{{address}})。
每个AngularJS应用至少会有一个名称为$rootScope的作用域,它是AngularJS应用的根作用域。前面我们接触过ng-app指令,它可以出现在任何HTML标签中,用于启动AngularJS框架。当AngularJS启动时会自动创建一个根作用域对象$rootScope,接着当我们使用ng-controller指令实例化控制器对象时,AngularJS框架会为我们创建一个子作用域$scope,默认情况下,该子作用域会继承$rootScope作用域的所有属性。下面来看一个作用域对象继承的例子:
代码清单:ch05\ch05_01\ch05_01.html
<!doctype html> <html ng-app="app"> <head> <meta charset="UTF-8"> <title>ch05_01</title> <script type="text/javascript" src="/angular-1.5.5/angular.js"></ script> <script type="text/javascript" src="controllers.js"></script> </head> <body ng-init="name='jane'; age=23"> <div ng-controller="FirstController"> </div> </body> </html>
上面使用的FirstController控制器代码定义在controller.js文件中,代码如下:
代码清单:ch05\ch05_01\controllers.js
var app = angular.module('app', []); app.controller('FirstController', function($scope, $log){ $log.info("FirstController:name →" + $scope.name); $log.info("FirstController:age →" + $scope.age); });
在本案例中,我们通过ng-init指令在$rootScope作用域对象中新增了两个属性,即name和age,接着使用ng-controller指令实例化FirstController控制器,此时AngularJS会创建一个子作用域对象继承自$rootScope,在FirstController控制器中输出子作用域对象的name和age属性。在浏览器中运行ch05_01.html页面,打开开发人员工具,控制台输出内容如下:
FirstController:name →jane FirstController:age →23
控制台中输出了name和age的属性值,说明控制器作用域对象确实继承了$rootScope作用域的属性。事实上$rootScope是所有作用域的父作用域(孤立作用域除外,后续会接触到)。
需要注意的是,我们可以在ng-controller指令所在的HTML元素开始与结束标签之间使用另外一个ng-controller指令实现作用域的嵌套,例如:
<div ng-app> <! -- 创建$rootScope作用域 --> <div ng-controller="FirstController"> <! --创建作用域(记为scope1)继承 $rootScope--> <div ng-controller="SecondController"> <! --创建作用域(记为scope2)继承 scope1--> </div> </div> </div>
在这种情况下,scope1作用域继承自$rootScope作用域,scope2作用域则会继承scope1作用域,$rootScope和scope1作用域中的属性在scope2作用域中均能访问。