angular ui-router 變更網址列的方式! (偷渡關於移除URL中的#

在angular提供的ng-router或者third-party的ui-router中,在裡面這樣那樣的切換頁面過程中,瀏覽器的網址都會變更,但其實如果直接輸入那個網址,卻會404!!

應該是因為 angular在切換頁面的過程中,不希望刷新頁面,所以使用了類似partial view的概念,對需要更新的部分用http request去把需要的content拉出來,並且將網址列的內容更改為本身router的state對應到的url !!


/*偷渡一段在這邊


angular默認會使用一個#符號來對url進行route

例如

http://tony.com

http://tony.com/#/home

http://tony.com/#/setting


如果不想要出現這個#的話

要用$locationProvider,並且設置相對連接的起點路徑

在app.config中加入

$locationProvider.html5Mode(true);

在index的head裡面加入

<base href="/">


*/

而這邊要提到的就是將網址列的內容改為本身router的state對應到的url,這是如何做到的呢~~


這是使用了html5的history api來達成,可以透過window物件->history物件瀏覽瀏覽器的歷史,並且有提供一些方法讓你可以在歷史紀錄中前進以及後退要在歷史紀錄中往後移動,可以: window.history.back(); 同樣的,你也可以往前移動window.history.forward();


你可以用 go() 方法來從頁面的 session 歷史記錄中載入特定紀錄, 以目前頁面的相對位置而定(目前的頁面想當然爾是 index 0)


往前一頁(等同於呼叫 back()):window.history.go(-1);


往後一頁(等同於呼叫 forward()):window.history.go(1);

你可以查看 length 這個屬性來取得目前瀏覽歷史的總數 :
var numberOfEntries = window.history.length;

加入和修改歷史紀錄

HTML5 加入了 history.pushState() 和 history.replaceState() 方法,讓你可以加入或修改歷史紀錄。這些方法都可以跟 window.onpopstate 事件一同應用。


使用 history.pushState()後,會改變 XMLHttpRequest 時 HTTP 標頭中 referrer 的值。referrer 會是創造 XMLHttpRequest 物件時的當前視窗文件(this)的 URL


EX: var stateObj = { foo: "bar" }; history.pushState(stateObj, "page 2", "bar.html"); 這會讓網址列顯示 http://mozilla.org/bar.html,但不會讓瀏覽器去載入 bar.html,甚或去檢查 bar.html 存在與否。


假設現在使用者瀏覽到 http://google.com,然後點擊上一頁鈕。這時網址列會顯示 http://mozilla.org/bar.html,頁面會獲得 popstate 的事件(state object 會包含一份 stateObj 的副件)。頁面長得跟 foo.html 很像,但是可能在 popstate 事件執行中被修改。

如果我再點一次上一頁鈕, 網址會改變成為 http://mozilla.org/foo.html,且文件會得到另外一個 popstate 事件,此次會包含一個空的(null)state object。同樣的,回上頁鈕不會改變文件的內容,只是文件可能會在 popstate 事件中被手動更新。

popState()方法

在同一文件的當前歷史紀錄變動時,如果其變動介於兩個歷史紀錄間,popstate 就會被呼叫。如果當前的歷史紀錄是藉由呼叫 history.pushState() 建立,或曾被 history.replaceState() 修改過,popstate 事件的 state 屬性,將包含一份歷史紀錄的 state 物件。

請注意:直接呼叫 history.pushState() 或 history.replaceState() 不會驅動 popstate 事件。popstate 事件只會被瀏覽器的行為驅動,例如點擊上一頁按鈕(或透過 JavaScript 呼叫history.back())。且此事件只會在用戶於同文件的兩個歷史紀錄間瀏覽時作動。window.onpopstate = function(event) { alert("location: " + document.location + ", state: " + JSON.stringify(event.state)); }; history.pushState({page: 1}, "title 1", "?page=1"); history.pushState({page: 2}, "title 2", "?page=2"); history.replaceState({page: 3}, "title 3", "?page=3"); history.back(); // 跳出 "location: http://example.com/example.html?page=1, state: {"page":1}" history.back(); // 跳出 "location: http://example.com/example.html, state: null history.go(2); // 跳出 "location: http://example.com/example.html?page=3, state: {"page":3}

pushState() 方法

pushState() 取用三個參數:一個 state 物件、title(目前忽略)與 URL(可選用)。我們來看看三個參數的細節之處:

state object — state object是與pushState()建立的新瀏覽歷史紀錄有關的一個 JavaScript 物件。只要使用者到了新的 state ,一個 popstate 的事件就會被觸發,然後該事件的 state 屬性會包含一個複製的歷史紀錄的 state object。

state 物件可以是任何可序列化的東西。因為 Firefox 儲存 state 物件到使用者的硬碟,當瀏覽器被重新啟動的時候,他們是可以被恢復的,因此我們加上了 640k 個字元的長度限制在一個 以序列化表示的state object。如果你傳送一個比這個更大的序列化表示的 state object 到 pushState(),這個方法會丟出一個例外事件。如果你需要更多空間的話,你可以試著用 sessionStorage 和/或 localStorage


title — Firefox 目前忽略了這個參數,雖然他以後有可能會採用。如果以後改變了這個作法,傳送空白的字串應該還會是安全的。另外,你可以傳送一個短的標題來敘述你想要到的 state


URL — 這個新歷史紀錄的 URL 從這個參數做設定。值得注意的是,在 pushState() 被呼叫之後,瀏覽器並不會馬上嘗試載入這個 URL ,但是它可能在以後嘗試載入這個 URL ,例如使用者重新開啟瀏覽器之後。新的 URL 不一定需要為一個絕對的路徑;如果是相對路徑,會依據目前的URL來解析。新的 URL 需要與目前 URL 的 origin 是一樣的; 否則,pushState() 會丟出一個錯誤的例外。這個參數是選擇性的; 如果沒有被指定的話,他會設定為目前文件的 URL。


replaceState() 方法

history.replaceState() 的執行就像 history.pushState() ,除了 replaceState() 是修改目前的歷史紀錄而不是創造一個新的。

replaceState() 很實用的時機是當你要更新目前歷史紀錄的 state object 或是URL來反應一些使用者的動作時。

看到這邊之後,我個人覺得應該就是用replaceState的方法變動變動在變動~~吧

http://docs.angularjs.org/guide/dev_guide.services.$location 看完這篇應該就會知道到底是怎樣了吧,之後再看看


REF: https://developer.mozilla.org/zh-TW/docs/Web/Guide/API/DOM/Manipulating_the_browser_history/Manipulating_the_browser_history
http://www.oschina.net/translate/pretty-urls-in-angularjs-removing-the-hashtag

留言

這個網誌中的熱門文章

postman有跨網域神力啊

google smtp好麻煩啊~