在我的AJAX应用程序中拦截对后退button的调用:我不希望它做任何事情!

我有一个AJAX应用程序。 用户点击一个button,页面的显示会改变。 他们点击后退button,希望转到原始状态,而是在浏览器中转到上一页。

我如何拦截和重新分配后退button事件? 我已经研究过像RSH这样的库(我无法工作…),而且我听说使用hash标记有所帮助,但我无法理解它。

谢谢!

啊,后退button。 你可能会想象“回”触发一个JavaScript事件,你可以简单地取消这样的事情:

document.onHistoryGo = function() { return false; } 

没有。 根本没有这样的事件。

如果你真的有一个networking应用程序 (而不是一个只有一个AJAXfunction的网站),这是合理的接pipe后退button(与URL片段,如你所说)。 Gmail做到这一点。 我正在谈论当你的Web应用程序在所有的一页,所有自足。

这项技术很简单 – 只要用户采取修改事件的操作,就可以redirect到您已经在的同一个URL,但使用不同的哈希片段。 例如

 window.location.hash = "#deleted_something"; ... window.location.hash = "#did_something_else"; 

如果您的Web应用程序的整体状态是可散列的,这是一个使用散列的好地方。 假设你有一个电子邮件列表,也许你会连接所有的ID和读取/未读的状态,并采取MD5哈希,使用它作为您的片段标识符。

这种redirect(仅散列)不会尝试从服务器获取任何内容,但它会在浏览器的历史logging列表中插入一个插槽。 所以在上面的例子中,用户点击“返回”,他们现在在地址栏中显示#deleted_something 。 他们又回来了,他们仍然在你的页面上,但没有哈希。 然后再回来,他们真的回去,无论他们从哪里来。

但是,现在最困难的部分是,在用户回击时检测到JavaScript(这样可以恢复状态)。 你所做的只是看着窗户的位置,看看它的变化。 投票。 (我知道,yuck,polling。那么,现在没有什么比跨浏览器更好的了)。 你将无法判断他们是前进还是后退,所以你必须得到你的哈希标识符的创意。 (也许一个哈希与一个序列号串联…)

这是代码的要点。 (这也是jQuery历史插件的工作原理。)

 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); 

为了给一个老的(但受欢迎的)问题提供一个最新的答案:

HTML5引入了history.pushState()history.replaceState()方法,可以分别添加和修改历史条目。 这些方法与window.onpopstate事件一起工作。

使用history.pushState()更改在更改状态后创build的XMLHttpRequest对象的HTTP标头中使用的引用链接。 引用者将是在创buildXMLHttpRequest对象时窗口是this文档的URL。

来源:从Mozilla开发者networking操纵浏览器历史 。

使用jQuery我做了一个简单的解决scheme:

 $(window).bind('hashchange', function() { top.location = '#main'; // Eventually alert the user describing what happened }); 

到目前为止只在Google Chrome上进行了testing。

这解决了我的networking应用程序,这也是基于AJAX的高度的问题。

这可能有点hack'ish – 但我会叫它优雅的黑客;-)每当你尝试向后导航它popup一个哈希部分的URI在技术上是什么,然后试图向后导航。

它拦截两个浏览器button和鼠标button。 而且,你不能通过点击几次,这是一个基于setTimeout或setInterval的解决scheme中出现的问题。

我真的很感谢在darkporter的答案给出的解释,但我认为可以通过使用“ hashchange ”事件来改善。 正如darkporter解释的那样,你要确保你所有的button都改变了window.location.hash的值。

  • 一种方法是使用<button>元素,然后附加事件给他们,然后设置window.location.hash = "#!somehashstring";
  • 另一种方法是只使用button的链接,如<a href="#!somehashstring">Button 1</a> 。 这些链接被点击后,哈希自动更新。

之所以在哈希符号后面加上感叹号,是为了满足Google的“hashbang”范式( 阅读更多内容 ),如果您希望通过search引擎进行索引,这很有用。 您的散列string通常是名称/值对,如#!color=blue&shape=triangle或像#!/blue/triangle这样的列表 – 无论您的networking应用程序是否合理。

那么你只需要添加这一点的代码,只要散列值发生变化(包括后退button被触发)就会触发。 没有轮询循环似乎是必要的。

 window.addEventListener("hashchange", function(){ console.log("Hash changed to", window.location.hash); // .... Do your thing here... }); 

除了Chrome 36以外,我还没有testing过,但根据caniuse.com的说法 ,这个应该可以在IE8 +,FF21 +,Chrome21 +以及Opera Mini以外的大多数浏览器上使用。

这是很容易禁用浏览器返回button ,如下面的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

谢谢 !

由于隐私问题,无法禁用后退button或检查用户的历史logging,但可以在此历史logging中创build新条目而不更改页面。 每当你的AJAX应用程序改变状态,用一个新的URI片段更新top.location

 top.location = "#new-application-state"; 

这将在浏览器的历史堆栈中创build一个新的条目。 许多AJAX库已经处理了所有无聊的细节,比如真正简单的历史 。

在我的情况下,我想阻止后退button发送用户到最后一页,而是采取不同的行动。 使用hashchange事件我想出了一个解决scheme,为我工作。 这个脚本假设你正在使用它的页面没有使用散列,就像我的情况一样:

 var hashChangedCount = -2; $(window).on("hashchange", function () { hashChangedCount++; if (top.location.hash == "#main" && hashChangedCount > 0) { console.log("Ah ah ah! You didn't say the magic word!"); } top.location.hash = '#main'; }); top.location.hash = "#"; 

我遇到的一些其他答案的问题是hashchange事件不会触发。 根据你的情况,这可能也适合你。

我做这样的事情 我保持与以前的应用程序状态arrays。

启动为:

 var backstack = []; 

然后我听取位置哈希值的变化,当它改变时,我这样做:

 if (backstack.length > 1 && backstack[backstack.length - 2] == newHash) { // Back button was probably pressed backstack.pop(); } else backstack.push(newHash); 

这样,我有一个跟踪用户历史logging的简单方法。 现在,如果我想在应用程序中实现一个后退button(而不是浏览器),我只需要这样做:

 window.location.hash = backstack.pop(); 

我想出了一种方法来覆盖正常的历史行为,并使用HTML5历史API(在IE 9中不起作用)创build不同的backforwardbutton事件。 这是非常hacky,但如果你想拦截后退和前进的button事件,并处理它们,但是你想要的。 这在很多情况下都很有用,例如,如果您正在显示远程桌面窗口并需要在远程计算机上重新生成向前和向后button的点击。

以下将覆盖后退和前进button的行为:

 var myHistoryOverride = new HistoryButtonOverride(function() { console.log("Back Button Pressed"); return true; }, function() { console.log("Forward Button Pressed"); return true; }); 

如果您在这两个callback函数中返回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. } }); }; 

这是一个简单的概念。 当我们的页面加载时,我们创build3个不同的历史状态(编号为1,2和3),并导航浏览器到状态编号2.因为状态2在中间,下一个历史导航事件将使我们处于状态1或3,由此我们可以确定用户按下了哪个方向。 就这样,我们拦截了一个后退或前进的button事件。 然后,我们然后处理它,然后返回到状态2,以便捕获下一个历史导航事件。

显然,在使用HistoryButtonOverride脚本时,您需要避免使用history.replaceState和history.pushState方法,否则会破坏它。