如何在AngularJS中销毁$emit和$broadcast事件?
如何在AngularJS中销毁$emit和$broadcast事件?
Plnkr实例构建:http://plnkr.co/edit/gB7MtVOOHH0FBJYa6P8t?p=preview
根据这里的答案,我创建了一些$broadcast事件,以允许在主$rootScope中的操作关闭子$scopes中的弹出框。但是,我想确保清理所有事件,不留下任何不应该存在的东西。
我有一个弹出框指令,一旦弹出框被激活,我会发送:
vs.$emit('popoverOpen');
然后在主应用程序模块($rootScope)中,我在这里进行监听:
vs.$on('popoverOpen',function(events,data) { // if 'popoverOpen' is heard, then activate this function // which on click $broadcasts out even 'bodyClick' // but also destroy the 'popoverOpen' event vs.bodyClick = function() { $rootScope.$broadcast('bodyClick'); $rootScope.$$listenerCount.popoverOpen=[]; }; });
回到弹出框指令,这是我的bodyClick监听器:
vs.$on('bodyClick', function() { vs.searchPopoverDisplay = false; $rootScope.$$listenerCount.bodyClick=[]; });
^我也在那里尝试了杀死bodyClick事件的代码,但是没有效果 🙁
如下所示,我已经从$$listenerCount中移除了bodyClick和popoverOpen($$listener对象中从未有任何东西)。
但是,即使popoverOpen应该已被删除,用户仍可以访问主应用程序rootScope中的vs.bodyClick()函数。
因此,在首次加载时:
- 如果用户在不打开任何弹出框的情况下单击,将不会捕获/传输bodyClick事件
- 打开弹出框后,bodyClick变为活动状态
- 如果用户单击主体,该事件被发送出去并关闭弹出框
- 然而,现在即使没有打开任何弹出框,如果用户单击主体,则该bodyClick事件仍然会被发送出去
如何正确地移除bodyClick事件在发送出关闭弹出窗口之后?
更新 我也尝试了这个(https://github.com/toddmotto/angularjs-styleguide#publish-and-subscribe-events), 但是在弹出窗口关闭并且被销毁之后,bodyClick事件仍然被发送出。
popoverDirective函数依然被调用:
vs.$on('bodyClick', function() { console.log('bodyClick received ...'); console.log($rootScope.$$listener); console.log($rootScope.$$listenerCount); vs.searchPopoverDisplay = false; var unbind = $rootScope.$on('popoverOpen', []); vs.$on('$destroy', unbind); // $rootScope.$$listenerCount.bodyClick=[]; });
关于您的代码片段,有一些需要注意的地方:
- 您的控制器没有超出作用域,因此没有触发
$destroy
事件。 - 您在监听
$destroy
事件,但尝试触发destroy
,这是不一样的。移除监听器中的$
符号,就能看到回调函数在执行了。 - 由于
subController
是mainController
的子级,摧毁主控制器,两个控制器也都被销毁了,包括按钮和其他所有对象。此现象可在此代码片段中看到。
因此,为了激发虚假的$destroy
事件,我将其改为仅监听destroy
事件。
然后,我没有调用您的解除绑定方法,因为在这种情况下我们并没有真正摧毁任何对象,而是仅仅将bodyClick
函数进行了替换,因为它被绑定在了上。
$scope.$on('destroy', function() { $scope.bodyClick = angular.noop(); });
这样做好像达到了预期效果。这是更新后的代码片段。
更新:我发现了一点,那就是它一直在不断添加监听器……!destroy
监听器出现在按钮回调函数中。因此,每次按下按钮都会添加一个新的回调函数。我将destroy
监听器移到了popover
监听器之外。现在已经没有内存泄漏的问题了!