前言
前面我们讲了控制器、过滤器以及指令,这一节我们来讲讲重大内容之一服务和其中涉及到的工厂。
话题
AngularJS中服务可以说是和DI紧密联系在一起,在应用程序中我们可以通过使用服务来共享代码,服务可以被延迟实例化,为何这样说,在Angular内置的服务或者我们自定义的服务只有在注入才能被实例化,同时也就意味着当我们应用程序需要依赖于服务这一组件时才会被实例化,Angular中的服务是一个单例对象即服务中的某一个部分依赖于另外一个服务都会返回从服务工厂中获取到单个实例的引用。Angular中有许多内置默认有用的服务供我们使用,和过滤器一样,我们同样可以根据需求自定义服务。
服务到底做了什么?它的底层实现了什么?它提供了跨领域、请求和操作数据、和外部服务集成以及包括业务逻辑的功能,它简单的就如一个JSON对象。下图给出了Angular组件以及它们之间的作用。
服务到底什么时候应该被创建?为什么要被创建?当我们在应用程序利用Angular需要重用代码时,我们通过服务来封装功能,在Angular模块中有三种方法来定义服务:Factory、Service、Provider。下面我们就这三种方式来创建服务。
Factory method for creating service(推荐方式)
创建服务最简单的方式则是通过module.Factory的方式来创建服务,通过传递两个参数,一个是创建服务的名称,另外一个则是factory函数来返回服务对象。下面我们来创建一个日志记录服务看看。
FactoryService.js
创建factoryApp模块并自定义一个logService服务。
var factroyApp = angular.module('factoryApp', []); factroyApp.factory('logService', function(){ var messageCount = 0; return { log : function(msg){ console.log("(日志提醒 + " + messageCount++ + ") " + msg); } }; })
app.js
加载factoryApp依赖模块,通过点击对应的按钮来记录该按钮的文本以及点击的次数。
var app = angular.module('myApp', ['factoryApp']); app.controller('FactoryController', function ($scope, logService) { $scope.data = { device: ["Vivo Xplay5", "OPPO R9", "Huawei P9"], totalClicks: 0 }; $scope.$watch('data.totalClicks', function (count) { logService.log("点击次数: " + count); }); }); app.directive("triButton", function (logService) { return { scope: { counter: "=counter" }, link: function (scope, element, attrs) { element.on("click", function (event) { logService.log("所点击按钮文本为: " + event.target.innerText); scope.$apply(function () { scope.counter++; }); }); } } });
FactoryHtml
<html ng-app="myApp"> <head> <meta charset="utf-8"> <title></title> <link href="../Content/bootstrap.min.css" rel="stylesheet"/> <script type="text/javascript" src="../Scripts/angular.min.js"></script> <script type="text/javascript" src="../Service/FactoryService.js"></script> <script type="text/javascript" src="../app.js"></script> </head> <body ng-controller="FactoryController"> <div class="well"> <div class="btn-group" tri-button counter="data.totalClicks" source="data.device"> <button class="btn btn-default" ng-repeat="item in data.device"> {{item}} </button> </div> <h5>总点击次数: {{data.totalClicks}}</h5> </div> </body> </html>
我们同样来看看结果:
其实对于上述app.js我们完全可以进行改造,通过DI来实现(虽然还未讲到DI)我们可以事先体验一下来得到同样的效果,同时将上述控制器代码进行拆分,这样代码才能一目了然。将app.js中控制器代码改造如下:
app.controller('FactoryController',FactoryController); app.$inject = ['$scope','logService']; function FactoryController($scope,logService){ $scope.data = { device: ["Vivo Xplay5", "OPPO R9", "Huawei P9"], totalClicks: 0 }; $scope.$watch('data.totalClicks', function (count) { logService.log("点击次数: " + count); }); }
Service method for creating service
我们同样可以用service方法来创建服务,但是与上述通过工厂方法来创建服务有点不同,当在AnuglarJS中某一组件需要通过工厂方法定义的服务这一依赖时,很简单只是通过工厂方法返回的对象来使用该对象即可,而在service方法中需要使用服务对象,那么需要将工厂方法作为一个构造函数并且需要使用js关键字来创建这个服务对象,此时这个关键字则不会再在程序中大量使用,则容易造成不必要的麻烦。说了这么多貌似只有用代码才能加深我们的理解,其实就是利用原型继承来创建,我们重新写一个日志服务方法。
上述我们只需要将创建服务的脚本进行改造如下即可:
var serviceApp = angular.module('factoryApp', []); var baseLogger = function () { var messageCount = 0; this.log = function (msg) { console.log("(日志提醒 + " + messageCount++ + ") " + msg); } }; var debugLogger = function () { }; debugLogger.prototype = new baseLogger serviceApp.service("logService", debugLogger);
上述代码想必不用做过多解释,再加上第一种方式作为推荐方式,这两种方式作为了解,知道有这三种方式即可。
Provider method for creating service
对于通过这种方式来创建服务我们需要更多的去用代码进行改造,和第一种方式类比,我们通过工厂函数来返回,而对于此方法我们最终需要通过调用$get方法来获取服务对象。代码如下:
var providerApp = angular.module('factoryApp', []); providerApp.provider("logService", function () { var messageCount = 0; return { $get: function () { return { log: function (msg) { console.log("(日志提醒 + " + messageCount++ + ") " + msg); } }; } } });
总结
这一节我们稍微比较详细的介绍了在AngularJS中如何创建服务,利用三种方式来创建服务,希望对阅读本文的你有所帮助,我们下节再叙。