Angular中的服务
在Angular中,服务的本质是一些和控制器捆绑在一起的可替换的对象,通过这些对象提供了在应用的整个生命周期都存有数据的方法,当重载或刷新页面时,数据不会被清除,而且还与加载之前保持一致。
Angular服务介绍
在Angular中服务是一种单例对象。服务主要的功能是为实现应用的功能提供数据和对象。它又可以分为内置服务和自定义服务
内置服务
Angular提供了很多内置服务,如$scope
、$http
、$window
、$location
等。
html:
<div ng-controller="MyController">
<div>当前的地址是: {{url}}</div>
<button ng-click="onclick()">显示地址</button>
</div>
var myapp = angular.module('MyApp', []);
myapp.controller('MyController', ['$scope', function($scope){
$scope.onclick = function () {
$scope.url = $location.absUrl();
}
}])
$location
服务除了包含absUrl()
方法外,还有search()
和path()
等方法。同时它还提供了$locationChangeStart
和$locationChangeSuccess
方法
自定义服务
自定义服务有两种方法,一是使用内置的$provider
服务,另一种是调用模块(Module)中的服务注册方法,如factory
、service
、constant
和value
等方法
html:
<div ng-controller="myCtrl">
<div>服务返回的值:
<span>{{info('name')}}</span>
<span>{{info('sex')}}</span>
<span>{{info('score')}}</span>
</div>
</div>
javascript:
var app = angular.module('myApp', []);
app.factory('$output', function () {
var stu = {
name: '张三',
sex: '男',
score: 60
}
return stu;
});
app.controller('myCtrl', ['$scope', '$output', function ($scope, $output) {
$scope.info = function (n) {
for (_n in $output) {
if (_n == n) {
return ($output[_n]);
}
}
}
}]);
创建Angular服务
在Angular中创建自定义服务,只需要先构建一个模块(Module),然后在构建过程中调用内置的$provide
服务,通过该服务的工厂函数来创建属于自己的Angular服务。除此之外,还可以调用模块中的factory
、service
、constant
、value
方法来创建。
使用factory
方法自定义服务
在Angular中,最常用的创建自定义服务的,就是factory
方法了
app.factory(name, fn);
html:
<div ng-controller="MyController">
<div>{{str('我是factory返回的内容')}}</div>
<div>{{name(1)}}</div>
</div>
javascript:
var myapp = angular.module('MyApp', []);
myapp.factory('outfun', function () {
return {
str: function (s) {
return s;
}
}
});
myapp.factory('outarr', function () {
return ['张三', '李四', '王五'];
});
myapp.controller('MyController', function ($scope, outfun, outarr) {
$scope.str = function (n) {
return outfun.str(n);
}
$scope.name = function (n) {
return outarr[n];
}
});
使用service
方法自定义服务
使用service
方法也可以自定义服务,与factory
不同的是,它可以接受一个构造函数
app.service(name, fn)
其中,fn为构造函数,当注入该服务时,通过该函数并使用new关键字来实例化服务对象
html:
<div ng-controller="MyController">
<div class="show">姓名: {{name}}</div>
<div class="show">邮件: {{email}}</div>
<div class="show">{{title}}</div>
<button ng-click="say()">主题</button>
</div>
javascript:
var myapp = angular.module('MyApp', []);
myapp.service('student', function () {
this.name = 'Kaindy',
this.email = 'kaindy7633@163.com',
this.say = function () {
return 'Hello, Angular!';
}
});
myapp.controller('MyController', ['$scope', 'student', function ($scope, student){
$scope.name = student.name;
$scope.email = student.email;
$scope.say = function () {
$scope.title = student.say();
}
}]);
使用constant和value方法自定义服务
使用constant
和value
方法创建服务,常用于返回一个常量。
app.constant(name, value)
app.value(name, value)
html:
<div ng-controller="MyController">
<div class="show">图书ISBN号: {{BOOK}}</div>
<div class="show">美元兑换价: {{USD}}</div>
</div>
javascript:
var myapp = angular.module('MyApp', []);
myapp.constant('$ISBN', {
BOOK: '9898733238'
});
myapp.value('$RATE', {
USD: 614.28
});
myapp.controller('MyController', function($scope, $ISBN, $RATE){
var n = 600;
angular.extend($RATE, {USD: n});
$scope.BOOK = $ISBN.BOOK;
$scope.USD = $RATE.USD;
})
管理服务的依赖
添加自定义服务依赖项方法
我们在自定义服务时,会添加其他各类对象或服务,有下面三种方式:
(1) 隐式声明
在参数中直接调用,但这种方式在代码压缩时注入的对象可能会失效
app.factory('ServiceName', function(dep1, dep2) {})
(2) 调用$inject
属性
将需要注入的服务对象包装成一个数组,作为$inject
的属性值,但这种方式效率很低
var sf = function(dep1, dep2) {};
sf.$inject = ['dep1', 'dep2'];
app.factory('ServieceName', sf);
(3) 显式声明
在创建服务的函数中,添加一个数组,在数组中按顺序声明需要注入的服务或对象名称,这种方式既高效也不会丢失代码,推荐使用
app.factory('ServiceName', ['dep1', 'dep2', function(dep1, dep2) {} ])
html:
<div ng-controller="MyController">
<div class="show">你选择的是:{{result}}</div>
<button ng-click="confirm('你真的要删除这条记录吗?')">删除</button>
</div>
javascript:
var myapp = angular.module('MyApp', []);
myapp.service('notify', ['$window', function ($win) {
return function (msg) {
return $win.confirm(msg) ? '确定' : '取消';
}
}]);
myapp.controller('MyController', ['$scope', 'notify', function ($scope, notify) {
$scope.confirm = function (msg) {
$scope.result = notify(msg);
}
}]);
嵌套注入服务
在Angular中,有时需要将一个自定义的服务注入到另一个自定义的服务中,形成嵌套注入的形式,通常只需要将被注入的服务作为内置服务,采用显式声明的方式注入即可
html:
<div ng-controller="MyController">
<button ng-click="ask(false, '你输入的内容不正确')">提示框</button>
<button ng-click="ask(true, '你真的要删除这条记录吗?')">询问框</button>
</div>
javascript:
var myapp = angular.module('MyApp', []);
// 使用factory定义confirm服务
myapp.factory('confirm', ['$window', function ($win) {
return function (msg) {
$win.confirm(msg);
}
}]);
// 将confirm服务显式的注入到notify服务中
myapp.service('notify', ['$window', 'confirm', function ($win, con) {
return function (t, msg) {
return (t) ? con(msg) : $win.alert(msg);
}
}]);
myapp.controller('MyController', ['$scope', 'notify', function ($scope, notify) {
$scope.ask = function (t, msg) {
notify(t, msg);
}
}])
添加服务的其他设置
创建好的服务一般比较复杂,如果后期需要修改,往往面临很高的风险,Angular为服务添加了一些设置项,如装饰器(decorator),可以在不修改原代码的情况下为服务添加其他功能
服务的装饰器
装饰器(decorator)是Angular中内置服务$provide
所特有的一项设置函数,通过它可以拦截服务在实例化时创建的一些功能,并对原有功能进行优化和替代。
$provide.decorator('ServiceName', Fn)
-
$provide
表示注入后创建的服务对象 -
ServiceName
表示需要拦截的服务名称 -
Fn
表示服务在实例化时调用的函数,该函数在执行时需要添加一个名为$delegate
的参数,该参数代表服务实例化后的对象,服务的新功能就是通过这个对象进行扩展和优化的
示例代码:
<div ng-controller="MyController">
<div class="show">姓名: {{stu.name}}</div>
<div class="show">邮件: {{stu.email}}</div>
<div class="show">主题: {{stu.title}}</div>
</div>
var myapp = angular.module('MyApp', []);
// 使用工厂函数factory定义student服务
myapp.factory('student', function () {
return {
name: 'Kaindy',
email: 'kaindy7633@gmail.com'
}
});
// 使用$provider的装饰器decorator为服务student扩展一个title属性
myapp.config(function ($provide) {
$provide.decorator('student', function ($delegate) {
$delegate.title = 'Hello, Angular!';
return $delegate;
})
});
myapp.controller('MyController', function ($scope, student) {
$scope.stu = student;
});