服务这个概念其实并不陌生,好比在Java语言中便有这样的概念,其做用就是对外提供某个特定的功能,如消息服务,菜单服务等,是一个独立的模块。php
angular的服务是这样定义的:
Angular services are singletons objects or functions that carry out specific tasks common to web apps.html
在Angular中,服务的本质是一些和控制器捆绑在一块儿的一个单例对象或函数,对外提供特定的功能。经过这些对象提供了在应用的整个生命周期都存有数据的方法,当重载或刷新页面时,数据不会被清除,并且还与加载以前保持一致。即不管这个服务被注入到任何地方,对象始终只有一个实例。web
这与咱们本身定义一个function而后在其余地方调用不一样,由于服务被定义在一个模块中,因此其使用范围是能够被咱们管理的。angular的避免全局变量污染意识很是强。json
Angular提供了不少内置服务,如$scope、$http、$window、$location等。设计模式
咱们介绍一下$location。(注意服务是如何注入控制器的,后边会有单独模块介绍angular的依赖注入)跨域
<div ng-controller="MyController"> <div>当前的地址是: {{url}}</div> <button ng-click="onclick()">显示地址</button> </div> angular.module('MyApp').controller('MyController'['$scope','$location',function($scope,$location){ $scope.onclick = function () { $scope.url = $location.absUrl(); } }])
以'http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&projectId=42&mWin=false' 这个路径为例:数组
1.获取当前完整的url路径:
$location.absUrl():
http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&projectId=42&mWin=false
*2.获取当前url路径(当前url#后面的内容,包括参数和哈希值--哈希值介绍):
$location.url();
// /demandManager/view.html?orderId=10&projectId=42&mWin=false*3.获取当前url的子路径(也就是当前url#后面的内容,不包括参数):
$location.path()
// /demandManager/view.htmlpromise
4.获取当前url的协议(好比http,https)
$location.protocol()
// http
5.获取当前url的主机名
$location.host()
// localhost
6.获取当前url的端口
$location.port()
// 80 (这里就是wamp的默认端口号)
*7.获取当前url的哈希值(hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分)
$location.hash()
// null
*8.获取当前url的参数的序列化json对象
$location.search()
// {'orderId':10,'projectId':42,'mWin':'false'}
于$location.search(),$location.url();,$location.path(),$location.hash(),这四种能够传入参数进行修改url,在这种状况下,函数的返回值都是$location自己:安全
1.修改url的子路径(也就是当前url#后面的内容,包括参数):
参数格式:字符串服务器
$location.url('/demandCustomer/view.html?orderId=10&projectId=42&mWin=true'); //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandCustomer/view.html?orderId=10&projectId=42&mWin=true
2.修改url的子路径部分(也就是当前url#后面的内容,不包括参数):
参数格式:字符串
$location.path('/demandCustomer/view.html'); //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandCustomer/view.html?orderId=10&projectId=42&mWin=false
3.修改url的哈希值部分
参数格式:字符串
$location.hash('#footer'); //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&projectId=42&mWin=false#footer
4.修改url的参数部分(这是重点啊!!!!!!!!)
(1).传入两个参数,第一个参数的格式为字符串:
①第二个参数的格式也是字符串
第一个参数表示url参数的属性名,第二个参数是该属性名的属性值,若是是已有属性名,则修改,若是不是已有属性,则新增
$location.search('mWin','true') //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&projectId=42&mWin=true
②第二个参数的格式为数组,数组中的各个值也是字符串或者布尔值
第一个参数表示url参数的属性名,第二个参数是该属性名的值,有多少个值,url中就会依次重复出现多少个.以下:
$location.search('projectSearch',['book','home']) //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&projectId=42&mWin=false&projectSearch=book&projectSearch=home
(2).传入两个参数,第一个参数为字符串,第二个参数为null:
第一个值表示url参数的属性名,若是是已有属性名,则删除该属性,若是不是已有属性,那就等于没改过
$location.search('projectId',null) //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&mWin=false
(3).传入一个参数,格式为json对象:
直接用这个json对象里的键值对替换整个url的参数部分
①普通的键值对:
$location.search({orderId:11,projectId:45,mWin:true,projectSearch:'book'}) //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=11&projectId=45&mWin=true&projectSearch=book
②属性值为一个数组:
$location.search({orderId:11,projectId:45,mWin:true,projectSearch:['book','home']}) //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=11&projectId=45&mWin=true&projectSearch=book&projectSearch=home
(4).传入一个参数,格式为字符串:
直接用这个字符串替换整个url的参数部分(没有键值对,参数部分就是一个属性名)
$location.search('role') //http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?role
在上文的全部修改url的方法的时候,每修改一次,url都会被存入历史记录,可使用后退按钮回到修改前的url,若是不想要这种效果,而仅仅是替换当前的记录,可使用:
$location.replace();
例子:
// 原url: // http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&projectId=42&mWin=false $location.url('/demandCustomer/view.html?orderId=10&projectId=45&mWin=true'); // 修改一次后: // http://39.106.222.235:8080/cds/personalCenter/index.html#/demandCustomer/view.html?orderId=10&projectId=45&mWin=true // 按下后退回到原url: // http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&projectId=42&mWin=false // 再按下前进回到修改后url: // http://39.106.222.235:8080/cds/personalCenter/index.html#/demandCustomer/view.html?orderId=10&projectId=45&mWin=true $location.path('/demandCustomer').replace(); // 修改第二次后调用replace(): // http://39.106.222.235:8080/cds/personalCenter/index.html#/demandCustomer/view.html?orderId=10&projectId=42&mWin=false // 按下后退,不会回到第二次修改前的url,而是回到第一次修改前的url // http://39.106.222.235:8080/cds/personalCenter/index.html#/demandManager/view.html?orderId=10&projectId=42&mWin=false
Angular也能够监听路径的变化,这些事件咱们会在路由中作讲解。(待添加)
$http是Angular内置的服务,用于服务向服务器发送请求,应用响应服务器传送过来的数据。
写法:
写法一 $http({ method: 'GET', //能够改为POST url: '/someUrl' }).then(function successCallback(response) { // 请求成功执行代码 }, function errorCallback(response) { // 请求失败执行代码 }); 写法二 $http.get('/someUrl',config).then(successCallback, errorCallback); $http.get('/someUrl',{params:{"id":3}}).then(successCallback, errorCallback); $http.post('/someUrl', data:{name:"aaa",id:"1",age:"20"},config).then(successCallback, errorCallback); jsonp写法 $http({ method: 'JSONP', url: 'http://www.b.com/test.php?callback=JSON_CALLBACK' }).success(function(response){ console.log(response); }); $http.jsonp( 'http://www.b.com/test.php?callback=JSON_CALLBACK' ).success(function (response){ console.log(response); }); //这里要注意,跨域请求的url后必定要追加参数callback,而且callback的值是固定的,即JSON_CALLBACK,不要去作任何改动
这里只作简单介绍,项目中咱们使用的是基于$http的$resource服务,$resource依赖于$http。建立一个resource对象的工厂函数,可让你安全的和RESFUL服务端进行数据交互。
须要注入 ngResource 模块。一样会有单独模块介绍。这里是链接(待添加)。
J是中的setTimeout()和setInterval()这个你们确定不会陌生,在Angular中也有一样的服务
$timeout 服务
angular.module('myApp').controller('myCtrl', function($scope, $timeout) { $scope.myHeader = "Hello World!"; $timeout(function () { $scope.myHeader = "How are you today?"; }, 2000); }); //要在模块中引入
$interval 服务
angular.module('myApp').controller('myCtrl', function($scope, $timeout) { $scope.theTime = new Date().toLocaleTimeString(); $interval(function () { $scope.theTime = new Date().toLocaleTimeString(); }, 1000); //时间绑定。 });
3种建立自定义服务的方式。
以前也没有提到过,Angular这套框架最开始是由后台人员开发的,应用了后台早就存在的分层思想。因此项目也是使用这一设计模式。由此建立自定义服务时用到了上述三种方式。
factory方式建立的服务,做用就是返回一个有属性有方法的对象。
//经过工厂模式建立自定义服务 //一样能够注入依赖,但不能注入$scope做用域对象。 angular.module("MetronicApp").factory('myFactory', ['$resource','UrlConfig',function($resource,UrlConfig) { var service = {};//定义一个Object对象' service.name = "龙傲天"; service._getUrl = UrlConfig.url; var age;//定义一个私有化的变量 //对私有属性写getter和setter方法 service.setAge = function(newAge){ age = newAge; } service.getAge = function(){ return age; } //原始需求详情 service.getUrl = function (id) { return $resource(service._getUrl).get({orderId: id}); }; return service;//返回这个Object对象 }]); //建立控制器 angular.module("MetronicApp").controller('myCtrl',['$scope', 'myFactory',function($scope, myFactory) { $scope.name = myFactory.name; myFactory.setAge(20); $scope.age =myFactory.getAge(); myFactory.getUrl(id).$promise.then(function (result) { scope.model = result.data; });; }]);
在service使用构造函数的方法去用它,在控制器中是以new的方式引入,因此能够调用 service中定义的属性
//经过工厂模式建立自定义服务 //依赖注入其余模块 angular.module("MetronicApp").controller("myCtrl",['$scope'',myService',function($scope,myService){ $scope.name=myService.name; myService.get(id).$promise.then(function (result) { $scope.model = result.data; }); }]) /*Service是new出来的,因此能够直接调用里面的属性*/ angular.module("MetronicApp").service("myService",['$resource','UrlConfig',function($resource,UrlConfig){ this.name = '龙傲天'; this.url = UrlConfig.url; this.get = function (id) { return this.$resource(this._getUrl).get({orderId: id}); }; }])
若是想在 service 对象启用以前,先进行模块范围的配置,那就应该选择 provider。
当你使用Provider建立一个自定义服务时,能够经过$get()函数返回内容,惟一能够写进config配置阶段的一种。若是服务,必需要在配置阶段执行,那么必须使用provider。
使用Provider的优势就是,你能够在Provider对象传递到应用程序的其余部分以前在app.config函数中对其进行修改。
//名字必须符合规范:myProvider(你的Provider服务名字)+Provider angular.module("MetronicApp").config(function(myProviderProvider){ myProviderProvider.name = "龙傲天" }) //使用$get方法关联对应的config angular.module("MetronicApp").provider("myProvider",['$resource','UrlConfig',function($resource,UrlConfig){ this.$get = function(){ return { name : this.name, age : 18, url : UrlConfig.url , getData : function(id){ return this.$resource(UrlConfig.url).get({orderId: id}); } } } }]) angular.module("MetronicApp").controller("myCtrl",['$scope','myProvider',function($scope,myProvider){ $scope.model = { name : myProvider.name, age : myProvider.age, url : myProvider.url, } myProvider.getData(id).$promise.then(function (result) { $scope.model.data = result.data; }); }])
使用constant和value方法建立服务,经常使用于返回一个常量。
angular.module("MetronicApp").constant('$age', { age: '18' }); angular.module("MetronicApp").value('$name', { name : '龙傲天' }); angular.module("MetronicApp").controller('MyController', function($scope, $age, $name){ $scope.name = $name.name $scope.USD = $age.age })
angular.module("MetronicApp").service("myService",['UrlConfig',function(UrlConfig){ this.name = '龙傲天'; this.url = UrlConfig.url; this.getUrl = function (url) { var arr=url.split('/'); arr.push(this.url); arr.push(this.name); return arr.join('/') } }]) app.filter('myFilter',['myService', function(myService) { return function(url) { return myService.getUrl(url); }; }]);
咱们在自定义服务时,会依赖对象或服务,有下面三种方式:
(1) 隐式声明
在参数中直接调用,但这种方式在代码压缩时注入的对象可能会失效
angular.module("MetronicApp").service("myService", function($resource,UrlConfigService) { //code })
(2) 调用$inject属性
function myService($resource,UrlConfigService) { //code } myService.$inject = ['$resource','UrlConfigService']; angular.module('MetronicApp').service('myService', myService);
(3) 显式声明
在建立服务的函数中,添加一个数组,在数组中按顺序声明须要注入的服务或对象名称,这种方式既高效也不会丢失代码,推荐使用(在上述实例中咱们是用的都是此方法)
angular.module("MetronicApp").service("myService",['$resource','UrlConfig',function($resource,UrlConfig){ this.name = '龙傲天'; this.url = UrlConfig.url; this.get = function (id) { return this.$resource(this._getUrl).get({orderId: id}); }; }])
在angular的modul(模块)中注入服务,也能够在定义modul时使用数组做为第二个参数,在此处把服务注入进去,这样在函数体中使用不一致的服务名称也是能够的,不过要确保注入的顺序是一致的。(这个做为穿插,项目中可使用定义的服务名称,也能定义简化参数名称)注意此方法只针对显式声明有效。
angular.module("MetronicApp").controller("myCtrl",['$scope'',myDemandManageService',function($scope,myService){ //这里的myService就是指myDemandManageService; $scope.name=myService.name; myService.get(id).$promise.then(function (result) { $scope.model = result.data; }); }])
在Angular中,有时须要将一个自定义的服务注入到另外一个自定义的服务中,造成嵌套注入的形式,一般只须要将被注入的服务做为内置服务,采用显式声明的方式注入便可。
// 使用factory定义confirm服务
angular.module("MetronicApp").factory('confirm', ['$window', function ($win) { return function (msg) { $win.confirm(msg); } }]); // 将confirm服务显式的注入到fontWay服务中 angular.module("MetronicApp").service('fontWay', ['$window', 'confirm', function ($win, con) { return function (t, msg) { return (t) ? con(msg) : $win.alert(msg); } }]); angular.module("MetronicApp").controller('MyCtrl', ['$scope', 'fontWay', function ($scope, fontWay) { $scope.ask = function (t, msg) { fontWay(t, msg); } }])
建立好的服务通常比较复杂,若是后期须要修改,每每面临很高的风险,Angular为服务添加了一些设置项,如装饰器(decorator),能够在不修改原代码的状况下为服务添加其余功能。
装饰器(decorator)是Angular中内置服务$provide所特有的一项设置函数,经过它能够拦截服务在实例化时建立的一些功能,并对原有功能进行优化和替代。
// 使用工厂函数factory定义myService服务
angular.module("MetronicApp").factory("myService", function () { return { name: '龙傲天', age: 18 } }); // 使用$provider的装饰器decorator为服务myService扩展一个title属性 //关键的地方是在于decorator方法的回调函数的参数$delegate,指的是当前的数据(继承);项目中可使用这个来作你想作的事情。 angular.module("MetronicApp").config(function ($provide) { $provide.decorator('myService', function ($delegate) { $delegate.title = 'CDS'; return $delegate; }) }); angular.module("MetronicApp").controller('MyCtrl', function ($scope, myService) { $scope.model = myService; });
服务是Angular的一个难点,你们能够先理解,在项目中参照上述实例作比较。。任重而道远啊。。