標籤:
服務是一種由伺服器端帶到用戶端的特性,它由來已久。AngularJS應用中的服務是一些用依賴注入捆綁在一起的可替換的對象。服務是最常和依賴注入一起用的,它也是AngularJS中的關鍵特性。
接下來,我們詳細講解下$location服務。
$location服務,解析地址欄中的URL(基於window.location),讓你在應用代碼中能擷取到。改變地址欄中的URL會反應到$location服務中,反之亦然。
$location服務:
- 暴露當前地址欄的URL,這樣你就能
- 當出現以下情況時同步URL
- 改變地址欄
- 點擊了後退按鈕(或者點擊了曆史連結)
- 點擊了一個連結
- 一系列方法來擷取URL對象的具體內容用(protocol, host, port, path, search, hash)
window.location和$location.service的區別:
| |
window.location |
$location.service |
| 目的 |
允許對當前瀏覽器位置的讀寫 |
同左 |
| API |
暴露一個能被讀寫的對象 |
暴露jquery風格的讀寫器 |
| 是否在AngularJS應用生命週期中和應用整合 |
否 |
在應用聲明周期內的每一個階段可擷取到,並且和$watch整合 |
| 是否和HTML5 API的無縫整合 |
否 |
是(對低級瀏覽器優雅降級) |
| 和應用的上下文是否相關 |
否,window.location.path返回"/docroot/actual/path" |
是,$location.path()返回"/actual/path" |
什麼時候該用$location
在你想對URL的改變做出響應時,或者在你想改變當前URL時。
它不能用來幹什麼
在URL改變時,不能重新整理整個頁面。一定要的話,用低級的API,$window.location.href。
$location服務的具體行為取決於它初始化時的配置。預設設定對大多數應用都是適合的,你也可以自訂配置來增加些新特性。
$location服務初始化好以後,你就可以使用jquery風格的讀寫器和它互動了,你可以擷取或者改變當前URL。
要配置$location服務,檢索$locationProvider並把參數設定成以下這樣:
配置樣本
$locationProvider.html5Mode(true).hashPrefix(‘!‘);
讀寫器(getter and setter)
$location服務為URL唯讀部分(absUrl, protocol, host, port)提供讀方法,為可讀寫部分(url, path, search, hash)提供讀寫方法。
所有的寫方法返回同一個$location對象來支援鏈式操作。
$location服務有一個特殊的replace方法可以用來告訴$lacation服務下一次自動和瀏覽器同步,上一條瀏覽記錄應該被替換而不是建立一個新的。這在重新導向的時候很好用。不這樣的話容易使後退按鈕失效(點後退時會又觸發重新導向)。要改變URL而不添加新的記錄,你可以這樣做:
$location.path(‘/someNewPath‘);$location.replace();// or you can chain these as: $location.path(‘/someNewPath‘).replace();
注意:寫方法並不會馬上更新window.location,而是在範圍的$digest階段將多個$location操作合并成一個對windiow.location對象的commit操作。因為多個操作之後對瀏覽器來說都會只是一個,所以只要調用一次replace()方法就能實現瀏覽器記錄的替換操作。一旦瀏覽器更新了,$location服務就會將replace方法的標誌重設,以後的改變就會建立新的記錄,直到再次調用replace方法。
你可以給$location服務傳遞特殊字元,它會根據RFC 3986規則來編碼。當你調用寫方法時:
- 所有傳遞給寫方法(如path(), search(), hash())的值都會被編碼。
- 讀方法(path(), search(), hash()不帶參數的調用)返回解碼後的值。
- 當你調用absUrl()時,會返回各部分經過了編碼的完整url。
- 當你調用url()時,返回的值是path, search 和hash,形式是
/path?search=a&b=c#hash。
$location服務有兩種用來控制地址欄URL格式的配置:Hashbang模式(預設)和HTML5模式(使用HTML5曆史API)。應用會使用兩種模式中相同的API,並且$location服務會使用需要的URL片段和瀏覽器API來協助改變URL或者進行曆史管理。
它們兩者的區別:
Hashbang模式 HTML5模式配置: 預設 { html5Mode: true }URL格式: 所有瀏覽器都支援hashbang URLs 在進階瀏覽器中使用regular URLs,低級瀏覽器使用hashbang URLs<a href=""> 連結重寫: 否 是需要伺服器端配置: 否 是Hashbang模式(預設mode)
使用這個模式的話,$location會在所有瀏覽器中使用Hashbang URLs。
支援網路爬蟲
你需要添加特別的meta標記在你的文檔的頭部才能支援對你的AJAX應用的索引。
<meta name="fragment" content="!" />
這能讓網路爬蟲,請求帶有_escaped_fragment_形式的參數連結,這樣你就能識別爬蟲並且返回一個HTML的快照了。
HTML5模式
在HTML5模式中,$location服務的讀寫器和瀏覽器的URL地址通過HTML5曆史API互動,這使你能用regular URL path搜尋各組成部分,和hashbang是等效的。
- 在低級瀏覽器中使用了regular URL -> 重新導向成hashbang URL
- 在現代瀏覽器中開啟了一個hashbang URL -> 重寫成regular URL
低級瀏覽器使用的降級
在支援HTML5 曆史 API的瀏覽器中,$location服務的讀寫器和瀏覽器的URL地址通過HTML5曆史API互動。 如果瀏覽器不支援HTML5 曆史API, $location服務會自動降級成使用hashbang URLs。你就不用擔心瀏覽器的支援性了。$location服務總是會用最好的選擇。
Html連結重寫
當你使用曆史API模式時,在不同的瀏覽器中你需要使用不同的連結,但是你需要做的僅僅是指定好regular URL形式的連結,如 <a href="/some?foo=bar">link</a>。
當使用者點擊這個連結時
- 在低級瀏覽器中,URL轉換成
/index.html#!/some?foo=bar
- 在現代瀏覽器中轉換成
/some?foo=bar
如果是下面的這幾種形式,連結不會被重寫。取而代之的是,瀏覽器會根據連結重新載入頁面。
-
包含target的連結
Example: <a href="/ext/link?a=b" target="_self">link</a>
-
指向其他域的絕對路徑 Example: <a href="http://angularjs.org/">link</a>
-
當base被定義時,使用‘/‘開頭指向一個不同的base路徑。 Example: <a href="/not-my-base/link">link</a>
相對連結
記住要檢查所有的相對串連、圖片、指令碼等。你必須指定你首頁面的base url(<base href="/my-base">),或者你使用絕對路徑也行,因為相對路徑會結合文檔的初始絕對路徑轉換成絕對路徑。文檔初始路徑通常和應用的根路徑不一樣。
我們強烈推薦應用使用文檔根節點開始的曆史API,因為它能處理好所有相對路徑的問題。
不同瀏覽器中的連結
因為HTML模式的重寫能力,你的使用者能在低級瀏覽器中使用regualr url,在現代瀏覽器中使用hashbang url。
- 在進階瀏覽器中會將hashbang URLs重寫成regular URLs。
- 在低級瀏覽器中使用了regular URL會被重新導向成hashbang URL。
注意頁面的重新載入
$location服務只能讓你改變URL;不能讓你重新載入頁面。當你需要重新載入頁面或者跳轉到另外的頁面時,請使用更低層級的API,$window.location.href。
在範圍生命週期外使用$location
$location知道應用範圍的聲明周期。當URL改變時,它會更新$location,並且調用$apply,這樣所有監聽它的程式都會收到。當你在$digest階段時改變URL。$location將改變傳遞給瀏覽器,並且通知所有的監聽者。但是如果在應用之外使用$location的話(比如,在DOM事件中或者測試中),你就要手動調用它的$apply方法來傳遞改變了。
$location.path() 和 "!" "/" 首碼
一個路徑應該總是以斜杠開始;$location.path()寫方法會在沒有首碼"/"時自動添加。
注意,hashbang模式中的"!"首碼實際上不是$location.path()的一部分,它其實是hashPrefix。
$location的雙向繫結
AngularJS的編譯器目前不支援對$location對象的雙向繫結。如果你需要對$location對象(在input元素上使用ngModel指令)進行雙向繫結,你需要指定一個帶有兩個監聽者的額外的模型屬性(比如locationPath),這兩個監聽者各負責一個方向。
<!-- html --><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開發指南14:AngularJS的服務詳解