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权威指南》