Angularjs控制器函数vs指令函数

时间:2016-01-30 19:16:53

标签: angularjs angularjs-directive angularjs-controller

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

$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等..还考虑了表现。

这些通话方法有什么区别?什么是用作呼叫功能的最佳选择?

1 个答案:

答案 0 :(得分:2)

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

让我们看看你的每个例子:

控制器

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指令的完美方法。

带链接功能的指令

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);
  }
});

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

指令w / Click事件处理程序

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这样做的是六个,另一个是六个。