AngularJs功能(七)--服務

服務 Service

服務這個概念其實並不陌生,好比在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的依賴注入)跨域

獲取url的相關方法:

<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'}

修改url的相關方法:

於$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請求

$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種建立自定義服務的方式。

  • Factory
  • Service
  • Provider

以前也沒有提到過,Angular這套框架最開始是由後臺人員開發的,應用了後臺早就存在的分層思想。因此項目也是使用這一設計模式。由此建立自定義服務時用到了上述三種方式。

Factory

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

在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});
    };
}])

Provider

若是想在 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

使用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)

裝飾器(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的一個難點,你們能夠先理解,在項目中參照上述實例作比較。。任重而道遠啊。。

相關文章
相關標籤/搜索