事件监听器
首先,重要的是要理解有两种“事件监听器”:
范围事件监听器通过$on注册:
美元的范围。$on('anEvent',函数(事件,数据){
...
});
事件处理程序附加到元素,例如on或bind:
元素。On('点击',函数(事件){
...
});
范围。摧毁美元()
当执行$scope.$destroy()时,它将删除在该$scope上通过$on注册的所有侦听器。
它不会删除DOM元素或任何附加的第二类事件处理程序。
这意味着在指令的link函数中手动调用$scope.$destroy()不会删除通过for example元素附加的处理程序。on,也不是DOM元素本身。
element.remove ()
注意remove是一个jqLite方法(或者是一个jQuery方法,如果jQuery在AngularjS之前加载),并且在标准DOM元素对象中不可用。
当执行element.remove()时,该元素及其所有子元素将连同所有事件处理程序一起从DOM中删除,例如通过element.on附加。
它不会破坏与元素关联的$scope。
更让人困惑的是,还有一个jQuery事件叫做$destroy。有时,当使用第三方jQuery库删除元素时,或者手动删除它们时,您可能需要执行清理:
element.on('$destroy', function () {
scope.$destroy();
});
当指令被“销毁”时该怎么做
这取决于指令是如何被“销毁”的。
正常情况下,由于ng-view改变了当前视图,指令被销毁。当这种情况发生时,ng-view指令将销毁相关的$作用域,切断对其父作用域的所有引用,并在元素上调用remove()。
这意味着,如果该视图在被ng-view销毁时,它的link函数中包含一个带有This的指令:
scope.$on('anEvent', function () {
...
});
element.on('click', function () {
...
});
两个事件监听器都将被自动删除。
但是,需要注意的是,这些侦听器中的代码仍然可能导致内存泄漏,例如,如果您已经实现了常见的JS内存泄漏模式循环引用。
即使在这种由于视图改变而导致指令被破坏的正常情况下,也可能需要手动清理一些东西。
例如,如果你在$rootScope上注册了一个监听器:
var unregisterFn = $rootScope.$on('anEvent', function () {});
scope.$on('$destroy', unregisterFn);
这是必需的,因为$rootScope在应用程序的生命周期内永远不会被销毁。
如果你正在使用另一个发布/订阅实现,当$作用域被破坏时,它不会自动执行必要的清理,或者如果你的指令向服务传递回调,情况也是一样的。
另一种情况是取消$interval/$timeout:
var promise = $interval(function () {}, 1000);
scope.$on('$destroy', function () {
$interval.cancel(promise);
});
如果你的指令将事件处理程序附加到当前视图之外的元素,你也需要手动清理这些:
var windowClick = function () {
...
};
angular.element(window).on('click', windowClick);
scope.$on('$destroy', function () {
angular.element(window).off('click', windowClick);
});
这些是一些例子,说明了当指令被Angular“销毁”时该怎么做,比如被ng-view或ng-if。
如果你有自定义指令来管理DOM元素的生命周期等,当然会变得更复杂。