本网站只能被运行在支持JavaScript脚本的环境中

第六节 AngularJS中的模块及服务

本节介绍AngularJs中的模块及服务。

服务通常用于指定整个应用程序中的公共函数。

<!DOCTYPE html>
<html>
<head>
<title>AngularJS使用示例</title>
<script src="angular.min.js"></script>
<link rel="stylesheet" href="css/bootstrap.min.css">
<script>
var MyApp = angular.module('MyApp', []);
MyApp.service('MyAppSevrices', [function () {
    this.plus = function (x, y) {
        return (x + y);
    }
    this.minus = function (x, y) {
        return (x - y);
    }
    this.multiply = function (x, y) {
        return (x * y);
    }
    this.divide = function (x, y) {
        return (x / y);
    }
}]);
MyApp.controller('ServiceCtrl', function ($scope, MyAppSevrices) {
    $scope.x=20;
    $scope.y=10;
    $scope.plus = function() {
        return MyAppSevrices.plus(parseInt($scope.x), parseInt($scope.y));
    }

    $scope.minus = function() {
        return MyAppSevrices.minus(parseInt($scope.x), parseInt($scope.y));
    }

    $scope.multiply = function() {
        return MyAppSevrices.multiply(parseInt($scope.x), parseInt($scope.y));
    }

    $scope.divide = function() {
        return MyAppSevrices.divide(parseInt($scope.x), parseInt($scope.y));
    }
});
</script>
</head>
<body ng-app="MyApp">
    <div class="container">
        <div class="jumbotron">
            <h2>服务示例</h2>
        </div>
        <div ng-controller="ServiceCtrl">
            <input ng-model="x"><input ng-model="y">
            <div class="bg-info">
                <p>加法运算: {{plus()}}</p>
                <p>减法运算: {{minus()}}</p>
                <p>乘法运算: {{multiply()}}</p>
                <p>除法运算: {{divide()}}</p>
            </div>
        </div>
    </div>
</body>
</html>

可以利用模块的service方法注入多个服务。该方法使用两个参数,第一个参数值用于定义服务名,第二个参数值用于指定服务的构造函数,可以为一个数组,其中存放多个服务的构造函数。

在控制器的函数定义中,可以通过添加指定服务名的函数来引用该函数。

