AngularJS -- Module (模块)

点击查看AngularJS系列目录
转载请注明出处:http://www.cnblogs.com/leosx/


 

什么是AngularJS的模块

我们所说的模块,是你的AngularJS应用程序的一个组成部分,它可以是一个Controller,也可以是一个Service服务,也可以是一个过滤器(Filter),也可以是一个directive(指令)等等…都是属于一个模块!

大多数的应用程序都是有一个自己的函数入口方法Main ,用它来进行初始化,以及加载装配各个模块,然后这些模块的组合,构成了你的应用程序,对吧?

但是,but, AngularJS应用程序却不是这样的哦,它没有main 方法,没有函数入口。代替之的是在模块中指定声明这个模块在AngularJS应用程序中该如何去加载,启动。这种方法有以下几个优点:

1) 使用声明的方式,让人更加容易理解。

2) 你可以更加容易的让你的代码进行重用。

3) 模块的加载顺序就更加容易控制了。因为这些模块是延迟执行的。

4) 对于进行单元测试就变得更加的方便了。更加可靠,你只需要载入这个模块就可以进行测试了。

5) 端对端的测试中,你可以使用模块去重写配置。

 

还是看看代码最重要,直接上代码:

<div ng-app="myApp">
  <div>
    {{ 'World' | greet }}
  </div>
</div>
<script src="https://code.angularjs.org/1.3.0/angular.min.js"></script>
<script type="text/javascript">
  (function(){
    // declare a module
    var myAppModule = angular.module('myApp', []);

    // configure the module.
    // in this example we will create a greeting filter
    myAppModule.filter('greet', function() {
     return function(name) {
        return 'Hello, ' + name + '!';
      };
    });
})();
</script>

单元测试的代码:

it('should add Hello to the name', function() {
  expect(element(by.binding("'World' | greet")).getText()).toEqual('Hello, World!');
});

效果图:

module-01

 

有几个事情需要注意一下的:

1. 关于模块的API,点击这里

2. <div ng-app=”myApp”>引用了myApp 模块。 这既是告诉启动器,你使用了这个名为myApp的模块,当AngularJS启动的时候,它就会去加载力的这个模块。

3. 在 angular.module(‘myApp’, [] )中,有个空的数组,这个数组是myApp模块说依赖的模块的列表.

 

 

推存设置

上面的例子都是非常简单的。它不是大型应用。我们建议你将你的AngularJS应用程序碎片化,也就是让你的应用程序变成多个模块的组合,例如:

1.不同的业务,为一个模块。

2.一个模块中,包含很多可以重用的组件(特别是指令和过滤器,以后也可以使用的)

3.一个应用程序级别的模块,它依赖于上级的模块,并且它还包含有所有的初始化代码。。。

在Google上,有一个关于如何编写大型应用程序的文档,你可以点击这里查看。

当然咯!  上面的都是建议,你可以根据你的需求,进行量身定做。比如:

<div ng-app="xmpl">
  <div ng-controller="XmplController">
    {{ greeting }}
  </div>
</div>
<script src="https://code.angularjs.org/1.3.0/angular.min.js"></script>
<script type="text/javascript">
  (function(){
    angular.module('xmpl.service', [])

  .value('greeter', {
    salutation: 'Hello',
    localize: function(localization) {
      this.salutation = localization.salutation;
    },
    greet: function(name) {
      return this.salutation + ' ' + name + '!';
    }
  })

  .value('user', {
    load: function(name) {
      this.name = name;
    }
  });

angular.module('xmpl.directive', []);

angular.module('xmpl.filter', []);

angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter'])

  .run(function(greeter, user) {
    // This is effectively part of the main method initialization code
    greeter.localize({
      salutation: 'Bonjour'
    });
    user.load('World');
  })

  .controller('XmplController', function($scope, greeter, user){
    $scope.greeting = greeter.greet(user.name);
  });
})();
</script>

效果图:

module-02

 

 

模块的加载和依赖

一个模块,其实是一个在应用程序的引导程序中运行的,一个配置的集合和运行块的集合。

1. 配置模块,它可以在provider提供者中进行注册,还可以再配置应用阶段进行执行。只有provider和常量才能够被注入到配置块中去。这样做是为了防止在配置块没有配置完成之前,意外的实例化了服务,这是不被允许的。

2. 运行(run)块, 是在注入器被创建出来之后和被用于应用程序之后,进行执行的。只有实例对象和常量能够被注入到 运行(run )块当中。这样做的目的是为了防止在应用程序运行期间,增加,修改了系统配置。

来看看例子:

angular.module('myModule', []).
config(function(injectables) { // provider-injector
  // This is an example of config block.
  // You can have as many of these as you want.
  // You can only inject Providers (not instances)
  // into config blocks.
}).
run(function(injectables) { // instance-injector
  // This is an example of a run block.
  // You can have as many of these as you want.
  // You can only inject instances (not Providers)
  // into run blocks
});

 

 

配置块

其实在模块上有一些非常方便的方法,它们就相当于是一个 config 配置块,看例子:

angular.module('myModule', []).
value('a', 123).
factory('a', function() { return 123; }).
directive('directiveName', ...).
filter('filterName', ...);

// is same as

angular.module('myModule', []).
config(function($provide, $compileProvider, $filterProvider) {
  $provide.value('a', 123);
  $provide.factory('a', function() { return 123; });
  $compileProvider.directive('directiveName', ...);
  $filterProvider.register('filterName', ...);
});

当AngularJS在进行引导启动你的应用程序的时候,它会首先定义所有的常量。然后再在配置块中使用同一个 常量列表 去注册它们。

 

 

运行块(Run)

Run,我们这里叫运行块,它是最接近Main入口函数的一个方法。运行块(run) 是建立在AngularJS应用程序之上的。它会在所有的服务配置完毕,注入器被创建完毕之后执行。。 一个运行块(run block) 通常会包含着单元测试,正因如此,应该把他声明在一个独立的模块(module)当中,这样,就可以把单元测试给独立开来了。

 

 

依赖关系

一个模块,它知道所有它所依赖的其它模块,也就是说在它加载起来前,需要将它所依赖的其它所有模块给加载起来。换句换说,对于需要配置块的模块来说,配置块一定是在需要它的模块初始化之前就被初始化完毕了。 同样的,运行块(run block)也是这样的,一个模块,会且仅会被加载一次,无论有多少个模块引用了它,它都只会被加载一次的。

 

 

异步加载(Asynchronous Loading)

Modules are a way of managing $injector configuration, and have nothing to do with loading of scripts into a VM. There are existing projects which deal with script loading, which may be used with Angular. Because modules do nothing at load time they can be loaded into the VM in any order and thus script loaders can take advantage of this property and parallelize the loading process.(这句话实在翻译不了,英文太烂,有看到并且英文好的哥们儿,望帮忙翻译下)

 

 

创建和检索

在使用 angular.module(‘myModule’, [] )的时候得注意,它会创建一个叫做 myModule的模块,并且会覆盖掉所有之前叫做 myModule 的模块。  我们使用 angular.module(‘myModule’) 就可以去查找,检索我们已经创建的模块。来个例子:

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

// add some directives and services
myModule.service('myService', ...);
myModule.directive('myDirective', ...);

// overwrites both myService and myDirective by creating a new module
var myModule = angular.module('myModule', []);

// throws an error because myOtherModule has yet to be defined
var myModule = angular.module('myOtherModule');

 

 

单元测试

单元测试是一个很好的去初始化你的应用模块,并且调用它的一个小的应用。  有结构的模块对于单元测试时非常有用的,可以很好的找到关注重点。

一个模块只能在注入器(injector) 中被加载一次,且仅有一次。通常,一个Angular 应用程序只有一个 注入器(injector) 而且所有模块只会被加载一次。但是每个单元测试都会有自己的注入器(injector) ,而且模块可以被加载多次。 在我们的所有例子中,都遵循了模块定义的这个规则:

angular.module('greetMod', []).

factory('alert', function($window) {
  return function(text) {
    $window.alert(text);
  }
}).

value('salutation', 'Hello').

factory('greet', function(alert, salutation) {
  return function(name) {
    alert(salutation + ' ' + name + '!');
  }
});

 

我们来写一些单元测试,来看看在单元测试当中如何重写配置

describe('myApp', function() {
// load application module (`greetMod`) then load a special
// test module which overrides `$window` with a mock version,
// so that calling `window.alert()` will not block the test
// runner with a real alert box.
beforeEach(module('greetMod', function($provide) {
  $provide.value('$window', {
    alert: jasmine.createSpy('alert')
  });
}));

// inject() will create the injector and inject the `greet` and
// `$window` into the tests.
it('should alert on $window', inject(function(greet, $window) {
  greet('World');
  expect($window.alert).toHaveBeenCalledWith('Hello World!');
}));

// this is another way of overriding configuration in the
// tests using inline `module` and `inject` methods.
it('should alert using the alert service', function() {
  var alertSpy = jasmine.createSpy('alert');
  module(function($provide) {
    $provide.value('alert', alertSpy);
  });
  inject(function(greet) {
    greet('World');
    expect(alertSpy).toHaveBeenCalledWith('Hello World!');
  });
});
});
posted @ 2014-10-28 14:43  Entertainment  Views(8319)  Comments(0Edit  收藏  举报