AngularJS Service是一个函数或对象,可以使用在Angular应用中。

AngularJS有很多内置服务,我们也可以按照自己的需要来创建服务,这里讲一下几个常用的服务。

$HTTP

$http服务是所有Angular服务中最为常用的内置服务之一。

$http服务封装了浏览器原生的XMLHttpRequest对象。它只能接受一个参数,且这个参数是一个对象,包含了用来生成HTTP请求的配置内容。它返回一个Promise对象(一个原生的ES6对象,表示即将发生的事件),具有两个方法(success和error)。

$http({
  url:'data.json',
  method:'GET'
}).success(function(response){
  //响应成功
  
}).error(function(response){
  //处理响应失败
});

使用than方法来处理回调

$http({
  method: 'GET',
  url: 'data.js'
}).then(function successCallback(response) {
  //响应成功
  }, function errorCallback(response) {
  //处理响应失败
});

快捷的GET/POST请求

$http.get('date.json', config).then(successCallback, errorCallback);

$http.post('date.json', data, config).then(successCallback, errorCallback);

$location

Angular中使用内置的$location服务来监听、操作URL,包括如下功能:

  • 获取、监听、改变地址栏的URL
  • 与URL实现双向数据绑定(地址栏变动、前进后退或者点击页面的链接均会触发)
  • 将URL对象封装成了一套方法(protocol、host、port、path、search和hash)

$location服务的具体行为取决于它初始化时的配置。默认设置对大多数应用都是适合的,你也可以自定义配置来增加些新特性。

$location服务初始化好以后,你就可以使用jquery风格的读写器和它交互了,你可以获取或者改变当前URL。

$location服务的配置

要配置$location服务,检索$locationProvider并把参数设置成以下这样:

html5Mode(模式): {boolean}
  strue - 参阅HTML5模式
  false - 参阅Hashbang模式
  default: false

hashPrefix(前缀): {string}
  Hashbang URLs的前缀 (在Hashbang模式中或者低级浏览器中使用)
  default: '!'

配置示例

$locationProvider.html5Mode(true).hashPrefix('!');

Hashbang和HTML5模式

$location服务有两种用来控制地址栏URL格式的配置:Hashbang模式(默认)和HTML5模式(使用HTML5历史API)。应用会使用两种模式中相同的API。

示例

Hashbang模式(默认mode)

使用这个模式的话,$location会在所有浏览器中使用Hashbang URLs。

it('should show example', inject(
  function($locationProvider) {
  $locationProvider.html5mode = false;
  $locationProvider.hashPrefix = '!';
  },
  function($location) {
  // open http://host.com/base/index.html#!/a
  $location.absUrl() == 'http://host.com/base/index.html#!/a'
  $location.path() == '/a'

  $location.path('/foo')
  $location.absUrl() == 'http://host.com/base/index.html#!/foo'

  $location.search() == {}
  $location.search({a: 'b', c: true});
  $location.absUrl() == 'http://host.com/base/index.html#!/foo?a=b&c'

  $location.path('/new').search('x=y');
  $location.absUrl() == 'http://host.com/base/index.html#!/new?x=y'
  }
));

支持网络爬虫

你需要添加特别的meta标记在你的文档的头部才能支持对你的AJAX应用的索引。

<meta name="fragment" content="!" />

这能让网络爬虫请求带有_escaped_fragment_形式的参数链接,这样你就能识别爬虫并且返回一个HTML的快照了。更多信息请参考 Making AJAX Applications Crawlable

HTML5模式

在HTML5模式中,$location服务的读写器和浏览器的URL地址通过HTML5历史API交互,这使你能用regular URL path并且搜索各组成部分,和hashbang是等效的。 如果浏览器不支持HTML5 历史API, $location服务会自动回退成使用hashbang URLs。你就不用担心浏览器的支持性了。$location服务总是会用最好的选择。

  • 在低级浏览器中使用了regular URL -> 重定向成hashbang URL
  • 在现代浏览器中打开了一个hashbang URL -> 重写成regular URL
it('should show example', inject(
  function($locationProvider) {
  $locationProvider.html5mode = true;
  $locationProvider.hashPrefix = '!';
  },
  function($location) {
  // in browser with HTML5 history support:
  // open http://host.com/#!/a -> rewrite to http://host.com/a
  // (replacing the http://host.com/#!/a history record)
  $location.path() == '/a'

  $location.path('/foo');
  $location.absUrl() == 'http://host.com/foo'

  $location.search() == {}
  $location.search({a: 'b', c: true});
  $location.absUrl() == 'http://host.com/foo?a=b&c'

  $location.path('/new').search('x=y');
  $location.url() == 'new?x=y'
  $location.absUrl() == 'http://host.com/new?x=y'

  // in browser without html5 history support:
  // open http://host.com/new?x=y -> redirect to http://host.com/#!/new?x=y
  // (again replacing the http://host.com/new?x=y history item)
  $location.path() == '/new'
  $location.search() == {x: 'y'}

  $location.path('/foo/bar');
  $location.path() == '/foo/bar'
  $location.url() == '/foo/bar?x=y'
  $location.absUrl() == 'http://host.com/#!/foo/bar?x=y'
  }
));

