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

问题描述 投票:167回答:15

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

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

为什么地球上没有浏览器按钮触发他们自己的事件!?

javascript cross-browser single-page-application back
15个回答
150
投票

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

这是我开始研究documentwindow之间的区别。我的最终解决方案是使用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
    }
}

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

编辑:

为了确保用户不使用退格键来触发后退事件,您还可以包含以下内容(感谢this Question上的@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();
            }
        }
    });
});

1
投票
 <input style="display:none" id="__pageLoaded" value=""/>


 $(document).ready(function () {
        if ($("#__pageLoaded").val() != 1) {

            $("#__pageLoaded").val(1);


        } else {
            shared.isBackLoad = true;
            $("#__pageLoaded").val(1);  

            // Call any function that handles your back event

        }
    });

上面的代码对我有用。在移动浏览器上,当用户单击后退按钮时,我们希望按照上次访问恢复页面状态。


1
投票

我能够在这个帖子和其他人中使用一些答案,让它在IE和Chrome / Edge中运行。 IE11不支持history.pushState。

if (history.pushState) {
    //Chrome and modern browsers
    history.pushState(null, document.title, location.href);
    window.addEventListener('popstate', function (event) {
        history.pushState(null, document.title, location.href);
    });
}
else {
    //IE
    history.forward();
}

0
投票

我通过跟踪触发hashchange的原始事件(无论是滑动,点击还是滚轮)解决了这个问题,因此事件不会被误认为是简单的登陆页面,并且使用了额外的标志在我的每个事件绑定中。点击后退按钮时,浏览器不会再将标志设置为false

var evt = null,
canGoBackToThePast = true;

$('#next-slide').on('click touch', function(e) {
    evt = e;
    canGobackToThePast = false;
    // your logic (remember to set the 'canGoBackToThePast' flag back to 'true' at the end of it)
}

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

这是唯一一个对我有用的解决方案(它不是一个网页)。它与Chrome,Firefox和Safari一起使用。


0
投票

正确的答案已经回答了这个问题。我想提一下新的JavaScript API PerformanceNavigationTiming,它正在取代弃用的performance.navigation

如果用户使用后退或前进按钮登陆页面,则以下代码将登录控制台“back_forward”。 Take a look at compatibility table before using it in your project.

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

0
投票

我用下面的技巧完成了这个任务。当有人回到带有浏览器后退按钮的页面时,这个添加的事件监听器被调用,并且在那个事件中重新加载了页面。希望有所帮助。

window.addEventListener("pageshow", function(event) {
  var historyTraversal = event.persisted || (typeof window.performance !=
    "undefined" && window.performance.navigation.type === 2);
  if (historyTraversal) {
    // Handle page restore. 
    window.location.reload();
  }
});

在页面底部添加了此代码。


-18
投票

我尝试了上面的选项,但没有一个适合我。这是解决方案

if(window.event)
   {
        if(window.event.clientX < 40 && window.event.clientY < 0)
        {
            alert("Browser back button is clicked...");
        }
        else
        {
            alert("Browser refresh button is clicked...");
        }
    }

有关更多详细信息,请参阅此链接http://www.codeproject.com/Articles/696526/Solution-to-Browser-Back-Button-Click-Event-Handli


63
投票

你可以试试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是事件的属性等于历史状态对象。

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

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

另见:window.onpopstate on page load


另请参阅Single-Page Apps and 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+等。


13
投票

我一直在努力解决这个问题很长一段时间,并采取了上面的一些解决方案来实现它。然而,我偶然发现了一个观察结果,它似乎适用于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
  }
}

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


9
投票

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

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

5
投票

这肯定有效(用于检测后退按钮点击)

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

4
投票

浏览器: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>

2
投票

这是我的看法。假设是,当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);

2
投票

看到这个:

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

它工作得很好......


1
投票

document.mouseover不适用于IE和FireFox。不过我试过这个:

$(document).ready(function () {
  setInterval(function () {
    var $sample = $("body");
    if ($sample.is(":hover")) {
      window.innerDocClick = true;
    } else {
      window.innerDocClick = false;
    }
  });

});

window.onhashchange = function () {
  if (window.innerDocClick) {
    //Your own in-page mechanism triggered the hash change
  } else {
    //Browser back or forward button was pressed
  }
};

这适用于Chrome和IE,而不适用于FireFox。仍然努力使FireFox正确。检测浏览器后退/前进按钮点击的任何简单方法都是受欢迎的,特别是在JQuery中,还有AngularJS或普通Javascript。

© www.soinside.com 2019 - 2024. All rights reserved.