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

IT技术 javascript cross-browser single-page-application back
2021-02-01 06:47:21

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

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

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

6个回答

(注意:根据 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
    }
}

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

编辑:

为确保用户不使用退格键触发 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();
            }
        }
    });
});
移动设备怎么样(例如 ipad)
2021-03-21 06:47:21
如何区分前进和后退按钮?
2021-03-28 06:47:21
+1 好主意,但我认为如果用户在鼠标位于浏览器窗口内时使用任何用于“后退”的键盘快捷键(firefox 上的退格键),这将失败
2021-03-30 06:47:21
从 MAC 中的触控板滑动事件怎么样。也能拍出来吗?
2021-04-04 06:47:21
会做 - 反正我现在在办公室:)(编辑:现在完成)
2021-04-07 06:47:21

您可以尝试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()方法就会发生这种情况

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

对于 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+ 和类似版本兼容。

e.state 在现代浏览器中似乎总是未定义
2021-03-17 06:47:21
Kenorb,您说 popstate 可以抓取更改是正确的,但它并没有区分以编程方式调用事件和用户单击浏览器按钮的时间。
2021-03-19 06:47:21
我建议你把你的代码放在一个片段中,这样你就可以直接在这里运行它。
2021-03-20 06:47:21
关于单页应用程序和 HTML5 pushState 的好帖子非常适合现代“单页布局”或“单页应用程序”。谢谢你的链接和你的回答!
2021-04-01 06:47:21
当在同一文档的两个历史条目之间导航时,popstate 事件仅通过执行浏览器操作触发,例如单击后退按钮(或在 JavaScript 中调用 history.back())。developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/...
2021-04-01 06:47:21

我已经为这个要求苦苦挣扎了一段时间,并采用了上面的一些解决方案来实现它。然而,我偶然发现了一个观察结果,它似乎适用于 Chrome、Firefox 和 Safari 浏览器 + Android 和 iPhone

在页面加载时:

window.history.pushState({page: 1}, "", "");

window.onpopstate = function(event) {

  // "event" object seems to contain value only when the back button is clicked
  // and if the pop state event fires due to clicks on a button
  // or a link it comes up as "undefined" 

  if(event){
    // Code to handle back button or prevent from navigation
  }
  else{
    // Continue user action through link or button
  }
}

如果这有帮助,请告诉我。如果遗漏了什么,我会很乐意理解。

不对。event即使对于前进按钮也有value
2021-03-11 06:47:21

在 javascript 中,导航类型2意味着点击浏览器的后退或前进按钮,浏览器实际上是从缓存中获取内容。

if(performance.navigation.type == 2)
{
    //Do your code here
}
这不适用于单页应用程序,结果始终为 1(这意味着重新加载)。而且它没有区分后退和前进按钮,这是非常不幸的。
2021-03-11 06:47:21
这在弃用后有效,我不确定跨浏览器兼容性: if (String(window.performance.getEntriesByType("navigation")[0].type) === "back_forward") { // 在此处执行代码}
2021-03-22 06:47:21
“此外,它没有区分后退和前进按钮,这是非常不幸的。”是的,因为每当从缓存中获取数据时,performance.navigation.type 都是 2
2021-03-29 06:47:21
2021-04-04 06:47:21
我不在乎。它对我有用,很好!2020 年 12 月
2021-04-06 06:47:21
if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
  alert('hello world');
}

这是唯一对我有用的解决方案(它不是单页网站)。它适用于 Chrome、Firefox 和 Safari。

window.performance.navigation 已被弃用。这是文档developer.mozilla.org/en-US/docs/Web/API/Performance/navigation
2021-03-20 06:47:21
@llaaalu 这在弃用后有效,我不确定跨浏览器兼容性: if (String(window.performance.getEntriesByType("navigation")[0].type) === "back_forward") { // 做你的代码在这里}
2021-04-03 06:47:21
这在我的 .cshtml 页面上对我有用。在 Chrome 和 IE 上成功运行。谢谢
2021-04-07 06:47:21