Angularjs 控制器函数 vs 指令函数

Angularjs controller function vs directive function

最近我一直在构建一些模块,其中一些我只使用控制器(控制器设置在我已经需要用来加载模板的现有指令中)来实现服务和视图之间的这种通信,因为示例:

$scope.callFunction = function(data) {
    factRequest = saveData(data);
};

我还注意到我可以在指令中执行此操作,如下所示:

link:function(scope) {
    scope.callFunction = function(data) {
        factRequest.saveData(data);
    }
}

//or..

link:function(scope, element, attr) {
    attrValue = attr.myValue;
    element.bind('click', function(attrValue) {
        factRequest.saveData(attrValue);
    });
}

//or even..

link:function(scope, element, attr) {
    attrValue = attr.myValue;
    element.bind('click', function(attrValue) {
        factRequest.saveData(attrValue);
    });

    var elButton = element.fin('span'); //for example
    elButton.bind('click', function(attrValue) {
        factRequest.saveData(attrValue);
    });
}

考虑一个场景,这是一个可重用的对象,例如,一个产品,它显示在多个页面上并具有通用功能,例如addFavoriteaddCartaddWishList等等。还要考虑性能。

这些调用方式有什么区别?用作调用函数的最佳选择是什么?

重申一下,您正在对单击事件调用服务方法,并且想知道放置该逻辑的最佳位置。

让我们看看您的每个示例:

控制器

angular.module('myApp').controller('MyController', function($scope, factRequest) {
  $scope.callFunction = function(data) {
    factRequest.saveData(data);
  };
});

首先,每当我发现自己将 $scope 注入控制器时,我都会质疑我的方法。这是因为如果您依赖于在子控制器中使用这些变量,则将变量添加到当前作用域会创建隐藏的依赖项——如果不是,则没有必要。

相反,您应该使用 controllerAs 语法并将函数添加到控制器本身。像这样:

angular.module('myApp').controller('MyController', function(factRequest) {
  var vm = this;
  vm.callFunction = function(data) {
    factRequest.saveData(data);
  };
});

...您可以像这样在模板中访问它:

<div ng-controller="MyController as vm">
  <input ng-model="vm.data">
  <button ng-click="vm.callFunction(vm.data)">
    Click Me!
  </button>
</div>

这是利用本机 Angular 指令的完美方法。

带Link函数的指令

angular.module('myApp').directive('myDirective', function(factRequest) {
  return {
    link: function(scope) {
      scope.callFunction = function(data) {
        factRequest.saveData(data);
      }
    }
  };
});

同样,我不喜欢这样,因为您要将函数添加到作用域中。如果你有一个指令并想向模板公开一些功能,你应该使用一个控制器。例如:

angular.module('myApp').directive('myDirective', function() {
  return {
    controller: 'MyDirectiveController',
    controllerAs: 'myDir',
    template: '<input ng-model="myDir.data">' +
      '<button ng-click="myDir.callFunction(myDir.data)">' +
      'Click Me!' +
      '</button>'
  };
}).controller('MyDirectiveController', function(factRequest) {
  var myDir = this;
  myDir.callFunction = function(data) {
    factRequest.saveData(data);
  }
});

这与第一个示例基本相同,只是它现在是一个可重用的组件。

带点击事件处理程序的指令

angular.module('myApp').directive('myDirective', function(factRequest) {
  return {
    link: function(scope, element, attr) {
      element.on('click', function() {
        factRequest.saveData(scope.$eval(attr.myValue));
      });
    }
  };
});

请注意,我在这里做了一些改动。一方面,事件处理函数获取事件对象作为其第一个参数,因此尝试传递 attr.myValue 是行不通的。另外,我调用 scope.$eval(),这是一种最佳实践,可以在 myValue 属性中使用 Angular 表达式。

我最喜欢这种方法,因为它不依赖于 ng-click 等其他指令的使用。换句话说,这个指令更独立。

我应该补充的一件事是,当元素从 DOM 中删除时,Angular 不会删除此事件侦听器。最佳做法是在您的指令之后进行清理,如下所示:

angular.module('myApp').directive('myDirective', function(factRequest) {
  return {
    link: function(scope, element, attr) {
      function onClick() {
        factRequest.saveData(scope.$eval(attr.myValue));
      }
      element.on('click', onClick);
      scope.$on('$destroy', function() {
        element.off('click', onClick);
      });
    }
  };
});

结论

从性能的角度来看,所有这些方法大致相同。前两个本身不添加任何观察者,但是 ng-clickng-model 这样做是六个,另一个是六个。