$cacheFactory

$cacheFactory是应用程序一个会话(Session)中的缓存服务,以key-value对的方法存储一些临时数据。它跟浏览器本地缓存localStorage是不一样的。$cacheFactory在用户删除当前会话(比如强制刷新页面)之后,缓存的数据就被清空了。

用法

首先,要得到一个缓存实例,用id来区分,比如我想取id为’firstCache’的缓存:

var cache = $cacheFactory('firstCache');

添加kv对,put方法:

cache.put(key, value);

获取,get方法:

cache.get(key); // 如果不存在这个key的话,会返回undefined

添加kv对,put方法:

cache.put(key, value);

删除,remove和removeAll:

cache.remove(key); // 删除某个kv对
cache.removeAll(); // 删除该缓存的全部kv对

删除该缓存实例,destroy:

cache.destroy(); // 把当前缓存删除掉
cache.put(key, value); // 错误!不能再访问该缓存,要重新生产一个实例出来

$timeout、$interval

$timeout和$interval是AngularJS自带的服务,跟原生js中的setTimeout和setInterval函数的用法基本是一样的。但是有两个不一样的地方需要注意一下:

区别一:

原生js中的两个函数,如果在AngularJS中使用并且在回调函数中需要使用$scope服务的话,我们需要用$angular.$apply把回调函数包起来,因为这里setTimeout函数被AngularJS当作是外部函数了。就像这样:

// 错误的写法示例(使用setTimeout却没有用$apply):
angular.module('myDemo', [])

  .controller('firstController', ['$scope', function ($scope) {

  setTimeout(function () {
    console.log('before');  // 正常输出before
    $scope.name = "My name have been changed."; // 这一句不被执行
    console.log('after');   // 正常输出after
  }, 2000);
  }]);
// 正确的写法示例
angular.module('myDemo', [])

  .controller('firstController', ['$scope', function ($scope) {

  setTimeout(function () {
    console.log('before');  // 正常输出before
    $scope.$apply(function () {
    $scope.name = "My name have been changed.";  // 正确显示
    });
    console.log('after');   // 正常输出after
  }, 2000);
  }]);

所以,在AngularJS中,最好不要用setTimeout或setInterval,而是用那两个AngularJS系统服务。

区别二:

取消的方式不大一样,比如timeout:

// setTimeout
var id = setTimeout(func, 2000); // 返回该timeout的id
clearTimeout(id); // 使用clearTimeout
// $timeout服务
var promise = $timeout(f, 2000); // 返回一个promise对象
$timeout.cancel(promise); // 还是要使用服务,它的cancel方法

$sce

sce指的是Strict Contextual Escaping,它是默认开启的,负责拒绝一些不安全的行为,比如加载不同源的资源等等。但是有时候,我们又需要加载一些特定的资源,我们就得使用$sce的一些方法,来为这些资源和AngularJS系统之间建立信任。

用法

$sce有以下常用方法:

  • $sce.trustAsHtml(…):将一段html文本视为安全
  • $sce.trustAsUrl(…)
  • $sce.trustAsResourceUrl(…)
  • $sce.trustAsJs(…)

举个例子,假如我要显示(可以理解成渲染,相当于android SDK中的WebView)一段html文本表示的内容,我们需要遵循以下步骤:

1.在html模板中用“ng-bind-html”属性来绑定一个model(变量);

2.在js中注入$sce服务,并且使用方法$sce.trustAsHtml(…),把信任后的值赋给该model。

示例

HTML:

<div ng-controller="LogController">
  <!--这里不能用ng-bind,因为是渲染一段html文本,而不是显示简单的数据-->
  <div ng-bind-html="results"></div>
</div>

JS:

angular.module('myDemo', [])
  .controller('LogController', function ($scope, $http, $sce) {

  // 随便定义一段html文本
  var txt = "<h1>Hello world!</h1>";

  // 这里不能直接$scope.results = txt,否则会报错显示“不安全”
  $scope.results = $sce.trustAsHtml(txt);
  });

此时浏览器就会输出Hello world!

(完)