AngularJS模块声明的最佳实践?

ten*_*ent 114 angularjs

我在我的应用程序中声明了一堆Angular模块.我最初开始使用"链式"语法声明它们,如下所示:

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

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

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

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

mod.service('myservice', ['dep2', function(dep2){ ... }]);
...
Run Code Online (Sandbox Code Playgroud)

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

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

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

或者甚至足够关心?只是想知道模块声明的"最佳实践"是什么.提前致谢.

hug*_*ige 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){
      //..
  }])
})();
Run Code Online (Sandbox Code Playgroud)

不需要其他全局变量.

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

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

用于对模块和文件进行排序的选项

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

/******** sorting by route **********/    
angular.module('home')...
angular.module('another-route')...
angular.module('shared')...
Run Code Online (Sandbox Code Playgroud)

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

/******** 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'
]);
Run Code Online (Sandbox Code Playgroud)

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

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

2015关于排序模块的编辑: 稍后一年半的角度体验,我可以补充说,在你的应用程序中使用不同命名的模块带来的好处有些限制,因为AMD仍然不能很好地使用Angular和服务,指令和过滤器无论如何都在角度上下文中全局可用(如此处举例说明的).尽管如此,仍然存在语义和结构上的好处,并且能够包含/排除具有注释或注释的单行代码的模块可能是有帮助的.

按类型(例如'myMapSubModule.controllers')分离子模块几乎从来没有多大意义,因为它们通常相互依赖.

  • 您不需要IIFE(立即调用函数表达式),也就是匿名自执行函数 (6认同)

aqi*_*sao 27

我喜欢Johnpapa角度风格指南,这里有一些与这个问题相关的规则:

规则:命名与匿名函数

避免使用匿名函数:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', function() { })
Run Code Online (Sandbox Code Playgroud)

相反,使用命名函数:

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

function Dashboard() { }
Run Code Online (Sandbox Code Playgroud)

正如作者所说: 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() { }
Run Code Online (Sandbox Code Playgroud)

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

// app.module.js
angular
  .module('app', ['ngRoute']);
Run Code Online (Sandbox Code Playgroud)

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

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

function SomeController() { }
Run Code Online (Sandbox Code Playgroud)

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

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

function someFactory() { }
Run Code Online (Sandbox Code Playgroud)

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

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

(function (window, angular) {
  angular.module('app')
   .controller('Dashboard', function () { });
})(window, window.angular);
Run Code Online (Sandbox Code Playgroud)


m.e*_*roy 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',...]);
Run Code Online (Sandbox Code Playgroud)

但随着项目的发展,这些文件中的每一个都变得越来越大.所以我决定根据每个控制器或服务将它们分成单独的文件.我发现在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',[...]);
Run Code Online (Sandbox Code Playgroud)

我也是这样做的服务文件,不需要更改主应用程序模块文件,你仍然会注入相同的模块.

  • 在大型项目中,当控制器/过滤器/指令/服务全部交错在一起时,很难找到.这只是保持组织有序的一种方式. (2认同)

Man*_*y D 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'
]);
Run Code Online (Sandbox Code Playgroud)

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

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