(注意:根据 Sharky 的反馈,我已经包含了检测退格的代码)
所以,我在 SO 上经常看到这些问题,最近我自己也遇到了控制后退按钮功能的问题。在为我的应用程序寻找最佳解决方案(带有哈希导航的单页)几天后,我想出了一个简单的、跨浏览器、无库的系统来检测返回按钮。
大多数人推荐使用:
window.onhashchange = function() {
//blah blah blah
}
但是,当用户使用更改位置哈希的页内元素时,也会调用此函数。当您的用户点击并且页面后退或前进时,这并不是最佳的用户体验。
为了让您大致了解我的系统,当我的用户在界面中移动时,我将用以前的哈希值填充一个数组。它看起来像这样:
function updateHistory(curr) {
window.location.lasthash.push(window.location.hash);
window.location.hash = curr;
}
非常直接。我这样做是为了确保跨浏览器支持,以及对旧浏览器的支持。只需将新的哈希传递给函数,它会为您存储它,然后更改哈希(然后将其放入浏览器的历史记录中)。
我还使用了页内后退按钮,该按钮使用 lasthash 数组在页面之间移动用户。它看起来像这样:
function goBack() {
window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
//blah blah blah
window.location.lasthash.pop();
}
所以这会将用户移回最后一个哈希,并从数组中删除最后一个哈希(我现在没有前进按钮)。
所以。如何检测用户是否使用了我的页内后退按钮或浏览器按钮?
起初我查看了window.onbeforeunload,但无济于事 - 只有当用户要更改页面时才会调用它。这不会发生在使用哈希导航的单页应用程序中。
因此,经过更多挖掘,我看到了尝试设置标志变量的建议。在我的情况下,这个问题是我会尝试设置它,但由于一切都是异步的,它并不总是及时设置为散列更改中的 if 语句。 .onMouseDown 并不总是在 click 中调用,并且将其添加到 onclick 不会足够快地触发它。
这时我开始研究document 和window 之间的区别。我的最终解决方案是使用document.onmouseover 设置标志,并使用document.onmouseleave 禁用它。
发生的情况是,当用户的鼠标位于文档区域内时(读取:呈现的页面,但不包括浏览器框架),我的布尔值设置为 true。一旦鼠标离开文档区域,布尔值就会翻转到false。
这样,我可以将我的window.onhashchange 更改为:
window.onhashchange = function() {
if (window.innerDocClick) {
window.innerDocClick = false;
} else {
if (window.location.hash != '#undefined') {
goBack();
} else {
history.pushState("", document.title, window.location.pathname);
location.reload();
}
}
}
您会注意到#undefined 的检查。这是因为如果我的数组中没有可用的历史记录,它将返回 undefined。我用它来询问用户是否想使用window.onbeforeunload 事件离开。
因此,简而言之,对于不一定使用页内后退按钮或数组来存储历史记录的人:
document.onmouseover = function() {
//User's mouse is inside the page.
window.innerDocClick = true;
}
document.onmouseleave = function() {
//User's mouse has left the page.
window.innerDocClick = false;
}
window.onhashchange = function() {
if (window.innerDocClick) {
//Your own in-page mechanism triggered the hash change
} else {
//Browser back button was clicked
}
}
你有它。一种简单的三部分方法,用于检测与哈希导航相关的后退按钮使用与页内元素。
编辑:
为确保用户不使用退格键触发返回事件,您还可以包括以下内容(感谢@thetoolman on this Question):
$(function(){
/*
* this swallows backspace keys on any non-input element.
* stops backspace -> back
*/
var rx = /INPUT|SELECT|TEXTAREA/i;
$(document).bind("keydown keypress", function(e){
if( e.which == 8 ){ // 8 == backspace
if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
e.preventDefault();
}
}
});
});