资讯专栏INFORMATION COLUMN

AngularJs功能(七)--服务

妤锋シ / 1228人阅读

摘要:通过工厂模式创建自定义服务同样可以注入依赖,但不能注入作用域对象。名字必须符合规范你的服务名字龙傲天使用方法关联对应的和使用和方法创建服务,常用于返回一个常量。

服务 Service

服务这个概念其实并不陌生,比如在Java语言中便有这样的概念,其作用就是对外提供某个特定的功能,如消息服务,菜单服务等,是一个独立的模块。

angular的服务是这样定义的:
Angular services are singletons objects or functions that carry out specific tasks common to web apps.

在Angular中,服务的本质是一些和控制器捆绑在一起的一个单例对象或函数,对外提供特定的功能。通过这些对象提供了在应用的整个生命周期都存有数据的方法,当重载或刷新页面时,数据不会被清除,而且还与加载之前保持一致。即无论这个服务被注入到任何地方,对象始终只有一个实例。

这与我们自己定义一个function然后在其他地方调用不同,因为服务被定义在一个模块中,所以其使用范围是可以被我们管理的。angular的避免全局变量污染意识非常强。

内置服务

Angular提供了很多内置服务,如$scope、$http、$window、$location等。

我们介绍一下$location。(注意服务是如何注入控制器的,后边会有多带带模块介绍angular的依赖注入)

获取url的相关方法:
当前的地址是: {{url}}
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.html

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的一个难点,大家可以先理解,在项目中参照上述实例做比较。。任重而道远啊。。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92714.html

相关文章

  • angular - 收藏集 - 掘金

    摘要:如何在中使用动画前端掘金本文讲一下中动画应用的部分。与的快速入门指南推荐前端掘金是非常棒的框架,能够创建功能强大,动态功能的。自发布以来,已经广泛应用于开发中。 如何在 Angular 中使用动画 - 前端 - 掘金本文讲一下Angular中动画应用的部分。 首先,Angular本生不提供动画机制,需要在项目中加入Angular插件模块ngAnimate才能完成Angular的动画机制...

    AlexTuan 评论0 收藏0
  • 阿拉伯-汉字-数字转换

    摘要:说明本文实现了一个从阿拉伯数字到中文数字,以及从中文数字到阿拉伯数字的转换算法。源代码在这里阿拉伯数字转中文给定一个阿拉伯数字,把它转变为汉语表示的数字。 说明 本文实现了一个从阿拉伯数字到中文数字,以及从中文数字到阿拉伯数字的转换算法。同时用Vuejs和Angularjs同时实现了一遍,对比了一下这两个框架的优劣。在本例中,Vuejs的方便灵活性完胜Angularjs。 源代码在这里...

    王军 评论0 收藏0
  • MEAN.js 文档

    摘要:感谢使用框架本文档涵盖构建应用所需的基础知识。用于数据校验的组件及相关文件在此目录进行管理。除了自定义中间件外,还是用了诸多第三方的中间件,它们是五测试我们使用组件对服务端代码进行测试。识别当前导航从已有导航中删除给定标识的导航配置。 本文同步至个人博客 MEAN.js 文档,转载请注明出处。 Overview 感谢使用 MEAN.js 框架! 本文档涵盖构建 MEAN 应用所需的基础...

    Hydrogen 评论0 收藏0
  • 前端资源分享-只为更好前端

    摘要:一团队组织网站说明腾讯团队腾讯前端团队,代表作品,致力于前端技术的研究腾讯社交用户体验设计,简称,腾讯设计团队网站腾讯用户研究与体验设计部百度前端研发部出品淘宝前端团队用技术为体验提供无限可能凹凸实验室京东用户体验设计部出品奇舞团奇虎旗下前 一、团队组织 网站 说明 腾讯 AlloyTeam 团队 腾讯Web前端团队,代表作品WebQQ,致力于前端技术的研究 ISUX 腾...

    zxhaaa 评论0 收藏0

发表评论

0条评论

妤锋シ

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<