AngularJS 事件系统并不与浏览器的事件系统相通,这意味着,我们只能在作用域上监听 AngularJS 事件而不是 DOM 事件。由于作用域是有层次的(既是继承关系),所以可以在作用域链上传递事件。在传递事件前,需要先了解触发事件的作用域和处理事件的作用域的关系,这样我们才可以判断事件是向上传递还是向下广播。
a. 事件如何传播
什么时候需要向上传递事件?当处理事件的作用域为触发事件的作用域的父级作用域时,就需要将事件向上传递。同理,当处理事件的作用域为触发事件的作用域的子级作用域时,就需要将事件向下传递。
1. 使用$emit
向上传递事件
使用$emit
将事件沿着作用域链向上传递,即从子作用域到父作用域。
语法:
scope.$emit(name, args)
参数:
name
类型:String
,要触发事件的名称。
args
参数集合,可以是一个也可以是多个,作为对象传递到事件监听者中。
eg-1:1
$scope.$emit('just-test-emit', ['first'], ['second']);
- eg-1中,
just-test-emit
为事件名称,而[first]
和[second]
为传递到事件监听者中的参数。 - 在
$emit()
事件函数调用后,事件会从子作用域冒泡到父作用域。在触发事件的作用域之上的所有作用域都会收到这个事件的通知。
2. 使用$broadcast
向下广播事件
$broadcast
和$emit
用法很类似,只是$broadcast
是将事件沿着作用域向下传递,即从父作用域到子作用域。
语法:
scope.$broadcast(name, args)
参数:
name
类型:String
,要触发事件的名称。
args
参数集合,可以是一个也可以是多个,作为对象传递到事件监听者中。
eg-2:1
$scope.$broadcast('just-test-broadcast', ['first'], ['second']);
- 在
$broadcast()
事件函数调用后,每个在子作用域注册了事件的监听者都会收到这个事件通知。
3. 使用$on
监听事件
使用$on
根据事件的名称,注册一个监听者。同时$on
函数会返回一个反注册函数,我们可以通过调用这个反注册函数取消事件监听者。
语法:
scope.$on(name, listener)
参数:
name
类型:String
,要监听的事件名称。
listener
类型:Function
,事件监听者。
函数的格式:function(event, args...)
,AngularJS会把event
对象作为第一个参数传给正在监听事件的监听者(不管是自定义的事件还是AngularJS内置的事件)。args
为触发事件时传递给事件监听者的参数集合。event
(事件)对象属性:
event.targetScope
类型:Scope
,表示事件触发所在的那个作用域。
event.currentScope
类型:Scope
,当前事件处理的作用域。
event.name
类型:String
,事件的名称。
event.stopPropagation
类型:Function
,调用后会取消事件的冒泡,也就是取消通过$emit
触发的事件进一步在作用域链上向上传递。
event.preventDefault
类型:Function
,调用后会将defaultPrevented
设置为true
,同时告诉子作用域无需处理这个事件,但是不能阻止事件的传播。
event.defaultPrevented
类型:Boolean
。
b. 事件相关的核心服务
- 核心系统的
$emitted
事件
下面的事件从指令向上传递到包含指令调用的作用域。
1. $includeContentRequested
这个事件从调用ngInclude
的作用域向上传递。每次ngInclude
的内容被请求时,都会被触发。
2. $includeContentLoaded
当ngInclude
的内容重新加载时,将会从ngInclude
指令上触发。
3. $includeContentError
当HTTP请求模板错误时触发。
4. $viewContentLoaded
每当ngView
内容被重新加载时,将会从当前ngView
作用域向上传递事件。
- 核心系统的
$broadcast
事件
1.$locationChangeStart
当 AngularJS 从 $location 服务(通过$location.path()、$location.search()等)对浏览器的地址作更新时,会触发$locationChangeStart
事件。
2.$locationChangeSuccess
当且仅当浏览器的地址变更成功后,同时又没有阻止$locationChangeStart
事件的情况下,$locationChangeSuccess
事件会从$rootScope
作用域向下广播出来。
3.$routeChangeStart
在路由变更发生之前,$routeChangeStart
事件会从$rootScope
作用域广播出来。也就是在路由服务开始解析路由变更所需的所有依赖项时。
4.$routeChangeSuccess
在所有路由依赖项跟着$routeChangeStart
被解析后,$routeChangeSuccess
事件就会从$rootScope
作用域上广播出来。ngView
指令使用$routeChangeSuccess
事件来获悉何时实例化控制器并渲染视图。
5.$routeChangeError
如果路由对象上任意的resolve
属性被拒绝,$routeChangeError
就会被触发。
6.$routeUpdate
如果$routeProvider
上的reloadOnSearch
属性被设置成false,并且使用了控制器的同一实例,$routeUpdate
就会被触发,同时会从作用域$rootScope
向下传递。
7.$destroy
在作用域被销毁之前,$destroy
事件会在作用域上广播,这样子作用域在父作用域被真正移除之前可以先清理自身。
例如,如果在控制器中有一个正在运行的$interval
,我们不希望在包含它的控制器已经不存在的情况下,它还继续触发,就可以在作用域销毁前,先取消掉$interval
。
1 | var autoPolling = $interval(function() { |
参考
- 《Angular JS权威指南》