Ajax保留瀏覽器歷史的兩種解決方案(Hash&Pjax)
總是在github down點東西,github整個介面做的不錯,體驗也很好~對於其中的原始碼滑動的特效最為喜歡了~剛開始以為這個只是普通的ajax請求效果,但是發現這個特效能夠導致瀏覽器位址列跟隨變化,並且再點選前進後退按鈕後又可以將程式碼滑回滑出~~於是乎就來研究下吧~
一、通過錨點Hash實現:
在這方面其實國內很早就有做了,比如淘寶畫報,通過的是在位址列後面加#錨點實現的,瀏覽器是可以識別錨點為單位的歷史記錄的。但不是說頁面本身有這個錨點,錨點的Hash只是起到一個引導瀏覽器將這次的記錄推入歷史記錄棧頂的作用。
來做一個小小的demo:
<style type="text/css">
#tab1_header,#tab2_header{
cursor:pointer;
border:1px solid;
width:50px;
}
#tab1,#tab2{
width:90%;
height:200px;
border:1px solid;
}
</style>
<div id="tab_header">
<span id="tab1_header">Tab1</span>
<span id="tab2_header">Tab2</span>
</div>
<div id="tab1">1</div>
<div id="tab2">2</div>
一個很簡單的Tab切換如果一般情況下就直接:
$("#tab1_header").click(function() { $("#tab2").hide(); $("#tab1").show(); }); $("#tab2_header").click(function() { $("#tab1").hide(); $("#tab2").show(); });
但假如點選到tab2時想通過後退按鈕退到tab1時就不行了,假如重新整理的話瀏覽器的行為完全不是出於使用者的想法,這樣的話,我們可以加入#錨點來模擬新頁面,為什麼要說模擬呢,假如直接通過js改變window.location瀏覽器會重新載入頁面,但加#就不會重新載入並且能儲存在歷史中。JS通過window.location.hash來控制URL後面的錨點#。
我們把程式碼改為這樣:
$(function(){ showTab(); $(window).bind('hashchange', function(e){ showTab(); }); $("#tab1_header").click(showTab1); $("#tab2_header").click(showTab2); }); function showTab() { if (window.location.hash == "#tab2"){ showTab2(); } else { showTab1(); } } function showTab1() { $("#tab2").hide(); $("#tab1").show(); window.location.hash = "#tab1"; }; function showTab2() { $("#tab1").hide(); $("#tab2").show(); window.location.hash = "#tab2"; };
加上window.location.hash = "#tab1"這一段程式碼就行了,在點選tab後,位址列後面就會加上#tab1,點選tab2後就會改成#tab2,當瀏覽器檢測到url變化時就會觸發hashchange這一事件,就是使用者在點選後退時能夠得到的事件就能夠通過window.location.hash進行判斷並進行ajax操作了,但是haschange這個事件並不是每個瀏覽器都有的,只有現代高階瀏
覽器才有,所以在低階的瀏覽器中需要用輪詢來檢測URL是否在變化,這個這裡就不具體說了。
二、通過HTML5加強型的History物件實現(類Pjax)
可以通過window.history.pushState這個方法無重新整理的更新瀏覽器位址列,這個方法在更新位址列的同時將地址壓入歷史記錄堆疊裡,而要取出這個棧頂頁面則可以用popstate這個事件來捕獲~
來模擬一下github的環境,github中每個url是對應一個完整的實際頁面的,所以在ajax請求頁面時需要非同步獲取target頁面中指定id容器中的內容:
比如有這樣兩個頁面:
index.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gbk">
<title>index</title>
</head>
<body>
<script>document.write(new Date());</script>
<div id="cn">
<a href="second.html">載入前</a>
</div>
</body>
</html>
second.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gbk">
<title>second</title>
</head>
<body>
<script>document.write(new Date());</script>
<div id="cn">
<a href="index.html">載入後</a>
</div>
</body>
</html>
假如用同步的http請求開啟的話完全是兩個頁面,兩個頁面加入很多地方一樣的話我們完全可以用這種方法來實現ajax請求變更DOM,我在這裡加了<script>document.write(new Date());</script>語句通過它的變化能得知是否取自兩個http請求,局
部的ajax請求是不會改變這個時間顯示的。
$(function(){ var state = { title: "index", url: "index.html" }; $("#cn").click(function(){ window.history.pushState(state, "index", "second.html"); var $self = $(this); $.ajax({ url:"second.html", dataType: "html", complete: function(jqXHR, status, responseText){ responseText = jqXHR.responseText; if (jqXHR.isResolved()) { jqXHR.done(function(r){ responseText = r; }); $self.html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn")); } } }); document.title = "second"; return false; }); $(window).bind('popstate', function(e){ var st = e.state; //$("#cn").load(st.url + " #cn"); $.ajax({ url:"index.html", dataType: "html", complete: function(jqXHR, status, responseText){ responseText = jqXHR.responseText; if (jqXHR.isResolved()) { jqXHR.done(function(r){ responseText = r; }); $("#cn").html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn")); } } }); document.title = e.state.title; }); });
上面語句中當#cn元素被點選時將state通過pushState方法壓入歷史記錄棧,並在第三個引數中將瀏覽器URL框中指向second頁面,並通過ajax將second頁面非同步載入,將相應的部分加入容器中,這樣就實現了非同步載入並改變位址列url了,同樣使用者點選後退時,觸發popstate,剛才pushState方法中的第一個引數state便是這裡傳入的形參e中的state屬性,通過var st = e.state取出供開發使用。同時載入index頁面中對應內容。時間有限這個js沒有進行重構,直接寫$.ajax了,其實假如不需要任何特效單純的非同步載入在jQ中可以直接用$("#cn").load(st.url + " #cn");將請求的html對應的#cn放到本頁面的#cn容器中,但加入要更加炫的特效的話就要直接操作ajax傳回的資料了。
$("#cn").html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn"));
先建立一個div容器在將經過script過濾過的程式碼裝入這個容器在通過find方法找到裡面對應的選擇器容器插入本身的頁面中,這裡可以不用html來填充,可以根據自己的專案需要用slideUp,show什麼的特效進行內容顯示~~
另外這裡要推薦一個jQuery元件叫pjax(https://github.com/defunkt/jquery-pjax),比較牛叉的一個元件,非同步的部分load進來另外一個頁面對應容器中的內容,實現的機理和我上面的第二種方案一致。pushState + ajax = pjax 感覺這個應用會熱起來的。
稍微總結下,兩種方案其實對於想IE6或者FF3.6等比較低階的瀏覽器支援不是很好,前者若要相容低端瀏覽器要用輪詢來監聽瀏覽器位址列行為,而後者的話是完全的HTML5應用,對於非HTML5瀏覽器只能做判斷跳轉了。
如pjax最後的一段無奈的相容處理:
$.support.pjax = window.history && window.history.pushState // Fall back to normalcy for older browsers. if ( !$.support.pjax ) { $.pjax = function( options ) { window.location = $.isFunction(options.url) ? options.url() : options.url } $.fn.pjax = function() { return this } }
相關文章
- 瀏覽器同源策略及 Ajax 跨域解決方案瀏覽器跨域
- 理解瀏覽器的歷史記錄瀏覽器
- 瀏覽器歷史記錄的返回瀏覽器
- 【譯】瀏覽器user-agent的歷史瀏覽器
- 【工具】火狐瀏覽器歷史版本下載瀏覽器
- JavaScript瀏覽器歷史的語法小問題JavaScript瀏覽器
- chrome瀏覽器最小字號解決方案Chrome瀏覽器
- 使用 JavaScript 操作瀏覽器歷史記錄 APIJavaScript瀏覽器API
- 理解瀏覽器歷史記錄(2)- hashchange、pushState瀏覽器
- 主流瀏覽器核心介紹(前端開發值得了解的瀏覽器核心歷史)瀏覽器前端
- 突破瀏覽器域名併發限制的解決方案瀏覽器
- 「前端」History API與瀏覽器歷史堆疊管理前端API瀏覽器
- 解決JS彈出新視窗被瀏覽器阻止的解決方案JS瀏覽器
- 瀏覽器支援ES6的最優解決方案瀏覽器
- Edge瀏覽器被搜狗瀏覽器篡改的解決方法瀏覽器
- Mac上的Safari瀏覽器如何檢視歷史記錄?Mac瀏覽器
- 如何在官網中下載歷史版本的火狐瀏覽器瀏覽器
- 從瀏覽器到伺服器的4種跨域請求解決方案瀏覽器伺服器跨域
- angular瀏覽器相容性問題解決方案Angular瀏覽器
- 實現瀏覽器跨域解決方案介紹瀏覽器跨域
- 深入學習History物件管理瀏覽器會話歷史物件瀏覽器會話
- win10有兩種ie瀏覽器怎麼解決_win10桌面有兩個ie圖示的解決方法Win10瀏覽器
- QTP測試多個瀏覽器視窗的解決方案QT瀏覽器
- 瀏覽器 UA 的變遷史瀏覽器
- uc瀏覽器字型放大解決方案瀏覽器
- Fetch 代替 Ajax 的瀏覽器 API瀏覽器API
- 主流瀏覽器相容性問題與解決方案瀏覽器
- 瀏覽器相容性問題解決方案 · 總結瀏覽器
- 解決ajax回撥window.open瀏覽器阻止彈窗問題瀏覽器
- HTML5支援所有瀏覽器的SHIV解決方案HTML瀏覽器
- SSL-Explorer基於web瀏覽器的VPN解決方案Web瀏覽器
- 瀏覽器突然不能訪問某些可用網站解決方案瀏覽器網站
- 最新Iframe全瀏覽器相容自適應高度解決方案瀏覽器
- 詳解瀏覽器跨域的幾種方法瀏覽器跨域
- web端iphonex的各種瀏覽器適配問題和解決方案WebiPhone瀏覽器
- 讓 IE 瀏覽器成為歷史,這是微軟給的最好禮物瀏覽器微軟
- 瀏覽器核心WebKit編年史瀏覽器WebKit
- IE瀏覽器清除Ajax快取方法瀏覽器快取