AngularJS使用$on、$emit和$broadcast在作用域之间进行交互
AngularJS中的作用域具有继承性,并且结构是嵌套的。也就是说,对于每个Angular应用或者ng-app来说,只有一个主作用域$rootScope,其他所有作用域都会继承这个主作用域,或者嵌套在这个主作用域内部。通常情况下,你会发现作用域之间不会共享变量,并且互相之间不会基于原型继承。
如果需要在两个作用域之间进行通信,应该怎么做呢?其中一种方法是:创建一个服务,这个服务在整个应用范围内是一个单例,并且所有作用域之间的交互都通过它进行。另一种方法是:通过作用域上的事件进行交互。但是,这样做存在一些局限性。例如,你通常不能向正在监听的所有作用域同时广播事件。你必须选择是和父节点交互还是和子节点交互。
下面是一个如何监听事件的例子,在例子中,Start System(星系)中的作用域对象正在等待并监听planetDestroyed事件。
scope.$on('planetDestoryed', function(event, galaxy, planet) { //自定义事件,这样星球就被摧毁了 scope.alertnearbyPlanets(galaxy, planet); });
事件监听器上的这些额外参数是从哪来的呢?我们来看一看,单个的星球是如何和它所属的Star System进行交互的:
scope.$emit('planetDestroyed', scope.myGalaxy, scope.myPlanet);
传递给$emit的附加参数将会被当作函数参数传递给监听器函数。同时,$emit只会从当前的作用域向上进行通信,所以星球上可怜的居民(如果他们自已带有作用域对象的话)不会意识到他们的星球正在被摧毁。
类似地,如果Galaxy(银河系)需要向下和它的子节点进行交互,那么在Star System作用域中,它应该像下面这样进行交互:
scope.$emit('selfDestructSystem', targetSystem);
然后正在监听此事件的整个Star Systems都需要检查targetSystem,并且决定它们自已是否需要根据所接收的指令进行自我毁灭操作:
scope.$on('selfDestructSystem', function(event, targetSystem) { if(scope.mySystem == targetSystem) { scope.selfDestruct(); //引爆!! } });
当然,在事件向上(或者向下)传播的路径上,有一种操作可能是非常必要的,那就是在特定的层级或者作用域上说:“够了,不允许你通过这里!”,或者其他可以阻止事件的默认行为。传递给监听器的事件对象上带有一些函数,它们可以实现以上需求,甚至可以支持更多操作。如下所示: