angular什么时候销毁指令实例?

时间:2016-07-15 15:28:14

标签: angularjs

我创建了一个指令,它绑定到链接函数中的$stateChangeSuccess个事件:

module.exports = angular.module("titlePanel", [])
    .directive("titlePanel", titlePanel);

function titlePanel($state, $rootScope, $parse, $interpolate) {
return {
    restrict: "E",
    replace: false,
    scope: true,
    templateUrl: template,
    link: function(scope, element, attrs) {

        // some actions
        // ...

        $rootScope.$on("$stateChangeSuccess", function(){
            console.log("State change success happened on titlePanel");
        });
    }
}

此指令仅用于我网站的某些页面。令我惊讶的是,当我从包含该指令实例的状态转换到不再包含它的状态时,指令仍然响应$stateChangeSuccess事件并执行console.log()

我相信,在转移到特定状态时,我误解了事件的时间顺序(我使用ui-router)。我认为如下:

  1. ui-router开始切换到新状态
  2. 它解析并加载新状态控制器
  3. 的依赖关系
  4. 它实例化新控制器
  5. 遍历新控制器模板的代码并检测其中的指令
  6. 如果这些指令尚未编译并存储在模块注册表中,则会编译这些指令
  7. 它通过创建指令范围并调用link链接功能
  8. 来创建指令实例
  9. 它会破坏先前的状态,先前的控制器/范围以及为前一个控制器构建的指令实例
  10. 它会发出$ stateChangeSuccess
  11. 我可能在某处错了。你能描述正确的事件顺序吗?

1 个答案:

答案 0 :(得分:2)

一旦指令不再在DOM中表示,它们就会被销毁。 (如果它们不可见,它们会持续存在,因此ng-show=false会隐藏但不会破坏指令; ng-if=false会将其销毁。)

可是:

$rootScope.$on("$stateChangeSuccess", function(){
    console.log("State change success happened on titlePanel");
});

这会将事件附加到rootScope,这在应用程序的整个生命周期中都会持续存在,即使在指令消失之后也是如此。

您可以通过在指令的'destroy'方法上显式分离事件来阻止这种情况:

var unbinder = $rootScope.$on("$stateChangeSuccess", function() {
    console.log("State change success happened on titlePanel");
});
scope.$on('$destroy', function() {
    unbinder();
});

...或者更好的是,通过将事件附加到指令的范围而不是根范围,因此它将自动清理。 (通常不好的做法是在不是绝对必要时避免使用根作用域:而是将事件绑定到它们所属的指令,或者绑定到专门用于此目的的共享工厂或服务。)