在示例脚本代码中,MyApp.service('MyAppSevrices', [function () {语句表示为MyApp模块定义MyAppSevrices服务。在该服务中分别定义了用于加法、减法、乘法、除法的公共函数。

MyApp.controller('ServiceCtrl', function ($scope, MyAppSevrices) {语句表示为MyApp模块注入ServiceCtrl控制器并且为该控制器使用MyAppSevrices服务。

在HTML代码中,通过将两个input元素的ng-model属性值分别指定为x及y将input元素的值与控制器作用域中的x变量与y变量值进行绑定。通过在四个p元素中分别调用控制器的plus函数、minus函数、multiply函数及divide函数,在这四个函数内部调用服务器中的plus函数、minus函数、multiply函数及divide函数来显示两个input元素值的加法值、减法值、乘法值及除法值。

定义多个模块

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var hogeModule = angular.module('hogeModule', []);
hogeModule.service('hogeService',function(){
    this.method=function(){
        return 'hoge service';
    };
})
var myApp = angular.module('myApp', ['hogeModule']);
myApp.run(function($rootScope,hogeService){
    $rootScope.message=hogeService.method();
});
</script>
</head>
<body>
<h1>{{message}}</h1>
</body>
</html>

在同一模块中调用多个服务

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.service('hogeService',function(){
    this.method=function(){
        return 'hoge service';
    };
})
myApp.service('fugaService',function(){
    this.method=function(){
        return 'fuga service';
    };
})
myApp.run(function($rootScope,hogeService,fugaService){
    $rootScope.hoge=hogeService.method();
    $rootScope.fuga=fugaService.method();
});
</script>
</head>
<body>
<h1>{{hoge}}</h1>
<h1>{{fuga}}</h1>
</body>
</html>

使用factory()方法注册服务

当服务的创建比较复杂时,可以使用factory()方法注册服务。

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.factory('sampleService',function(){
    return {
        method:function(){
            return 'sample service created by factory.'
        }
    };
});
myApp.controller('SampleController',function($scope,sampleService){
    $scope.message=sampleService.method();
});
</script>
</head>
<body ng-controller="SampleController">
<h1>{{message}}</h1>
</body>
</html>

模块所具有的方法

config与run

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.service('hoge', function() {
    this.method = function() {
        console.log('hoge');
    };
})
.config(function() {
    console.log('config');
})
.run(function(hoge) {
    console.log('run');
    hoge.method();
});
</script>
</head>
<body>
</body>
</html>

浏览器控制台输出

config
run
hoge

config函数将在控制器、指令、服务等与模块具有依赖关系的对象被创建之前首先被调用。

不能在config函数中依赖注入服务等对象(将抛出运行时错误)。

可以依赖注入provider对象。

run函数为控制器、指令、服务等与模块具有依赖关系的对象被创建之后调用的函数。

可以在run函数中依赖注入服务等对象。

constant与value

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.constant('hoge', 'HOGE')
.constant('fuga', {name: 'Fuga'})
.value('piyo', 'PIYO')
.config(function(hoge, fuga) {
    console.log('hoge = ' + hoge + ', fuga.name = ' + fuga.name);
    fuga.name = 'FUGA';
})
.run(function(hoge, fuga, piyo) {
    console.log('hoge = ' + hoge + ', fuga.name = ' + fuga.name+ ', piyo = ' + piyo);
});
</script>
</head>
<body>
</body>
</html>

浏览器控制台输出

config : hoge = HOGE, fuga.name = Fuga
run : hoge = HOGE, fuga.name = FUGA, piyo = PIYO 

constant方法与value方法均用于以“键名/键值”的形式定义模块内可以使用的值。

可以在config函数中依赖注入使用constant方法定义的值。

不能在config函数中依赖注入使用value方法定义的值。

两种方法定义的值均为变量值。

provider

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.constant('hoge', 'HOGE')
.provider('myHoge', function() {
    var _name;

    this.setName = function(name) {
        _name = name;
    };

    this.$get = function() {
        return {name: _name};
    };
})
.config(function(myHogeProvider) {
     myHogeProvider.setName('hoge');
})
.run(function(myHoge) {
    console.log(myHoge.name);
});
</script>
</head>
<body>
</body>
</html>

浏览器控制台输出

hoge

provider方法用于定义可被依赖注入的对象。

必须在provider对象中定义$get方法。

可依赖注入使用$get方法返回的对象。

AngularJS常用内置服务

执行定时处理

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.run(function($timeout) {
    var promise = $timeout(function() {
        console.log('hoge');
    }, 1000);

    console.log('fuga');

    promise.then(function() {
        console.log('piyo');
    });
});
</script>
</head>
<body>
</body>
</html>

浏览器控制台输出

fuga
hoge
piyo

$timeout()函数内部封装setTimeout()函数。

$timeout()函数的返回值为一个promise对象。

LOG输出

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.run(function($log) {
    $log.log('log');
    $log.debug('debug');
    $log.info('info');
    $log.warn('warn');
    $log.error('error');
});
</script>
</head>
<body>
</body>
</html>

浏览器控制台输出

$log服务用于向控制台输出。

在不支持window.console的浏览器中,也不会抛出错误。

默认输出debug级别的消息。

当不想输出debug级别的消息时可以采用如下所示的代码。

angular
.module('myApp', [])
.config(function($logProvider) {
    $logProvider.debugEnabled(false);
})
.run(function($log) {
    $log.log('log');
    $log.debug('debug');
    $log.info('info');
    $log.warn('warn');
    $log.error('error');
});

异常处理

<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.config(function($provide) {
    $provide.decorator('$exceptionHandler', function($delegate) {
        return function(exception, cause) {
            console.log('intercept');
            $delegate(exception, cause);
        };
    });
})
.controller('SampleController', function($scope) {
    notExists.method();
});
</script>
</head>
<body ng-controller="SampleController">
</body>
</html>

浏览器控制台输出

针对压缩的对策

在AngularJS中,需要依靠控制器名或服务名来进行依赖注入。

但是如果将源代码进行压缩,压缩工具往往将名称缩短为a等短名称。

因此,当调用以控制器名或服务名为基础来实现的依赖注入时,会抛出运行时错误。

针对这种情况,AngularJS中可以显式指定依赖关系的名称,代码如下所示:

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

myApp.controller('SampleController', ['$scope', function(s) {
    s.message = 'hoge';
}]);

这种方法采用匿名函数来定义控制器或服务并将其放置在数组中,从而避免了由于名称而导致的压缩问题。