本文共 3946 字,大约阅读时间需要 13 分钟。
本节书摘来自华章出版社《AngularJS实战》一 书中的第3章,第3.4节,作者:陶国荣,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
与页面中DOM模型相似,作用域在绑定页面元素后,便依据元素的层次关系形成了自身的层级关系,而在这些层级关系中,它们还可以通过事件的传播进行数据的通信,只是这种通过事件的数据通信应用的场景非常有限,仅限于父和子级之间的作用域,接下来我们逐一进行分析。
与DOM树状结构类似,作用域也拥有自己的层级,并且与DOM的树状结构相辅相成,它的顶级作用域只有一个,而下面的子级作用域可以创建多个,子级作用域可以继承父级作用域中的全部属性和方法,但同级别子级作用域之间却不可以互相访问各自的属性和方法。接下来,我们通过一个完整的示例来详细介绍作用域的层级关系。
示例3-8 作用域的层级(1)功能描述以列表的方式分组显示一个学校的两个班级学生信息,两个班级各为一个作用域,而学校则为顶级作用域,两个班级的作用域可以访问顶级作用域中的全部属性。(2)实现代码新建一个HTML文件3-8.html,加入如代码清单3-8所示的代码。代码清单3-8 作用域的层级作用域的层级
- { {s_name}}{ {c_name}}
- 序号 姓名 性别 英语 数学
- { {$index+1}} { {stu.name}} { {stu.sex}} { {stu.english}} { {stu.maths}}
- { {s_name}}{ {c_name}}
- 序号 姓名 性别 英语 数学
- { {$index+1}} { {stu.name}} { {stu.sex}} { {stu.english}} { {stu.maths}}
(3)页面效果
执行HTML文件3-8.html,最终实现的页面效果如图3-8所示。(4)源码分析
在本示例源代码的控制器中,分别定义了3个控制器函数“c3_8_school”“c3_8_class_1”和“c3_8_class_2”,而在页面中通过向元素属性添加“ng-controller”指令来绑定这些函数,根据这些添加指令元素的DOM层次关系,便形成了作用域的层级关系。在本示例作用域的层次关系中,“c3_8_school”控制器属于父级,其余两个控制器属于子级,隶属于父级,因此,它们可以直接继承父级作用域中通过“$scope”对象添加的属性或方法,即“s_name”“bold”和“school”属性,如果在父作用域中又通过“$rootScope”对象添加了属性或方法,那么子级作用域将首先访问“$scope”对象,然后再访问“$rootScope”对象。在子级作用域的视图模板中,当页面渲染“s_name”属性值时,首先,它在取值阶段,将在元素本身所属的作用域中寻找是否存在该属性,如果不存在,则继续向上级作用域中查找,如果都没有找到,则直接在顶级的“$rootScope”对象中查找,确定属性的作用域之后,再进入计算值阶段,计算后,直接将获取的值渲染在页面的元素中。需要说明的是,每个作用域都会自动添加一个类别名为“ng-scope”的CSS样式,因此,可以通过修改该样式,来显示各作用域所控制的范围区域。通过前面内容的介绍,我们知道,在Angular中,作用域间有非常清晰的层次结构关系,类似于DOM树状图形,最顶层的就是rootscope作用域,其余的都是在它基础之上进行分支和嵌套的。在这种关系下的作用域,它们之间的数据通信变得相对复杂,概括来说,有下列两种方式可以实现作用域的通信。
1.?服务(service)通过在作用域间创建一个单例的服务,由该服务来处理各个作用域间的数据通信,这种方式在后续章节中介绍服务概念时,将进行详细的介绍。2.?事件(event)除使用服务外,还可以通过作用域间的事件进行数据通信,而要使用事件,则必须调用Angular中提供的两个方法$broadcasted和$emitted,方法$broadcasted的功能是将事件从父级作用域传播至子级作用域,它的调用格式如下。$broadcast(eventname, data)
其中,参数eventname为定义的事件名称,data为事件传播过程中携带的数据信息。
方法$ emitted的功能是将事件从子级作用域传播至父级作用域,它的调用格式如下。$emitted(eventname, data)
各参数的功能与$broadcasted相同,在此不再赘述。此外,除这两个传播事件的方法外,还需要通过调用$on方法,在作用域中监控传播来的事件并获取相应的数据,它的调用格式如下。
$on(eventname, function(event,data){ // 接收传播事件的处理代码})
在上述调用格式中,eventname为需要监控的传播事件名称,event为事件传播过程中自带的特征,该特征包括下列几个重要的属性,如表3-1所示。
而在$on方法处理传播事件的函数中,另外一个data参数,则为事件在传播过程中携带的数据,通过该对象可以在各个监控的作用域中获取传播时的数据,实现数据通信的功能。
虽然说通过作用域的事件可以实现数据通信的功能,但是它们的传播范围非常有限,只能是调用$broadcasted和$emitted这两个方法,在父和子级的作用域间进行传播,其他不具有这种关系的作用域将无法监控到传播来的事件。接下来,我们通过一个完整的示例来说明这点特征。示例3-9 作用域事件的传播(1)功能描述在页面中添加两个功能按钮,分别执行$broadcasted和$emitted方法,进行自定义事件的传播,然后在各个作用域中通过$on方法监控事件传播的状态,并将接收后的数据显示在控制台中。(2)实现代码新建一个HTML文件3-9.html,加入如代码清单3-9所示的代码。代码清单3-9 作用域事件的传播作用域事件的传播
(3)页面效果
执行HTML文件3-9.html,最终实现的页面效果如图3-9所示。(4)源码分析
在本示例的JavaScript代码中,定义了多个控制器,并通过ng-controller指令将它们与页面中的各个作用域相绑定,在其中名为“c3_9_s”的控制器中,添加了两个方法to_parent和to_child,分别用于在单击页面中两个按钮时调用。在to_parent方法中,直接调用Angular中的$emit方法,向父作用域传播“event_1”事件和“事件来源于子级”的字符串数据,而在to_child方法中,则是调用Angular中的$broadcast方法,向子作用域传播“event_2”事件和“事件来源于父级”的字符串数据;在其他的控制器中,则是通过调用$on方法接收其他作用域传播来的事件和数据,并将数据显示在浏览器控制台中。虽然除“c3_9_s”的控制器外,都通过$on方法接收其他作用域传播来的事件和数据,但当用户在页面中单击第一个按钮时,只有父级作用域才接收到了子作用域传播来的“event_1”事件和相应字符串内容,其他作用域都没有接收到。因此,只在浏览器控制台中显示“在父级中监听到事件来源于子级”的字样,效果如示意图3-9所示。当用户单击页面中的第二个按钮时,也只有在子级作用域才接收到了父级作用域传播来的“event_2”事件和相应字符串内容,其他作用域同样也都没有接收到,通过这个示例,我们清楚地看到,通过作用域中的事件传播数据的功能非常有限,只能调用Angular中的$emit和$broadcast方法,在父级和子级作用域中进行事件数据的传递,这点在代码开发时需要注意。转载地址:http://ifmia.baihongyu.com/