将窗口绑定到popstate事件会触发两次。

5

在jQuery中,简单地将窗口与popstate绑定,该事件总是触发两次。

$( window ).bind( 'popstate', myFunction );

这个问题不是由myFunction()引起的 - 我已经尝试将该函数简化为以下内容:

console.log( 'triggered' );

结果是相同的。它总是被触发两次(在Safari、Chrome和Firefox中测试过)。

我知道HTML5历史API存在问题,但除了“尝试使用History.js”之外,是否有其他建议,将不胜感激!


无法在FF 10中重现。你能展示一下完整的代码吗? - Rob W
嗨@RobW-“完整”的代码有3000多行!但是myFunction()似乎与事件触发两次无关。我仍然在FF 10.0.1(OSX)中遇到问题。 - Richard Sweeney
如果您在ASP.NET中使用常规的ASP:button,它会尝试执行history.go/back,然后执行asp.net postback,这也可能会出现此问题。 - StingyJack
4个回答

6

好的,我找到了解决方法:

jQuery( function(){

  var currentPageNo = location.hash || 1;

  var myFunction = function(){

    var pageNo = location.hash;

    if( pageNo != currentPageNo ){

      // trigger AJAX stuff here

      currentPageNo = pageNo;

    }

  };

  $( window ).bind( 'popstate', myFunction );

});

只触发一次函数,但状态仍被触发两次!


4

这并没有直接回答问题,但对于其他发现此问题的人可能有所帮助。因为我只需要监听一次popstate事件,然后立即移除监听器。

如果你想在触发popstate事件后(仅一次)销毁监听器,你可以将以下对象添加到addEventListener的第三个参数中:

window.addEventListener('popstate', myFunction, {once: true});

once

一个布尔值,表示侦听器在添加后最多只会被调用一次。如果为 true,则侦听器在调用后会自动移除。

这是文档链接:https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener


1
这解决了我的问题。通过导航“后退”和“前进”,我意识到我不小心注册了两次后退按钮事件监听器。 - Josh McGee

2
当使用历史记录API,如history.back()和history.go(-1)时,popstate事件会触发两次。但是使用浏览器的后退按钮只会触发一次。
我使用超时作为解决方法:
var timeout = null;
$(window).bind('popstate', function(event) {
    clearTimeout(timeout);
    timeout = setTimeout(function() {
        console.log( 'triggered' );
    }, 50);
});

0

在处理ReactJS中的后退按钮时,我遇到了以下问题:

  1. 第一次未调用popstate事件
  2. 在执行自定义后退逻辑后,它被调用两次

为了解决问题1,我编写了以下代码:

  componentDidMount() {
    window.history.pushState(null, null, window.location.pathname);
    window.addEventListener('popstate', this.onBackButtonEvent);
  }

为了解决问题2,我编写了以下代码:

   onBackButtonEvent = (e) => {
    e.preventDefault();
    if (!this.isBackButtonClicked) {

  if (window.confirm("Do you want to save your changes")) {
       this.isBackButtonClicked = true;
       // your custom logic to page transition
        } else {
         window.history.pushState(null, null, window.location.pathname);
         this.isBackButtonClicked = false;
       }
    }
  }

不要忘记在构造函数中添加this.isBackButtonClicked = false;并取消订阅事件。
  componentWillUnmount = () => {
    window.removeEventListener('popstate', this.onBackButtonEvent);
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接