AngularJS模块声明的最佳实践?

时间:2013-11-13 15:10:40

标签: angularjs

我在我的应用程序中声明了一堆Angular模块。我最初开始使用“链式”语法声明它们:

angular.module('mymodule', [])
    .controller('myctrl', ['dep1', function(dep1){ ... }])
    .service('myservice', ['dep2', function(dep2){ ... }])
    ... // more here

但我认为这不是很容易阅读,所以我开始使用这样的模块变量声明它们:

var mod = angular.module('mymodule', []);

mod.controller('myctrl', ['dep1', function(dep1){ ... }]);

mod.service('myservice', ['dep2', function(dep2){ ... }]);
...

第二种语法对我来说似乎更具可读性,但我唯一的抱怨是这种语法会将mod变量留在全局范围内。如果我有一个名为mod的其他变量,则会覆盖下一个变量(以及与全局变量相关的其他问题)。

所以我的问题是,这是最好的方法吗?或者做这样的事情会更好吗?:

(function(){
    var mod = angular.module('mymod', []);
    mod.controller('myctrl', ['dep1', function(dep1){ ... }]);
    mod.service('myservice', ['dep2', function(dep2){ ... }]);
    ...
})();

或者它是否足够关心?只是想知道模块声明的“最佳实践”是什么。提前谢谢。

7 个答案:

答案 0 :(得分:117)

宣布模块的“最佳”方式

由于angular位于全局范围本身且模块保存到其变量,因此您可以通过angular.module('mymod')访问模块:

// one file
// NOTE: the immediately invoked function expression 
// is used to exemplify different files and is not required
(function(){
   // declaring the module in one file / anonymous function
   // (only pass a second parameter THIS ONE TIME as a redecleration creates bugs
   // which are very hard to dedect)
   angular.module('mymod', []);
})();


// another file and/or another anonymous function
(function(){   
 // using the function form of use-strict...
 "use strict";
  // accessing the module in another. 
  // this can be done by calling angular.module without the []-brackets
  angular.module('mymod')
    .controller('myctrl', ['dep1', function(dep1){
      //..
    }])

  // appending another service/controller/filter etc to the same module-call inside the same file
    .service('myservice', ['dep2', function(dep2){ 
    //... 
    }]);

  // you can of course use angular.module('mymod') here as well
  angular.module('mymod').controller('anothermyctrl', ['dep1', function(dep1){
      //..
  }])
})();

不需要其他全局变量。

当然这完全取决于偏好,但我认为这是最好的做法,如

  1. 您不必污染全球范围
  2. 您可以随处访问您的模块,并随意将它们及其功能分类到不同的文件中
  3. 您可以使用“use strict”的功能形式;
  4. 文件的加载顺序无关紧要
  5. 对模块和文件进行排序的选项

    这种声明和访问模块的方式使您非常灵活。您可以通过功能类型(如另一个答案中所述)或通过路由对模块进行排序,例如:

    /******** sorting by route **********/    
    angular.module('home')...
    angular.module('another-route')...
    angular.module('shared')...
    

    如何对它进行排序最终取决于个人品味以及项目的规模和类型。我个人喜欢将模块的所有文件分组到同一文件夹中(命令为指令,控制器,服务和过滤器的子文件夹),包括所有不同的测试文件,因为它使您的模块更可重用。因此,在中型项目中,我最终会得到一个基本模块,其中包括所有基本路由及其控制器,服务,指令以及或多或少复杂的子模块,当我认为它们对其他项目也有用时,例如:

    /******** modularizing feature-sets **********/
    /controllers
    /directives
    /filters
    /services
    /my-map-sub-module
    /my-map-sub-module/controllers
    /my-map-sub-module/services
    app.js
    ...
    
    angular.module('app', [
      'app.directives',
      'app.filters',
      'app.controllers',
      'app.services',
      'myMapSubModule'
    ]);
    
    angular.module('myMapSubModule',[
       'myMapSubModule.controllers',
       'myMapSubModule.services',
       // only if they are specific to the module
       'myMapSubModule.directives',
       'myMapSubModule.filters'
    ]);
    

    对于非常大的项目,我有时最终会按路线对模块进行分组,如上所述,或者通过一些选定的主要路线或甚至路线和一些选定组件的组合,但这实际上取决于。

    修改 仅仅因为它是相关的并且我最近又碰到了一次:要小心你只创建一个模块(通过向angular.module函数添加第二个参数)。这会弄乱您的应用程序,并且很难检测到。

    2015 EDIT on sorting modules: 一年半的角度体验之后,我可以补充说,在你的应用程序中使用不同命名的模块带来的好处有些限制,因为AMD仍然无法很好地使用Angular和服务,指令和过滤器在角度内部全局可用无论如何(as exemplified here)。尽管如此,仍然存在语义和结构上的好处,并且可以包含/排除具有注释或注销的单行代码的模块。

    通过类型(例如'myMapSubModule.controllers')分离子模块几乎没有什么意义,因为它们通常相互依赖。

