AngularJs Using $location詳解及範例程式碼_AngularJS

來源:互聯網
上載者:User

一、What does it do?

  $location服務分析瀏覽器地址欄中的URL(基於window.location),讓我們可以在應用中較為方便地使用URL裡面的東東。在地址欄中更改URL,會響應到$location服務中,而在$location中修改URL,也會響應到地址欄中。

  $location服務:

暴露當前瀏覽器地址欄的URL,所以我們可以

1.注意和觀察URL
2.改變URL

當使用者做以下操作時,與瀏覽器一起同步URL:

1.改變地址欄
2.單擊後退或者前進按鈕(或者點擊一個曆史連結)。
3.單擊一個連結

將URL對象描繪為一系列的方法(protocol,host,path,search,hash)。

1. 比較$location和window.location

  1) 目的:window.location和$location服務,都允許對當前瀏覽器的location進行讀寫訪問。

  2) API:window.location暴露一個未經加工的對象,附帶一些可以直接修改的屬性;而$location服務則是暴露一些jQuery風格的getter/setter方法。

  3) 與angular應用聲明周期的整合:$location知道關於所有內部聲明周期的階段,與$watch等整合;而window.location則不行。

  4) 與HTML5 API無縫結合:是(with a fallback for legacy browsers,對於低版本的瀏覽器有相容手段?);而window.location則沒有。

  5) 知道應用載入的主目錄(docroot)或者上下文(context):window.location不行,wnidow.location.path會返回”/docroot/子路徑”;而$location.path()返回真實的docroot。

2. When should I use $location?

  在應用中,任何需要對當前URL的改變作出響應,或者想去改變當前瀏覽器的URL的時候。

3. What does it not do?

  當瀏覽器URL改變的時候,不會導致頁面重新載入(page reload)。如果需要做這件事情(更改地址,實現page reload),請使用較低層級的API,$window.location.href。

二、General overview of the API(API的總體概述)

  $location 服務可以根據它初始化時的配置而有不同的表現。預設配置是適合大多數應用的,其他配置定製,可以開啟一些新特性。

  當$location服務初始化完畢,我們可以以jQuery風格的getter、setter方法來使用它,允許我們獲得或者改變當前瀏覽器的URl。

