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

如何使用#URL系统在单页web应用程序中强制使用页面内返回按钮?

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


当前回答

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

该事件。状态是事件的属性,等于历史状态对象。

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

其他回答

以下是我的看法。假设是,当URL更改但检测到文档内没有单击时,它是浏览器返回(是的,或向前)。用户点击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);

这将肯定工作(用于检测返回按钮点击)

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

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

移动控制: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>

Kotlin/JS (React)的解决方案:

import org.w3c.dom.events.Event
import kotlin.browser.document
import kotlin.browser.window

...
override fun componentDidMount() {
    window.history.pushState(null, document.title, window.location.href)
    window.addEventListener("popstate", actionHandler)
}
...
val actionHandler: (Event?) -> Unit = {
    window.history.pushState(
        null,
        document.title,
        window.location.href
    )
    // add your actions here
}

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

所以这将移动用户回到最后的哈希,并从数组中删除最后的哈希(我现在没有前进按钮)。

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

起初我看着窗户。Onbeforeunload,但是没有用——只有当用户要更改页面时才会调用它。这在使用散列导航的单页应用程序中不会发生。

因此,在深入研究之后,我看到了尝试设置标志变量的建议。在我的情况下,这个问题是,我会试着设置它,但由于一切都是异步的,它并不总是在哈希中的if语句更改时设置。onmousedown并不总是在点击中调用,并将其添加到onclick中不会足够快地触发它。

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

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

这样,我就可以换窗口了。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。我使用它来询问用户是否想要使用窗口离开。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
    }
}

结果出来了。关于哈希导航,一种简单的、由三部分组成的方法来检测后退按钮的使用情况与页面内元素的使用情况。

编辑:

为了确保用户不会使用backspace来触发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();
            }
        }
    });
});