標籤:http io os 使用 ar sp 資料 div 2014
一. 情境再現
如大家熟知,Ajax 可以實現頁面的無重新整理操作,但會造成兩個與普通頁面操作(有重新整理地改變頁面)有著明顯差別的問題—— URL 沒有修改以及無法使用前進、後退按鈕。例如常見的 Ajax 分頁,在第一頁點擊第二頁的連結,Ajax 分頁完成後瀏覽器地址欄上顯示的 URL 依然是第一頁的 URL,使用後退按鈕也無法回到第一頁。url 的改變代表一個標識,在傳統的網頁體驗中,內容的變更伴隨 url 的改變,url 的改變、前進和後退按鈕三者之間更加形成一種獨特的導航體驗,而 Ajax 破壞了這種體驗難免會對使用者造成不便。
當然,很早之前,機智的前端工程師們已經想好瞭解決辦法,最為常見的,就是使用 hash ——在 URL 結尾添加形如"#xxx" 的標識,然後用 onhashchange 等方式監聽 hash 值變化作出相應處理。
很麻煩?是的,因此,HTML5 History 中新增了幾個可以優雅地解決這些問題的特性!
二. HTML5 History 的新特性
History 對象從 HTML4 開始引入,HTML5 中增加了 pushState, replaceState 兩個方法,和 popstate 事件。下面作一些簡單的介紹。
1. pushState()方法
pushState() 的作用是往記錄的堆棧中壓入一條記錄,該方法有三個參數:
state object —— 一個對象,用於儲存狀態資訊,當 popstate 事件被觸發時,popstate 事件對象的 state 屬性會包含相應的 state object 的拷貝。state object 的容量很小(Firefox 中強製為 640k),如果需要儲存較大的資料,建議使用 localStorage 或 sessionStorage。
title —— 即被壓入的記錄的頁面的標題,該屬性暫時被所有瀏覽器忽略,實際開發時可以填Null 字元或一個簡短的標題。
url —— 新的記錄的地址,可以是相對路徑或絕對路徑,若為相對路徑則以當前 url 為基址。
2. replaceState()方法
replaceState() 方法與 pushState() 方法類似,參數與 pushState() 也相同,但 replaceState() 方法會修改當前的記錄而並非建立新的記錄,因此在需要更新當前記錄的 state object 或 URL 時,使用該方法會更加合適。
3. popstate 事件
popstate 事件會在啟用的記錄發生變化(如前進、後退、調用 pushState 或 replaceState 方法)時觸發在 window 對象上。如上面所描述,如果被啟用的記錄由 pushState 建立或是被 replaceState 修改,則 popstate 事件的狀態屬性將包含相應的 state object 的拷貝,開發人員可以在 popstate 的回調中調用這些之前儲存在 state object 中的資訊。
值得注意的是,Chrome 會在開啟頁面(包括第一次開啟頁面)以及頁面重新整理時產生 popstate 事件而 Firefox 則不會,這會為開發帶來一些麻煩,但下面會給出解決方案。
4. 瀏覽器安全色
| 特性 |
Chrome |
Firefox (Gecko) |
Internet Explorer |
Opera |
Safari |
| pushState, replaceState |
5 |
4.0 (2.0) |
10 |
11.50 |
5.0 |
| history.state |
18 |
4.0 (2.0) |
10 |
11.50 |
6.0 |
三. 使用 History 的新特性增強 Ajax 體驗
這裡說的增強體驗,實質就是要解決文章開頭提到的兩個問題 —— Ajax 翻頁時不會修改 URL 以及前進、後退功能無效。
看了上面的方法,相信大家已經能想到基本的解決思路,無非就是在 Ajax 需求產生時 pushState 一條記錄到記錄中,然後在 popstate 的回呼函數中作出相應的處理。當然,要想實際獲得比較好的體驗,要做的內容還是比較複雜的。下面以 Ajax 分頁為例,提供一個完整思路:
- 每次使用 Ajax 擷取新頁面後,使用 pushState() 把新頁面的 url 壓入記錄棧頂。
- 監聽 popstate 事件,當使用者前進或後退時在回調中根據前進或後退後的 URL 重新使用 Ajax 擷取頁面內容,實現 Ajax 前進與後退。
- Chrome 在開啟頁面以及重新整理頁面後會產生 popstate 事件,導致多餘的 Ajax 請求,因此需要 popstate 中利用 url 作為判斷使用者是否在點擊前進或後退功能,抑或是開啟、重新整理頁面,若為前進或後退才觸發 Ajax 擷取相應內容。
基本代碼
| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
// 定義 Ajax 擷取分頁方法,這裡不列出具體內容function turnPage(url){ // ...} // 定義 popstate 的回調if( history.pushState ){ // 判斷瀏覽器是否支援 pushState // currentState 用於記錄 popstate 產生前的頁面 url,頁面載入時初始化 currentState 為當前連結 var currentState = window.location.href; window.addEventListener(‘popstate‘, function(event){ // _currentUrl 用於記錄 popstate 產生時的頁面 url var _currentUrl = window.location.href; /* 判斷 currentState 和 _currentUrl 是否相同, * 若相同則表明這個 popstate 產生前後頁面 url 沒有變化, * 即頁面是第一次載入頁面或者被重新整理,無需觸發新的 Ajax 請求, * 若不同則表明 url 已改變,這是觸發 Ajax 擷取內容 */ if( currentState != _currentUrl ){ console.log(‘擷取新分頁‘); turnPage(_currentUrl); // 根據當前 url 重新擷取分頁內容 currentState = _currentUrl; // 更新 currentState } }); } // 綁定點擊分頁產生 Ajax 請求// 點擊分頁連結,擷取 url 為 currentLink,產生一次 Ajax 請求turnPage(currentLink); // 調用 pushState() 壓入新記錄if( history.pushState ){ // 判斷瀏覽器是否支援 pushState // 往記錄中壓入新記錄,瀏覽器的地址欄上的 url 同時會被修改為新 url history.pushState(null, document.title, currentLink); currentState = window.location.href; // 分頁時更新 currentState 為當前 url} |
本站已經根據上面的思路進行了 Ajax 分頁的增強,具體的情況如下:
開啟頁面,url 顯示為首頁的 url
點擊第二頁連結,觸發 Ajax 分頁,在 Ajax 中調用 pushState() ,可以看到,url 已經被修改為第二頁的 url
點擊後退按鈕,url 地址變為第一頁,再在 popstate 的回調中觸發 Ajax 擷取第一頁的內容。
這樣,就做到了既吸收了局部重新整理頁面的好處同時保留傳統的 url 導航體驗。而對於不支援 pushState 的瀏覽器,可以使用漸進增強設計忽略這些瀏覽器,畢竟這是一個增強體驗的功能;當然如果必須照顧那些瀏覽器,也可以採用 hash 的方案代替。
四. 現有的解決方案
如果需要直接的解決方案,可以參考這個封裝好並且實現了跨瀏覽器安全色的庫 —— History.js
本文由 Kayo Lee 發表,本文連結:http://kayosite.com/html5-history-improve-ajax.html
使用 HTML5 History 新特性增強 Ajax 的體驗(轉)