1. $location service configuration

  想配置$location服務,需要獲得$locationProvider(http://code.angularjs.org/1.0.2/docs/api/ng.$locationProvider),並設定以下參數:

html5Mode(mode):{boolean},true - see HTML5 mode;false - see Hashbang mode,預設: false。(下面的章節會解釋各種mode)

hashPrefix(prefix):{string},hashbang使用的首碼(html5Mode為false時,使用hashbang mode,以適應不支援HTML5 mode的瀏覽器),預設:'!'

2. Getter and setter methods

  $location 服務為唯讀URL部分(absUrl,protocol,host,port)提供getter方法,也提供url,path,search,hash的getter、setter方法。

 // get the current path  $location.path();  // change the path  $location.path('/newValue')

  所有setter方法都返回同一個$location對象,以實現鏈式文法。例如,在一句裡面修改多個屬性,鏈式setter方法類似:

  $location.path(‘/newValue').search({key:value});

  有一個特別的replace方法,可以用作告訴$location服務,在下一次與瀏覽器同步時,使用某個路徑代替最新的記錄,而不是建立一個新的記錄。當我們想實現重新導向(redirection)而又不想使後退按鈕(後退按鈕回重新觸發重新導向)失效時,replace方法就很有用了。想改變當前URL而不建立新的記錄的話,我們可以這樣做:

          $location.path(‘/someNewPath').replace();

  注意,setter方法不會馬上更新window.location。相反,$location服務會知道scope生命週期以及合并多個$location變化為一個,並在scope的$digest階段一併提交到window.location對象中。正因為$location多個狀態的變化會合并為一個變化,到瀏覽器中,只調用一次replace()方法,讓整個commit只有一個replace(),這樣不會使瀏覽器建立額外的記錄。一旦瀏覽器更新了,$location服務會通過replace()方法重設標誌位,將來的變化將會建立一個新的記錄,除非replace()被再次調用。

           Setter and character encoding

  我們可以傳入特殊字元到$location服務中,服務會按照RFC3986標準,自動對它們進行編碼。當我們訪問這些方法時:

  1. 所有傳入$location的setter方法的值,path()、search()、hash(),都會被編碼。
  2. getter方法(沒參數)返回的值都是經過解碼的,如path(),search(),hash()。
  3. 當我們調用absUrl()方法時,返回的值是包含已編碼部分的完整url。
  4. 當我們調用url()方法時,返回的是包含path、search和hash部分的已經編碼的url,如/path?search=1&b=c#hash。 

三、Hashbang and HTML5 Modes

$location服務有兩個配置模式,可以控制瀏覽器地址欄的URL格式:Hashbang mode(預設)與基於使用HTML5 History API的HTML5 mode。在兩種模式下,應用都使用相同的API,$location服務會與正確的URL片段、瀏覽器API一起協作,協助我們進行瀏覽器URL變更以及曆史管理。

 

 

1. Hashbang mode (default mode)

  在這個模式中,$location在所有瀏覽器中都使用Hashbang URL。查看下面的程式碼片段,可以瞭解更多:

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() == {};//search沒東東的時候,返回Null 物件  $location.search({a: 'b', c: true});  $location.absUrl() == 'http://host.com/base/index.html#!/foo?a=b&c';  $location.path('/new').search('x=y');//可以用字串的方式更改search,每次設定search,都會覆蓋之前的search  $location.absUrl() == 'http://host.com/base/index.html#!/new?x=y';  }));

  Crawling your app(讓google能夠對我們的應用進行索引)

  如果我們想讓我們的Ajax應用能夠被索引,我們需要在head中增加一個特殊的meta標籤:

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

  這樣做,將讓爬蟲機器人使用_escaped_fragment_參數請求當前的連結,讓我們的伺服器認識爬蟲機器人,並提供對應的HTML快照。想瞭解更多關於這個技術的資訊,可以查看https://developers.google.com/webmasters/ajax-crawling/docs/specification?hl=zh-CN

四、HTML5 mode

  在HTML5模式中,$location服務的getter、setter通過HTML5的History API與瀏覽器URL進行互動,允許使用正規的path、search模組,代替hashbang的模式。如果部分瀏覽器不支援HTML5 History API,$location服務會自動退回到使用hashbang URL的模式。為了讓我們能夠從不清楚顯示我們的應用的瀏覽器是否支援history API的擔心中解脫出來,使用$location服務是一個正確的、最佳的選擇。

  在舊版瀏覽器中開啟一個正規的URL會轉換為hashbangURL。

  在現代瀏覽器中開啟一個hashbangURL,會重寫為一個正規的URL。

1. 向前相容舊版瀏覽器

  對於支援HTML5 history API的瀏覽器,$location回使用它們去寫path和search。如果瀏覽器不支援history API,$location會轉為提供Hashbang URL。這是$location服務自動轉換的。

2. HTML link rewriting

  當我們使用history API mode的時候,我們對於不同的瀏覽器,需要不同的連結,但我們只需要提供正規的URL即可,例如<a href=”/some?foo=bar”>link</a>

當使用者單擊這個超連結時:

在舊的瀏覽器中,URL會改為/index.html#!/some?foo=bar

在現代瀏覽器中,URL會改為/some?foo=bar

  在下面的情況中,連結不會被重寫,而是會使頁面載入到對應Url中:

包含target的超連結:<a href="/ext/link?a=b" target="_self">link</a>

到不同domain的絕對連結:<a href="http://angularjs.org/">link</a>

設定了base路徑後,通過” /”開頭的連結到不同base路徑的超連結:<a href="/not-my-base/link">link</a>

3. server side

  使用這個方式,在服務端請求URL重新導向,通常,我們需要重新導向我們所有的連結到我們的應用中。(例如index.html)。

4. Crawling your app

  與之前相同

5. Relative links

  確保檢查所有相對連結、圖片、指令碼等。我們必須在<head>中指定base url(<base href="/my-base">),並在所有地方使用絕對url(以/開頭)。因為相對URL會根據document的初始路徑(通常與應用的root有所不同),轉化為絕對url。(relative urls will be resolved to absolute urls using the initial absolute url of the document, which is often different from the root of the application)。

  我們十分鼓勵在document root中運行允許使用History API的angular應用,因為這很好地照顧到相對連結的問題。

6. Sending links among different browsers

  (這裡講解了兩種模式的地址可以適應不同瀏覽器,自動轉換,又重複講一次……)

7. 例子

  在這例子中,可以看到兩個$location執行個體,兩個都是html5 mode,但在不同的瀏覽器上,所以我們可以看到兩者之間的不同點。這些$location服務與兩個假的“瀏覽器”串連。每一個input代表瀏覽器的地址欄。

  注意,當我們輸入hashbang地址到第一個“瀏覽器”(或者第二個?),它不會重寫或重新導向另外的Url,這個轉換過程只會發生在page reload的時候。

<!DOCTYPE html><html ng-app><head>  <base href=""/>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>  <title>fake-browser</title>  <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">  <style type="text/css">    .ng-cloak {      display: none;    }  </style></head><body><div ng-non-bindable class="html5-hashbang-example">  <div id="html5-mode" ng-controller="Html5Cntl">    <h4>Browser with History API</h4>    <div ng-address-bar browser="html5"></div><br><br>    $location.protocol() = {{$location.protocol()}}<br>    $location.host() = {{$location.host()}}<br>    $location.port() = {{$location.port()}}<br>    $location.path() = {{$location.path()}}<br>    $location.search() = {{$location.search()}}<br>    $location.hash() = {{$location.hash()}}<br>    <a href="http://www.host.com/base/first?a=b">/base/first?a=b</a> |    <a href="http://www.host.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |    <a href="/other-base/another?search">external</a>  </div>  <div id="hashbang-mode" ng-controller="HashbangCntl">    <h4>Browser without History API</h4>    <div ng-address-bar browser="hashbang"></div><br><br>    $location.protocol() = {{$location.protocol()}}<br>    $location.host() = {{$location.host()}}<br>    $location.port() = {{$location.port()}}<br>    $location.path() = {{$location.path()}}<br>    $location.search() = {{$location.search()}}<br>    $location.hash() = {{$location.hash()}}<br>    <a href="http://www.host.com/base/first?a=b">/base/first?a=b</a> |    <a href="http://www.host.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |    <a href="/other-base/another?search">external</a>  </div></div><script src="../angular.js" type="text/javascript"></script><script type="text/javascript">  function FakeBrowser(initUrl, baseHref) {    this.onUrlChange = function(fn) {      this.urlChange = fn;    };    this.url = function() {      return initUrl;    };    this.defer = function(fn, delay) {      setTimeout(function() { fn(); }, delay || 0);    };    this.baseHref = function() {      return baseHref;    };    this.notifyWhenOutstandingRequests = angular.noop;  }  var browsers = {    html5: new FakeBrowser('http://www.host.com/base/path?a=b#h', '/base/index.html'),    hashbang: new FakeBrowser('http://www.host.com/base/index.html#!/path?a=b#h', '/base/index.html')  };  function Html5Cntl($scope, $location) {    $scope.$location = $location;  }  function HashbangCntl($scope, $location) {    $scope.$location = $location;  }  function initEnv(name) {    var root = angular.element(document.getElementById(name + '-mode'));    angular.bootstrap(root, [      function ($compileProvider, $locationProvider, $provide) {        debugger;      $locationProvider.html5Mode(true).hashPrefix('!');      $provide.value('$browser', browsers[name]);      $provide.value('$document', root);      $provide.value('$sniffer', {history:name == 'html5'});      $compileProvider.directive('ngAddressBar', function () {        return function (scope, elm, attrs) {          var browser = browsers[attrs.browser],              input = angular.element('<input type="text" style="width:400px;">').val(browser.url()),              delay;          input.bind('keypress keyup keydown', function () {            if (!delay) {              delay = setTimeout(fireUrlChange, 250);            }          });          browser.url = function (url) {            return input.val(url);          };          elm.append('Address: ').append(input);          function fireUrlChange() {            delay = null;            browser.urlChange(input.val());          }        };      });    }    ]);    root.bind('click', function (e) {      e.stopPropagation();    });  }  initEnv('html5');  initEnv('hashbang');</script></body></html>

五、附加說明

1. Page reload navigation

  $location服務僅僅允許我們改變URl;它不允許我們重新載入頁面(reload the page)。當我們需要改變URL且reload page或者跳轉到其他頁面時,我們需要使用低級點得API,$window.location.href。

2. Using $location outside of the scope life-cycle

  $location知道angular的scope life-cycle。當瀏覽器的URL發生改變時,它會更新$location,並且調用$apply,所以所有$watcher和$observer都會得到通知。當我們再$digest階段中修改$location,不會出現任何問題;$location會將這次修改傳播到瀏覽器中,並且通知所有$watcher、$observer。當我們需要在angular外面改變$location時(例如在DOM事件中或者在測試中),我們必須調用$apply,以傳播這個變化。

3. $location.path() and ! or / prefixes

  path可以直接使用”/”開始;$location.path()setter會在value沒有以”/”開頭時自動補上。

  注意”!”首碼,在Hashbang mode中,不屬於$location.path()的一部分。它僅僅是hashPrefix。

六、Testing with the $location service

  在測試中使用$location服務的時候,是處於angular scope life-cycle外面的。這意味著我們需要負責調用scope.apply()。  

describe('serviceUnderTest', function() {  beforeEach(module(function($provide) {    $provide.factory('serviceUnderTest', function($location){    // whatever it does...    });  });  it('should...', inject(function($location, $rootScope, serviceUnderTest) {    $location.path('/new/path');    $rootScope.$apply();    // test whatever the service should do...  }));});
 

七、Migrating from earlier AngularJS releases

  在早期的angular中,$location使用hashPath或者hashSearch去處理path和search方法。在這個release中,當有需要的時候,$location服務處理path和search方法,然後使用那些獲得得資訊去構成hashbang URL(例如http://server.com/#!/path?search=a)。

八、Two-way binding to $location

  angular compiler當前不支援方法的雙向繫結(https://github.com/angular/angular.js/issues/404)。如果我們希望對$location對象實現雙向繫結(在input中使用ngModel directive),我們需要指定一個額外的model屬性(例如:locationPath),並加入兩個$watch,監聽兩個方向上的$location更新,例如:

<input type="text" ng-model="locationPath" />

// js - controller$scope.$watch('locationPath', function(path) {  $location.path(path););$scope.$watch('$location.path()', function(path) {  scope.locationPath = path;});

以上就是關於AngularJs Using $location的資料整理,後續繼續補充相關資料,謝謝大家對本站的支援!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.