javascript - programming - web ajax tutorial
在我的AJAX應用程序中攔截對後退按鈕的調用:我不希望它做任何事情! (6)
我有一個AJAX應用程序。 用戶單擊按鈕,頁面的顯示會發生變化。 他們點擊後退按鈕,期望進入原始狀態,但是,他們會在瀏覽器中轉到上一頁。
如何攔截和重新分配後退按鈕事件? 我已經研究了像RSH這樣的庫(我無法工作......),而且我聽說使用哈希標籤會有所幫助,但我無法理解它。
謝謝!
使用jQuery我做了一個簡單的解決方案:
$(window).bind('hashchange', function() {
top.location = '#main';
// Eventually alert the user describing what happened
});
到目前為止只在Google Chrome中測試過。
這解決了我的網絡應用程序的問題,該應用程序也是基於AJAX的。
它可能有點hack'ish - 但我稱之為優雅的黑客;-)每當你嘗試向後導航時,它會在URI中彈出一個哈希部分,從技術上來說它會嘗試向後導航。
它攔截了單擊瀏覽器按鈕和鼠標按鈕。 而且你不能通過每秒點擊幾次來向後強制它,這是基於setTimeout或setInterval的解決方案中會出現的問題。
啊,後退按鈕。 您可能會想像“返回”會觸發一個JavaScript事件,您可以像這樣簡單地取消:
document.onHistoryGo = function() { return false; }
不是的。 根本就沒有這樣的事件。
如果你真的有一個網絡應用程序 (而不僅僅是一個具有一些ajaxy功能的網站),接管後退按鈕是合理的(如你所提到的那樣,URL上有片段)。 Gmail就是這麼做的。 我在談論你的網頁應用程序在一個頁面中的所有內容,都是獨立的。
該技術很簡單 - 每當用戶採取修改事物的操作時,重定向到您已經使用的相同URL,但使用不同的哈希片段。 例如
window.location.hash = "#deleted_something";
...
window.location.hash = "#did_something_else";
如果您的Web應用程序的整體狀態是可清除的,那麼這是一個使用哈希的好地方。 假設您有一個電子郵件列表,也許您將連接所有ID和已讀/未讀狀態,並使用MD5哈希作為您的片段標識符。
這種重定向(僅限哈希)不會嘗試從服務器獲取任何內容,但它會在瀏覽器的歷史列表中插入一個插槽。 因此,在上面的示例中,用戶點擊“返回”,他們現在在地址欄中顯示#deleted_something 。 他們再次回擊,他們仍然在你的頁面上,但沒有哈希。 然後再回來,他們實際上回到了他們來自哪裡。
現在是困難的部分,在用戶回擊時檢測JavaScript(這樣你就可以恢復狀態)。 您只需觀察窗口位置並查看其何時發生變化。 隨著民意調查。 (我知道,哎呀,民意調查。好吧,現在沒有更好的跨瀏覽器了)。 您將無法判斷他們是前進還是後退,因此您必須使用您的哈希標識符獲得創意。 (也許是與序列號連接的哈希...)
這是代碼的要點。 (這也是jQuery History插件的工作原理。)
var hash = window.location.hash;
setInterval(function(){
if (window.location.hash != hash) {
hash = window.location.hash;
alert("User went back or forward to application state represented by " + hash);
}
}, 100);
很容易禁用瀏覽器BACK按鈕 ,就像下面的JQuery代碼一樣:
// History API
if( window.history && window.history.pushState ){
history.pushState( "nohb", null, "" );
$(window).on( "popstate", function(event){
if( !event.originalEvent.state ){
history.pushState( "nohb", null, "" );
return;
}
});
}
你可以看到它工作,更多的例子在這裡dotnsf和這裡thecssninja
謝謝 !
我找到了一種方法來覆蓋正常的歷史行為,並使用HTML5歷史API創建不同的back
和forward
按鈕事件(它在IE 9中不起作用)。 這非常hacky,但如果您想攔截後退和前進按鈕事件並按照您的需要處理它們,則會非常有效。 這在許多場景中都很有用,例如,如果您正在顯示遠程桌面窗口並需要在遠程計算機上重現後退和前進按鈕單擊。
以下內容將覆蓋後退和前進按鈕行為:
var myHistoryOverride = new HistoryButtonOverride(function()
{
console.log("Back Button Pressed");
return true;
},
function()
{
console.log("Forward Button Pressed");
return true;
});
如果您在其中任何一個回調函數中返回false,您將允許瀏覽器繼續正常的後退/前進操作並離開您的頁面。
這是完整的腳本:
function HistoryButtonOverride(BackButtonPressed, ForwardButtonPressed)
{
var Reset = function ()
{
if (history.state == null)
return;
if (history.state.customHistoryStage == 1)
history.forward();
else if (history.state.customHistoryStage == 3)
history.back();
}
var BuildURLWithHash = function ()
{
// The URLs of our 3 history states must have hash strings in them so that back and forward events never cause a page reload.
return location.origin + location.pathname + location.search + (location.hash && location.hash.length > 1 ? location.hash : "#");
}
if (history.state == null)
{
// This is the first page load. Inject new history states to help identify back/forward button presses.
var initialHistoryLength = history.length;
history.replaceState({ customHistoryStage: 1, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.pushState({ customHistoryStage: 2, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.pushState({ customHistoryStage: 3, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.back();
}
else if (history.state.customHistoryStage == 1)
history.forward();
else if (history.state.customHistoryStage == 3)
history.back();
$(window).bind("popstate", function ()
{
// Called when history navigation occurs.
if (history.state == null)
return;
if (history.state.customHistoryStage == 1)
{
if (typeof BackButtonPressed == "function" && BackButtonPressed())
{
Reset();
return;
}
if (history.state.initialHistoryLength > 1)
history.back(); // There is back-history to go to.
else
history.forward(); // No back-history to go to, so undo the back operation.
}
else if (history.state.customHistoryStage == 3)
{
if (typeof ForwardButtonPressed == "function" && ForwardButtonPressed())
{
Reset();
return;
}
if (history.length > history.state.initialHistoryLength + 2)
history.forward(); // There is forward-history to go to.
else
history.back(); // No forward-history to go to, so undo the forward operation.
}
});
};
這是一個簡單的概念。 當我們的頁面加載時,我們創建3個不同的歷史狀態(編號為1,2和3)並將瀏覽器導航到狀態編號2.因為狀態2位於中間,下一個歷史導航事件將使我們處於狀態1或3,從中我們可以確定用戶按下哪個方向。 就這樣,我們截獲了一個後退或前進按鈕事件。 然後我們處理它然後我們想要並返回狀態2,這樣我們就可以捕獲下一個歷史導航事件。
顯然,在使用HistoryButtonOverride腳本時,您需要避免使用history.replaceState和history.pushState方法,否則就會破壞它。
我非常感謝darkporter的答案中給出的解釋,但我認為可以通過使用“ hashchange ”事件來改進它。 正如darkporter解釋的那樣,您希望確保所有按鈕都更改window.location.hash值。
- 一種方法是使用
<button>
元素,然後將事件附加到它們然後設置window.location.hash = "#!somehashstring";
。 - 另一種方法是使用按鈕的鏈接,例如
<a href="#!somehashstring">Button 1</a>
。 單擊這些鏈接時,哈希會自動更新。
我在哈希符號後面有一個感嘆號的原因是為了滿足谷歌的“hashbang”範式( 更多關於這一點 ),如果你想被搜索引擎索引,這很有用。 您的哈希字符串通常是名稱/值對,如#!color=blue&shape=triangle
或類似#!/blue/triangle
的列表 - 對您的Web應用程序有意義。
然後你只需要添加這段代碼,只要哈希值發生變化(包括擊中後退按鈕時)就會觸發。 似乎沒有必要進行輪詢循環。
window.addEventListener("hashchange", function(){
console.log("Hash changed to", window.location.hash);
// .... Do your thing here...
});
除了Chrome 36之外,我還沒有測試任何東西,但根據caniuse.com的說法 ,這應該適用於IE8 +,FF21 +,Chrome21 +以及除Opera Mini之外的大多數其他瀏覽器。
為舊的(但受歡迎的)問題提供最新答案:
HTML5引入了
history.pushState()
和history.replaceState()
方法,允許您分別添加和修改歷史條目。 這些方法與window.onpopstate
事件一起使用。使用
history.pushState()
更改在更改狀態後創建的XMLHttpRequest
對象的HTTP標頭中使用的引用者。 引用者將是在創建XMLHttpRequest
對象時其窗口this
的文檔的URL。
來源:從Mozilla Developer Network 處理瀏覽器歷史記錄 。