服務是一種由服務器端帶到客戶端的特性,它由來已久。AngularJS應用中的服務是一些用依賴注入捆綁在一起的可替換的對象。服務是最常和依賴注入一起用的,它也是AngularJS中的關鍵特性。
接下來,我們詳細講解下$location服務。
$location服務,解析地址欄中的URL(基於window.location),讓你在應用代碼中能獲取到。改變地址欄中的URL會反應到$location服務中,反之亦然。
$location服務:
- 暴露當前地址欄的URL,這樣你就能
- 獲取並監聽URL。
- 改變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並把參數設置成以下這樣:
-
html5Mode(模式): {boolean}
true - 參閱HTML5模式
false - 參閱Hashbang模式
default: false -
hashPrefix(前綴): {string}
Hashbang URLs的前綴 (在Hashbang模式中或者低級瀏覽器中使用)
default: '!'
配置示例
$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; });
加油!