每次创建角度控制器时,我都会添加一个事件监听器。每次我离开这个页面并返回它时,都会添加一个新的事件监听器,因为再次调用构造函数。
当这个事件被触发时,相同的事件被调用两次,如果我离开并返回,它会被调用3次......等等。我只希望它总是被调用一次。
以下是添加事件侦听器的代码,以及它调用的Listener函数: (仅供参考我使用的是TypeScript)
在构造函数中:
this.$window.addEventListener("message", this.processApi, false);
被调用的函数:
processApi = (e) => {
this.processApiMessage(e.data);
};
我读到我应该调用一个函数的引用而不是键入函数本身,所以它们都引用了一个函数的同一个实例,但同一个事件监听器被多次调用。
当我在chrome中使用开发人员工具,并转到EventListners,并转到消息部分时,每次点击构造函数时都会看到一个新的Window元素。我可以通过开发人员工具删除每个EventListers,但是当我这样做时似乎无法通过代码来完成它:
this.$window.removeEventListener("message", this.processApi, false);
我发现如果我刷新页面,所有的事件监听器都会清除,而构造函数中的那个会被创建,所以它可以正常工作。
我正在使用angular,并使用$ location服务导航到击中我的控制器的url,因此快速解决方法是将$ location.url(“url”)替换为window.location.href(“ URL“)
这似乎有效,因为当我导航到页面时页面会刷新。我宁愿保留$ location用于路由,并且只有一次我的事件监听器被命中,即使角度构造函数被多次命中。
答案 0 :(得分:3)
当范围为$destroyed
时,您需要删除事件侦听器。因此,在控制器构造函数中,您需要注入$scope
对象。在构造函数中,执行以下操作:
$scope.$on('$destroy', () =>
$window.removeEventListener("message", this.processApi));
可以肯定的是,有几种方法可以创建控制器。最常见的一个(特别是如果你使用的是TypeScript)是为控制器创建一个类。
我还会考虑将监听器添加到rootScope而不是$ window,这更像是Angular的处理方式。总而言之,它看起来像这样:
class MyController {
constructor($rootScope, $scope) {
'ngInject';
let unsubscriber = $rootScope.$on('message', this.processApi, false);
$scope.$on('$destroy', () => unsubscriber());
}
...
}