如何检测浏览器后退按钮事件 - 跨浏览器

如何明确检测用户是否按下了浏览器中的后退按钮?

如何在使用系统的单页 Web 应用程序中强制使用页内后退按钮?#URL

为什么浏览器后退按钮不触发自己的事件!?


答案 1

(注意:根据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语句。 并不总是在点击时调用,并且将其添加到onclick中永远不会足够快地触发它。.onMouseDown

这时我开始研究 、 和 .我的最后一个解决方案是使用 设置标志,并使用 禁用它。documentwindowdocument.onmouseoverdocument.onmouseleave

发生的情况是,当用户的鼠标位于文档区域内(读取:呈现的页面,但不包括浏览器框架)时,我的布尔值设置为 。一旦鼠标离开文档区域,布尔值就会翻转为 。truefalse

这样,我可以将我的更改为: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();
        }
    }
}

您将注意到 对 的检查。这是因为如果我的数组中没有可用的历史记录,它将返回 .我用它来询问用户是否要使用事件离开。#undefinedundefinedwindow.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
    }
}

你有它。一种简单的三部分方法来检测后退按钮与页面内元素在哈希导航方面的使用情况。

编辑:

为了确保用户不使用退格键来触发 back 事件,您还可以包含以下内容(感谢@thetoolman此问题):

$(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();
            }
        }
    });
});

答案 2

您可以尝试 popstate 事件处理程序,例如:

window.addEventListener('popstate', function(event) {
    // The popstate event is fired each time when the current history entry changes.

    var r = confirm("You pressed a Back button! Are you sure?!");

    if (r == true) {
        // Call Back button programmatically as per user confirmation.
        history.back();
        // Uncomment below line to redirect to the previous page instead.
        // window.location = document.referrer // Note: IE11 is not supporting this.
    } else {
        // Stay on the current page.
        history.pushState(null, null, window.location.pathname);
    }

    history.pushState(null, null, window.location.pathname);

}, false);

注意:为了获得最佳结果,应仅在要实现逻辑的特定页面上加载此代码,以避免任何其他意外问题。

每次当当前历史记录条目更改(用户导航到新状态)时,都会触发 popstate 事件。当用户单击浏览器的“后退/前进”按钮或 以编程方式调用 时,就会发生这种情况。history.back()history.forward()history.go()

事件的 is 属性等于历史记录状态对象。event.state

对于jQuery语法,请将其换行(在文档准备就绪后添加甚至侦听器):

(function($) {
  // Above code here.
})(jQuery);

另请参阅:页面加载时的 window.onpopstate


另请参阅单页应用程序和 HTML5 pushState 页面上的示例

<script>
// jQuery
$(window).on('popstate', function (e) {
    var state = e.originalEvent.state;
    if (state !== null) {
        //load content with ajax
    }
});

// Vanilla javascript
window.addEventListener('popstate', function (e) {
    var state = e.state;
    if (state !== null) {
        //load content with ajax
    }
});
</script>

这应该与Chrome 5 +,Firefox 4 +,IE 10 +,Safari 6 +,Opera 11.5 +等兼容。