AngularJs Using $location詳解及示例代碼
一、What does it do?
$location服務(wù)分析瀏覽器地址欄中的URL(基于window.location),讓我們可以在應(yīng)用中較為方便地使用URL里面的東東。在地址欄中更改URL,會(huì)響應(yīng)到$location服務(wù)中,而在$location中修改URL,也會(huì)響應(yīng)到地址欄中。
$location服務(wù):
暴露當(dāng)前瀏覽器地址欄的URL,所以我們可以
1.注意和觀察URL
2.改變URL
當(dāng)用戶做以下操作時(shí),與瀏覽器一起同步URL:
1.改變地址欄
2.單擊后退或者前進(jìn)按鈕(或者點(diǎn)擊一個(gè)歷史鏈接)。
3.單擊一個(gè)鏈接
將URL對(duì)象描繪為一系列的方法(protocol,host,path,search,hash)。
1. 比較$location和window.location
1) 目的:window.location和$location服務(wù),都允許對(duì)當(dāng)前瀏覽器的location進(jìn)行讀寫(xiě)訪問(wèn)。
2) API:window.location暴露一個(gè)未經(jīng)加工的對(duì)象,附帶一些可以直接修改的屬性;而$location服務(wù)則是暴露一些jQuery風(fēng)格的getter/setter方法。
3) 與angular應(yīng)用聲明周期的整合:$location知道關(guān)于所有內(nèi)部聲明周期的階段,與$watch等整合;而window.location則不行。
4) 與HTML5 API無(wú)縫結(jié)合:是(with a fallback for legacy browsers,對(duì)于低版本的瀏覽器有兼容手段?);而window.location則沒(méi)有。
5) 知道應(yīng)用加載的文檔根目錄(docroot)或者上下文(context):window.location不行,wnidow.location.path會(huì)返回”/docroot/子路徑”;而$location.path()返回真實(shí)的docroot。
2. When should I use $location?
在應(yīng)用中,任何需要對(duì)當(dāng)前URL的改變作出響應(yīng),或者想去改變當(dāng)前瀏覽器的URL的時(shí)候。
3. What does it not do?
當(dāng)瀏覽器URL改變的時(shí)候,不會(huì)導(dǎo)致頁(yè)面重新加載(page reload)。如果需要做這件事情(更改地址,實(shí)現(xiàn)page reload),請(qǐng)使用較低級(jí)別的API,$window.location.href。
二、General overview of the API(API的總體概述)
$location 服務(wù)可以根據(jù)它初始化時(shí)的配置而有不同的表現(xiàn)。默認(rèn)配置是適合大多數(shù)應(yīng)用的,其他配置定制,可以開(kāi)啟一些新特性。
當(dāng)$location服務(wù)初始化完畢,我們可以以jQuery風(fēng)格的getter、setter方法來(lái)使用它,允許我們獲得或者改變當(dāng)前瀏覽器的URl。
1. $location service configuration
想配置$location服務(wù),需要獲得$locationProvider(http://code.angularjs.org/1.0.2/docs/api/ng.$locationProvider),并設(shè)置以下參數(shù):
html5Mode(mode):{boolean},true - see HTML5 mode;false - see Hashbang mode,默認(rèn): false。(下面的章節(jié)會(huì)解釋各種mode)
hashPrefix(prefix):{string},hashbang使用的前綴(html5Mode為false時(shí),使用hashbang mode,以適應(yīng)不支持HTML5 mode的瀏覽器),默認(rèn):'!'
2. Getter and setter methods
$location 服務(wù)為只讀的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方法都返回同一個(gè)$location對(duì)象,以實(shí)現(xiàn)鏈?zhǔn)秸Z(yǔ)法。例如,在一句里面修改多個(gè)屬性,鏈?zhǔn)絪etter方法類似:
$location.path(‘/newValue').search({key:value});
有一個(gè)特別的replace方法,可以用作告訴$location服務(wù),在下一次與瀏覽器同步時(shí),使用某個(gè)路徑代替最新的歷史記錄,而不是創(chuàng)建一個(gè)新的歷史記錄。當(dāng)我們想實(shí)現(xiàn)重定向(redirection)而又不想使后退按鈕(后退按鈕回重新觸發(fā)重定向)失效時(shí),replace方法就很有用了。想改變當(dāng)前URL而不創(chuàng)建新的歷史記錄的話,我們可以這樣做:
$location.path(‘/someNewPath').replace();
注意,setter方法不會(huì)馬上更新window.location。相反,$location服務(wù)會(huì)知道scope生命周期以及合并多個(gè)$location變化為一個(gè),并在scope的$digest階段一并提交到window.location對(duì)象中。正因?yàn)?location多個(gè)狀態(tài)的變化會(huì)合并為一個(gè)變化,到瀏覽器中,只調(diào)用一次replace()方法,讓整個(gè)commit只有一個(gè)replace(),這樣不會(huì)使瀏覽器創(chuàng)建額外的歷史記錄。一旦瀏覽器更新了,$location服務(wù)會(huì)通過(guò)replace()方法重置標(biāo)志位,將來(lái)的變化將會(huì)創(chuàng)建一個(gè)新的歷史記錄,除非replace()被再次調(diào)用。
Setter and character encoding
我們可以傳入特殊字符到$location服務(wù)中,服務(wù)會(huì)按照RFC3986標(biāo)準(zhǔn),自動(dòng)對(duì)它們進(jìn)行編碼。當(dāng)我們?cè)L問(wèn)這些方法時(shí):
- 所有傳入$location的setter方法的值,path()、search()、hash(),都會(huì)被編碼。
- getter方法(沒(méi)參數(shù))返回的值都是經(jīng)過(guò)解碼的,如path(),search(),hash()。
- 當(dāng)我們調(diào)用absUrl()方法時(shí),返回的值是包含已編碼部分的完整url。
- 當(dāng)我們調(diào)用url()方法時(shí),返回的是包含path、search和hash部分的已經(jīng)編碼的url,如/path?search=1&b=c#hash。
三、Hashbang and HTML5 Modes
$location服務(wù)有兩個(gè)配置模式,可以控制瀏覽器地址欄的URL格式:Hashbang mode(默認(rèn))與基于使用HTML5 History API的HTML5 mode。在兩種模式下,應(yīng)用都使用相同的API,$location服務(wù)會(huì)與正確的URL片段、瀏覽器API一起協(xié)作,幫助我們進(jìn)行瀏覽器URL變更以及歷史管理。
1. Hashbang mode (default mode)
在這個(gè)模式中,$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沒(méi)東東的時(shí)候,返回空對(duì)象 $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,每次設(shè)置search,都會(huì)覆蓋之前的search $location.absUrl() == 'http://host.com/base/index.html#!/new?x=y'; } ));
Crawling your app(讓google能夠?qū)ξ覀兊膽?yīng)用進(jìn)行索引)
如果我們想讓我們的Ajax應(yīng)用能夠被索引,我們需要在head中增加一個(gè)特殊的meta標(biāo)簽:
<meta name="fragment" content="!" />
這樣做,將讓爬蟲(chóng)機(jī)器人使用_escaped_fragment_參數(shù)請(qǐng)求當(dāng)前的鏈接,讓我們的服務(wù)器認(rèn)識(shí)爬蟲(chóng)機(jī)器人,并提供對(duì)應(yīng)的HTML快照。想了解更多關(guān)于這個(gè)技術(shù)的信息,可以查看https://developers.google.com/webmasters/ajax-crawling/docs/specification?hl=zh-CN
四、HTML5 mode
在HTML5模式中,$location服務(wù)的getter、setter通過(guò)HTML5的History API與瀏覽器URL進(jìn)行交互,允許使用正規(guī)的path、search模塊,代替hashbang的模式。如果部分瀏覽器不支持HTML5 History API,$location服務(wù)會(huì)自動(dòng)退回到使用hashbang URL的模式。為了讓我們能夠從不清楚顯示我們的應(yīng)用的瀏覽器是否支持history API的擔(dān)心中解脫出來(lái),使用$location服務(wù)是一個(gè)正確的、最佳的選擇。
在舊版瀏覽器中打開(kāi)一個(gè)正規(guī)的URL會(huì)轉(zhuǎn)換為hashbangURL。
在現(xiàn)代瀏覽器中打開(kāi)一個(gè)hashbangURL,會(huì)重寫(xiě)為一個(gè)正規(guī)的URL。
1. 向前兼容舊版瀏覽器
對(duì)于支持HTML5 history API的瀏覽器,$location回使用它們?nèi)?xiě)path和search。如果瀏覽器不支持history API,$location會(huì)轉(zhuǎn)為提供Hashbang URL。這是$location服務(wù)自動(dòng)轉(zhuǎn)換的。
2. HTML link rewriting
當(dāng)我們使用history API mode的時(shí)候,我們對(duì)于不同的瀏覽器,需要不同的鏈接,但我們只需要提供正規(guī)的URL即可,例如<a href=”/some?foo=bar”>link</a>
當(dāng)用戶單擊這個(gè)超鏈接時(shí):
在舊的瀏覽器中,URL會(huì)改為/index.html#!/some?foo=bar
在現(xiàn)代瀏覽器中,URL會(huì)改為/some?foo=bar
在下面的情況中,鏈接不會(huì)被重寫(xiě),而是會(huì)使頁(yè)面加載到對(duì)應(yīng)Url中:
包含target的超鏈接:<a href="/ext/link?a=b" target="_self">link</a>
到不同domain的絕對(duì)鏈接:<a >link</a>
設(shè)置了base路徑后,通過(guò)” /”開(kāi)頭的鏈接到不同base路徑的超鏈接:<a href="/not-my-base/link">link</a>
3. server side
使用這個(gè)方式,在服務(wù)端請(qǐng)求URL重定向,通常,我們需要重定向我們所有的鏈接到我們的應(yīng)用中。(例如index.html)。
4. Crawling your app
與之前相同
5. Relative links
確保檢查所有相對(duì)鏈接、圖片、腳本等。我們必須在<head>中指定base url(<base href="/my-base">),并在所有地方使用絕對(duì)url(以/開(kāi)頭)。因?yàn)橄鄬?duì)URL會(huì)根據(jù)document的初始路徑(通常與應(yīng)用的root有所不同),轉(zhuǎn)化為絕對(duì)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)。
我們十分鼓勵(lì)在document root中運(yùn)行允許使用History API的angular應(yīng)用,因?yàn)檫@很好地照顧到相對(duì)鏈接的問(wèn)題。
6. Sending links among different browsers
?。ㄟ@里講解了兩種模式的地址可以適應(yīng)不同瀏覽器,自動(dòng)轉(zhuǎn)換,又重復(fù)講一次……)
7. 例子
在這例子中,可以看到兩個(gè)$location實(shí)例,兩個(gè)都是html5 mode,但在不同的瀏覽器上,所以我們可以看到兩者之間的不同點(diǎn)。這些$location服務(wù)與兩個(gè)假的“瀏覽器”連接。每一個(gè)input代表瀏覽器的地址欄。
注意,當(dāng)我們輸入hashbang地址到第一個(gè)“瀏覽器”(或者第二個(gè)?),它不會(huì)重寫(xiě)或重定向另外的Url,這個(gè)轉(zhuǎn)換過(guò)程只會(huì)發(fā)生在page reload的時(shí)候。
<!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 >/base/first?a=b</a> | <a >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 >/base/first?a=b</a> | <a >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>
五、附加說(shuō)明
1. Page reload navigation
$location服務(wù)僅僅允許我們改變URl;它不允許我們重新加載頁(yè)面(reload the page)。當(dāng)我們需要改變URL且reload page或者跳轉(zhuǎn)到其他頁(yè)面時(shí),我們需要使用低級(jí)點(diǎn)得API,$window.location.href。
2. Using $location outside of the scope life-cycle
$location知道angular的scope life-cycle。當(dāng)瀏覽器的URL發(fā)生改變時(shí),它會(huì)更新$location,并且調(diào)用$apply,所以所有$watcher和$observer都會(huì)得到通知。當(dāng)我們?cè)?digest階段中修改$location,不會(huì)出現(xiàn)任何問(wèn)題;$location會(huì)將這次修改傳播到瀏覽器中,并且通知所有$watcher、$observer。當(dāng)我們需要在angular外面改變$location時(shí)(例如在DOM事件中或者在測(cè)試中),我們必須調(diào)用$apply,以傳播這個(gè)變化。
3. $location.path() and ! or / prefixes
path可以直接使用”/”開(kāi)始;$location.path()setter會(huì)在value沒(méi)有以”/”開(kāi)頭時(shí)自動(dòng)補(bǔ)上。
注意”!”前綴,在Hashbang mode中,不屬于$location.path()的一部分。它僅僅是hashPrefix。
六、Testing with the $location service
在測(cè)試中使用$location服務(wù)的時(shí)候,是處于angular scope life-cycle外面的。這意味著我們需要負(fù)責(zé)調(diào)用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或者h(yuǎn)ashSearch去處理path和search方法。在這個(gè)release中,當(dāng)有需要的時(shí)候,$location服務(wù)處理path和search方法,然后使用那些獲得得信息去構(gòu)成hashbang URL(例如http://server.com/#!/path?search=a)。
八、Two-way binding to $location
angular compiler當(dāng)前不支持方法的雙向綁定(https://github.com/angular/angular.js/issues/404)。如果我們希望對(duì)$location對(duì)象實(shí)現(xiàn)雙向綁定(在input中使用ngModel directive),我們需要指定一個(gè)額外的model屬性(例如:locationPath),并加入兩個(gè)$watch,監(jiān)聽(tīng)兩個(gè)方向上的$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; });
以上就是關(guān)于AngularJs Using $location的資料整理,后續(xù)繼續(xù)補(bǔ)充相關(guān)資料,謝謝大家對(duì)本站的支持!
相關(guān)文章
Angular2中如何使用ngx-translate進(jìn)行國(guó)際化
本篇文章主要介紹了Angular2中使用ngx-translate進(jìn)行國(guó)際化,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05總結(jié)十個(gè)Angular.js由淺入深的面試問(wèn)題
這篇文章雖然只有10個(gè)問(wèn)題,但是覆蓋了angular開(kāi)發(fā)中的各個(gè)方面,有基本的知識(shí)點(diǎn),也有在開(kāi)發(fā)過(guò)程中遇見(jiàn)的問(wèn)題,同時(shí)也有較為開(kāi)放性的問(wèn)題去辨別面試者的基礎(chǔ)水準(zhǔn)和項(xiàng)目經(jīng)驗(yàn),注意答案僅供參考哦~2016-08-08Angular 理解module和injector,即依賴注入
本文主要介紹Angular 理解module和injector的知識(shí),這里整理了相關(guān)知識(shí),并詳細(xì)介紹了依賴注入的問(wèn)題,有興趣的小伙伴可以參考下2016-09-09Angular 多模塊項(xiàng)目構(gòu)建過(guò)程
這篇文章主要介紹了Angular 多模塊項(xiàng)目構(gòu)建過(guò)程,本文大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02angularjs中回車(chē)鍵觸發(fā)某一事件的方法
下面小編就為大家?guī)?lái)一篇angularjs中回車(chē)鍵觸發(fā)某一事件的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04