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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25806608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 21:53:53  来源:igfitidea点击:

How to Detect Browser Back Button event - Cross Browser

javascriptcross-browsersingle-page-applicationback

提问by Xarus

How do you definitively detect whether or not the user has pressed the back button in the browser?

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

How do you enforce the use of an in-page back button inside a single page web application using a #URLsystem?

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

Why on earth don't browser back buttons fire their own events!?

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

采纳答案by Xarus

(Note: As per Sharky's feedback, I've included code to detect backspaces)

(注意:根据 Sharky 的反馈,我已经包含了检测退格的代码)

So, I've seen these questions frequently on SO, and have recently run into the issue of controlling back button functionality myself. After a few days of searching for the best solution for my application (Single-Page with Hash Navigation), I've come up with a simple, cross-browser, library-less system for detecting the back button.

所以,我经常在 SO 上看到这些问题,最近我自己也遇到了控制后退按钮功能的问题。在为我的应用程序寻找最佳解决方案(带哈希导航的单页)几天后,我想出了一个简单的、跨浏览器、无库的系统来检测后退按钮。

Most people recommend using:

大多数人建议使用:

window.onhashchange = function() {
 //blah blah blah
}

However, this function will also be called when a user uses on in-page element that changes the location hash. Not the best user experience when your user clicks and the page goes backwards or forwards.

但是,当用户使用更改位置哈希的页面内元素时,也会调用此函数。当您的用户单击并且页面向后或向前时,这不是最佳的用户体验。

To give you a general outline of my system, I'm filling up an array with previous hashes as my user moves through the interface. It looks something like this:

为了让您大致了解我的系统,当我的用户在界面中移动时,我将用以前的散列填充一个数组。它看起来像这样:

function updateHistory(curr) {
    window.location.lasthash.push(window.location.hash);
    window.location.hash = curr;
}

Pretty straight forward. I do this to ensure cross-browser support, as well as support for older browsers. Simply pass the new hash to the function, and it'll store it for you and then change the hash (which is then put into the browser's history).

很直接。我这样做是为了确保跨浏览器支持,以及对旧浏览器的支持。只需将新的哈希值传递给函数,它就会为您存储它,然后更改哈希值(然后将其放入浏览器的历史记录中)。

I also utilise an in-page back button that moves the user between pages using the lasthasharray. It looks like this:

我还利用了一个页内后退按钮,使用该lasthash数组在页面之间移动用户。它看起来像这样:

function goBack() {
    window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
    //blah blah blah
    window.location.lasthash.pop();
}

So this will move the user back to the last hash, and remove that last hash from the array (I have no forward button right now).

因此,这会将用户移回最后一个散列,并从数组中删除最后一个散列(我现在没有前进按钮)。

So. How do I detect whether or not a user has used my in-page back button, or the browser button?

所以。如何检测用户是否使用了我的页内后退按钮或浏览器按钮?

At first I looked at window.onbeforeunload, but to no avail - that is only called if the user is going to change pages. This does not happen in a single-page-application using hash navigation.

起初我查看了window.onbeforeunload,但无济于事 - 只有在用户要更改页面时才会调用它。这不会发生在使用哈希导航的单页应用程序中。

So, after some more digging, I saw recommendations for trying to set a flag variable. The issue with this in my case, is that I would try to set it, but as everything is asynchronous, it wouldn't always be set in time for the if statement in the hash change. .onMouseDownwasn't always called in click, and adding it to an onclick wouldn't ever trigger it fast enough.

因此,经过更多的挖掘,我看到了尝试设置标志变量的建议。在我的情况下,这个问题是我会尝试设置它,但由于一切都是异步的,它不会总是及时设置哈希更改中的 if 语句。.onMouseDown并不总是在 click 中调用,并且将它添加到 onclick 不会足够快地触发它。

This is when I started to look at the difference between document, and window. My final solution was to set the flag using document.onmouseover, and disable it using document.onmouseleave.

这是我开始研究document, 和之间区别的时候window。我的最终解决方案是使用 设置标志document.onmouseover,并使用 禁用它document.onmouseleave

What happens is that while the user's mouse is inside the document area (read: the rendered page, but excluding the browser frame), my boolean is set to true. As soon as the mouse leaves the document area, the boolean flips to false.

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

This way, I can change my window.onhashchangeto:

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

You'll note the check for #undefined. This is because if there is no history available in my array, it returns undefined. I use this to ask the user if they want to leave using a window.onbeforeunloadevent.

您会注意到#undefined. 这是因为如果我的数组中没有可用的历史记录,它会返回undefined. 我用它来询问用户是否想使用window.onbeforeunload事件离开。

So, in short, and for people that aren't necessarily using an in-page back button or an array to store the history:

因此,简而言之,对于不一定使用页内后退按钮或数组来存储历史记录的人:

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
    }
}

And there you have it. a simple, three-part way to detect back button usage vs in-page elements with regards to hash navigation.

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

EDIT:

编辑:

To ensure that the user doesn't use backspace to trigger the back event, you can also include the following (Thanks to @thetoolman on this Question):

为确保用户不使用退格键触发 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();
            }
        }
    });
});

回答by kenorb

You can try popstateevent handler, e.g:

您可以尝试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);

