Angular 控制器生命周期和事件处理

Posted

技术标签:

【中文标题】Angular 控制器生命周期和事件处理【英文标题】:Angular controller lifetime and event handling 【发布时间】:2016-11-05 09:28:55 【问题描述】:

如何正确处理 Angular 控制器中的事件(如$rootScope 或套接字事件)?我面临的问题是我的控制器没有被销毁,这在监听特定事件时会导致一些问题。

为了明确我的意思,这里是一个笨蛋:http://plnkr.co/edit/CkXKUnpUdsbnZEjq8zLy?p=preview

首先触发 rootscope 事件(通过单击按钮)按预期工作:只获取一个事件。但是导航到Route 2 并再次触发 rootscope 事件显示了我的问题;该事件被获取了两次,因为(至少这是我的猜测)两个控制器现在都处于活动状态。每个路由切换都会导致一个额外的事件监听器。

如何处理?

【问题讨论】:

【参考方案1】:

使用$scope.$on而不是$rootScope.$on,监听器会在作用域销毁时自动销毁。

【讨论】:

好的,这很有帮助,谢谢。只剩下一个问题:这是否意味着像套接字事件(socket.on('event',...))这样的事情需要放在服务中而不是控制器中?由于监听套接字事件的行为与监听$rootScope 事件的行为相同,并且可以多次触发。【参考方案2】:

JosselinTD 给出的答案是正确的。如果在 $rootScope 上广播了一个事件,那么在您各自的控制器的 $scope 上监听就足够了,因为在层次上低于触发事件的范围的所有范围上触发了广播,并且所有其他范围都位于 $rootScope 下方的某个位置.

如果这不是一个选项,例如因为你想捕捉一个发出的事件(使用 $emit 方法而不是 $broadcast)并且不通过你的 $scope,你实际上也可以在 $rootScope 上监听。但是,在这种情况下,您必须确保在销毁控制器的作用域时清除侦听器:

var removeListener = $rootScope.$on('yourEvent', function(event) 
  // do what you want here..
);
// remove the listener on $rootScope when $scope is cleaned up
// this makes sure we have no unwanted references..
$scope.$on('$destroy', removeListener);

$on 方法返回一个允许删除由它创建的侦听器的函数。当控制器被销毁时(例如,因为它的视图被其他东西替换),AngularJS 将在你的 $scope 上调用 $destroy 事件。

如果您在控制器中收听非角度事件,您还应该使用

$scope.$on('$destroy', function() 
   //TODO: call some clean-up function to remove your event listener
 );

这可能是 socket io listener removal (***) 中所述的侦听器删除

另一个可能有用的提示:如果您正在侦听来自 AngularJS 上下文之外的事件(这适用于例如 DOM 事件,但当然也适用于 socket.io 事件),您必须将它们包装在 $ scope.$apply 否则 AngularJS 将不知道事件监听器带来的任何变化。

socket.on('someSocketEvent', function(data) 
  $scope.$apply(function() 
    $scope.dataFromSocket = data;
  );
); 

【讨论】:

以上是关于Angular 控制器生命周期和事件处理的主要内容,如果未能解决你的问题,请参考以下文章

如何在Angular中销毁Nativescript生命周期的applicationOn事件

生命周期函数事件处理函数和API

Ionic 4 迁移:Ionic 3 生命周期事件/导航守卫的 Angular 等价物是啥?

处理 Angular 4 生命周期钩子

[译] ASP.NET 生命周期 – ASP.NET 请求生命周期

Angular 5 中服务的生命周期是啥