答案 1 :(得分:27)

我喜欢Johnpapa的angular-styleguide,这里有一些与此问题相关的规则:

规则:命名与匿名函数

避免使用匿名函数:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', function() { })

相反,使用命名函数:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', Dashboard);

function Dashboard() { }

正如作者所说:This produces more readable code, is much easier to debug, and reduces the amount of nested callback code.

规则:为每个文件定义1个组件。

避免在一个文件中包含多个组件:

angular
  .module('app', ['ngRoute'])
  .controller('SomeController', SomeController)
  .factory('someFactory', someFactory);

function SomeController() { }

function someFactory() { }

Intead,使用一个文件来定义模块:

// app.module.js
angular
  .module('app', ['ngRoute']);

一个文件只使用模块来定义组件

// someController.js
angular
  .module('app')
  .controller('SomeController', SomeController);

function SomeController() { }

和另一个定义另一个组件的文件

// someFactory.js
angular
  .module('app')
  .factory('someFactory', someFactory);

function someFactory() { }

当然,模块,控制器和服务还有许多其他非常有用且值得阅读的规则。

感谢ya_dimon的评论,上面的代码应该包含在IIFE中,例如:

(function (window, angular) {
  angular.module('app')
   .controller('Dashboard', function () { });
})(window, window.angular);

答案 2 :(得分:12)

我最近也有这个难题。我就像你使用链式语法一样开始,但从长远来看,它对于大型项目来说变得难以处理。通常我会在单独的文件中创建一个控制器模块,一个服务模块等,并将它们注入我在另一个文件中找到的主应用程序模块中。例如:

// My Controllers File
angular.module('my-controllers',[])
    .controller('oneCtrl',[...])
    .controller('twoCtrl',[...]);

// My Services File
angular.module('my-services',[])
    .factory('oneSrc',[...])
    .facotry('twoSrc',[...]);

// My Directives File
angular.module('my-directives',[])
    .directive('oneDrct',[...])
    .directive('twoDrct',[...]);

// My Main Application File
angular.module('my-app',['my-controllers','my-services','my-directives',...]);

但随着项目的发展,这些文件中的每一个都变得越来越大。所以我决定根据每个控制器或服务将它们分成单独的文件。我发现使用没有注入数组的angular.module('mod-name').是你需要的工作。在一个文件中声明一个全局变量并期望在另一个文件中随时可用它不起作用或者可能产生意外结果。

简而言之,我的应用程序看起来像这样:

// Main Controller File
angular.module('my-controllers',[]);

// Controller One File
angular.module('my-controllers').controller('oneCtrl',[...]);

//Controller Two File
angular.module('my-controllers').controller('twoCtrl',[...]);

我也对服务文件执行了此操作,无需更改主应用程序模块文件,您仍然会将相同的模块注入其中。

答案 3 :(得分:8)

另一种做法是在自己的模块中填充控制器,指令等,并将这些模块注入“主”模块中:

angular.module('app.controllers', [])
  .controller('controller1', ['$scope', function (scope) {
    scope.name = "USER!";
  }]);

angular.module('app.directives', [])
  .directive('myDirective', [function () {
    return {
      restrict: 'A',
      template: '<div>my directive!</div>'
    }
  }]);

angular.module('app', [
  'app.controllers',
  'app.directives'
]);

全球范围内没有任何内容。

http://plnkr.co/edit/EtzzPRyxWT1MkhK7KcLo?p=preview

答案 4 :(得分:4)

我喜欢分割我的文件和模块。

这样的事情:

app.js

var myApp = angular.module('myApp', ['myApp.controllers', 'myApp.directives', 'myApp.services']);

myApp.config(['$routeProvider', function($routeProvider) {
    /* routes configs */
    $routeProvider.when(/*...*/);
}]);

directives.js

var myDirectives = angular.module('myApp.directives', []);

myDirectives.directive( /* ... */ );

service.js

var myServices = angular.module('myApp.services', []);

myServices.factory( /* ... */ );

我不是“链式”的忠实粉丝,所以我更喜欢永远记下我的变量。

答案 5 :(得分:0)

对我来说,链接是最紧凑的方式:

angular.module("mod1",["mod1.submod1"])

 .value("myValues", {
   ...
 })

 .factory("myFactory", function(myValues){
   ...
 })

 .controller("MainCtrl", function($scope){

   // when using "Ctrl as" syntax
   var MC = this;
   MC.data = ...;
 })
 ;

这样我可以轻松地在模块之间移动组件,永远不需要两次声明相同的模块,从不需要任何全局变量。

如果文件太长,解决方案很简单 - 分成两个文件,每个文件在顶部声明自己的模块。为了提高透明度,我尝试为每个文件保留一个唯一的模块,并将其命名为类似于文件的完整路径。这样我也不需要编写没有[]的模块,这是一个常见的痛点。

答案 6 :(得分:0)

我建议关注Angularjs Style Guide 他们处理从命名约定到模块化应用程序等所有概念。

对于角度2,您可以查看Angular 2 Style Guide