Note: For the best results, you should load this code only on specific pages where you want to implement the logic to avoid any other unexpected issues.

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

The popstate event is fired each time when the current history entry changes (user navigates to a new state). That happens when user clicks on browser's Back/Forward buttons or when history.back(), history.forward(), history.go()methods are programatically called.

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

The event.stateis property of the event is equal to the history state object.

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

For jQuery syntax, wrap it around (to add even listener after document is ready):

对于 jQuery 语法,将其包装起来(在文档准备好后添加侦听器):

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

See also: window.onpopstate on page load

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



See also the examples on Single-Page Apps and HTML5 pushStatepage:

另请参阅单页应用程序和 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>

This should be compatible with Chrome 5+, Firefox 4+, IE 10+, Safari 6+, Opera 11.5+ and similar.

这应该与 Chrome 5+、Firefox 4+、IE 10+、Safari 6+、Opera 11.5+ 和类似版本兼容。

回答by Itzmeygu

I had been struggling with this requirement for quite a while and took some of the solutions above to implement it. However, I stumbled upon an observation and it seems to work across Chrome, Firefox and Safari browsers + Android and iPhone

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

On page load:

在页面加载时:

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
  }
}

Let me know if this helps. If am missing something, I will be happy to understand.

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

回答by Hasan Badshah

In javascript, navigation type 2means browser's back or forward button clicked and the browser is actually taking content from cache.

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

if(performance.navigation.type == 2)
{
    //Do your code here
}

回答by rohan parab

This will definitely work (For detecting back button click)

这肯定会起作用(用于检测后退按钮点击)

$(window).on('popstate', function(event) {
 alert("pop");
});

回答by Jorge Rocha

See this:

看到这个:

history.pushState(null, null, location.href);
    window.onpopstate = function () {
        history.go(1);
    };

it works fine...

它工作正常......

回答by llaaalu

Correct answer is already there to answer the question. I want to mention new JavaScript API PerformanceNavigationTiming, it's replacing deprecated performance.navigation.

正确答案已经存在以回答问题。我想提及新的 JavaScript API PerformanceNavigationTiming,它正在取代已弃用的performance.navigation

Following code will log in console "back_forward" if user landed on your page using back or forward button. Take a look at compatibility table before using it in your project.

如果用户使用后退或前进按钮登陆您的页面,以下代码将登录控制台“back_forward”。在您的项目中使用它之前,请查看兼容性表。

var perfEntries = performance.getEntriesByType("navigation");
for (var i = 0; i < perfEntries.length; i++) {
    console.log(perfEntries[i].type);
}

回答by escanxr

if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
  alert('hello world');
}

This is the only one solution that worked for me (it's not a onepage website). It's working with Chrome, Firefox and Safari.

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

回答by Limitless isa

Browser: https://jsfiddle.net/Limitlessisa/axt1Lqoz/

浏览器:https: //jsfiddle.net/Limitlessisa/axt1Lqoz/

For mobile control: https://jsfiddle.net/Limitlessisa/axt1Lqoz/show/

对于移动控制:https: //jsfiddle.net/Limitlessisa/axt1Lqoz/show/

$(document).ready(function() {
  $('body').on('click touch', '#share', function(e) {
    $('.share').fadeIn();
  });
});

// geri butonunu yakalama
window.onhashchange = function(e) {
  var oldURL = e.oldURL.split('#')[1];
  var newURL = e.newURL.split('#')[1];

  if (oldURL == 'share') {
    $('.share').fadeOut();
    e.preventDefault();
    return false;
  }
  //console.log('old:'+oldURL+' new:'+newURL);
}
.share{position:fixed; display:none; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,.8); color:white; padding:20px;
<!DOCTYPE html>
<html>

<head>
    <title>Back Button Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

</head>

<body style="text-align:center; padding:0;">
    <a href="#share" id="share">Share</a>
    <div class="share" style="">
        <h1>Test Page</h1>
        <p> Back button press please for control.</p>
    </div>
</body>

</html>

回答by TomTom101

Here's my take at it. The assumption is, when the URL changes but there has no click within the documentdetected, it's a browser back (yes, or forward). A users click is reset after 2 seconds to make this work on pages that load content via Ajax:

这是我的看法。假设是,当 URL 更改但在document检测到的范围内没有点击时,它是浏览器返回(是的,或向前)。用户单击 2 秒后重置,以在通过 Ajax 加载内容的页面上执行此操作:

(function(window, $) {
  var anyClick, consoleLog, debug, delay;
  delay = function(sec, func) {
    return setTimeout(func, sec * 1000);
  };
  debug = true;
  anyClick = false;
  consoleLog = function(type, message) {
    if (debug) {
      return console[type](message);
    }
  };
  $(window.document).click(function() {
    anyClick = true;
    consoleLog("info", "clicked");
    return delay(2, function() {
      consoleLog("info", "reset click state");
      return anyClick = false;
    });
  });
  return window.addEventListener("popstate", function(e) {
    if (anyClick !== true) {
      consoleLog("info", "Back clicked");
      return window.dataLayer.push({
        event: 'analyticsEvent',
        eventCategory: 'test',
        eventAction: 'test'
      });
    }
  });
})(window, jQuery);