Javascript window.onpopstate, event.state == null?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11092736/
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-24 04:25:16  来源:igfitidea点击:

window.onpopstate, event.state == null?

javascripthtmldom-events

提问by mihok

I've read several question/answers on Stack Overflow and Googled the issue, I can't seem to get the event.stateto come back with anything but null.

我在 Stack Overflow 上阅读了几个问题/答案,并在谷歌上搜索了这个问题,我似乎无法得到event.state除了null.

I got that it wont work with the jQuery event, but when I do something like this:

我知道它不适用于 jQuery 事件,但是当我执行以下操作时:

window.onpopstate = function (e) {
     console.log(e.state)
}

With something along the lines of a jQuery.ajax success calling

与 jQuery.ajax 成功调用类似

history.pushState({ lastUrl: data.State }, data.Title, data.UrlKey);

Neither Chrome (v19) or Firefox (v12) return anything but null? Am I missing something? Is it just not fully implemented?

Chrome (v19) 或 Firefox (v12) 都不返回空值?我错过了什么吗?它只是没有完全实施吗?

回答by Jaco Briers

e.staterefers to the second last state that was pushed. You need to have pushed state at least twice for e.stateto not be null. This is because you should save the state when your site is loaded the first time and thereafter every time it changes state.

e.state指的是被推送的倒数第二个状态。您需要至少两次推送状态e.state才能不是null. 这是因为您应该在第一次加载站点时保存状态,此后每次更改状态时都应该保存状态。

回答by MQ87

I think that this question needs a more clear explanation because the sentence "second last state that was pushed" in the other answers may lead to confusion.

我认为这个问题需要更清楚的解释,因为其他答案中的“倒数第二状态”这句话可能会导致混淆。

When we do history.pushState we are pushing into the history stack a new State, that becomes the current one (as we can see from the navigation bar url.)

当我们执行 history.pushState 时,我们将一个新状态推入历史堆栈,它成为当前状态(正如我们从导航栏 url 中看到的那样。)

The window.onpopstate event means that the top history state is being popped out (taken away from the stack) , so the e.state will now point to the new new top state in the stack (as the navigation bar will point to the previous url).

window.onpopstate 事件意味着顶部历史状态被弹出(从堆栈中取出),所以 e.state 现在将指向堆栈中新的新顶部状态(因为导航栏将指向前一个状态)网址)。

回答by Panu Logic

I struggled with this same issue for many hours. Too many hours. The state-argument of onpopstate -handler was null even though I had called pushState() many times before I clicked the back-button.

我在这个问题上挣扎了好几个小时。太多小时了。即使我在单击后退按钮之前多次调用 pushState() , onpopstate -handler 的状态参数也是空的。

I also observed that my onclick-handler which called pushState() caused the onpopstate -handler to be triggered. I believe onpopstate -handler should only get called due to user clicking on the back-button from what I read on the web. But that seemed not to be the case in my case.

我还观察到我的 onclick-handler 调用 pushState() 导致 onpopstate -handler 被触发。我相信 onpopstate -handler 应该只在用户点击我在网上阅读的后退按钮时被调用。但就我而言,情况似乎并非如此。

Could there be a bug in the browser? Seems unlikely because I had the same or similar problem on both Chrome and FireFox. But possible. Or maybe there is a "bug in the spec" being too complicated to implement correctly. No public unit-tests showing how this should work.

浏览器可能有错误吗?似乎不太可能,因为我在 Chrome 和 FireFox 上都遇到了相同或类似的问题。但有可能。或者也许有一个“规范中的错误”太复杂而无法正确实现。没有公开的单元测试显示这应该如何工作。

Finally I arrived at a solution after which EVERYTHING started working. It was to put these two calls into my onload-handler:

最后我找到了一个解决方案,之后一切都开始工作了。是将这两个调用放入我的 onload-handler 中:

pushState (myInitialState, null, href);
pushState (myInitialState, null, href);

So I have to make the same push-state() call TWICE in the onload-handler! After that my onpopstate -handler started getting arguments whose state was NOT null but a state I had previously passed as argument to pushState().

所以我必须在 onload-handler 中进行相同的 push-state() 调用两次!之后,我的 onpopstate -handler 开始获取状态不为空的参数,而是我之前作为参数传递给 pushState() 的状态。

I don't really understand why it now works and why it didn't earlier when I called pushState ONLY ONCE.

我真的不明白为什么它现在可以工作,为什么在我只调用一次 pushState 时它没有更早。

I would like to understand why it works now but I already spent too much time with this getting it to work. If anybody has a reference to good example-code online which explains it that would be great.

我想了解它为什么现在起作用,但我已经花了太多时间让它起作用。如果有人参考了好的示例代码在线解释它会很棒。

回答by W.Leto

It will be helpful if you have ever learnt about the undo/redo stack, as the picture shows below.

如果您曾经了解过撤消/重做堆栈,将会很有帮助,如下图所示。

enter image description here

在此处输入图片说明

In fact, the history is kept in a stack like this. Your current state is from current stack item, and let's assume there is a pointer to it; when you call history.back(), the pointer go to older item of the stack, the onpopstateevent's state is the same as history.stateby the way. You will just get the item which pointer currently pointing at, which modified by history.replaceStateor added by history.pushState.

事实上,历史是这样保存在一个堆栈中的。您当前的状态来自当前堆栈项,假设有一个指向它的指针;当您调用 时history.back(),指针会指向堆栈中较旧的项目,顺便提一下,该onpopstate事件的状态是相同history.state的。您将只获得指针当前指向的项目,由 修改history.replaceState或添加的项目history.pushState

This process also explains why history.lengthdoesn't change, because it represents the whole stack's length. When you call history.go(1), the pointer move back to the newer item.

这个过程也解释了为什么history.length不变,因为它代表了整个栈的长度。当您调用 时history.go(1),指针将移回较新的项目。

When the pointer is at a middle position of stack, calling history.pushStatewill lead to all the items above the pointer popped, and new one added, also you can see history'lengthchanges.

当指针在栈的中间位置时,调用history.pushState会弹出指针上面的所有项目,并添加新的项目,你也可以看到history'length变化。

回答by thdoan

As Jaco Briers mentioned, for popstateto work the way we think it should work, we need to first store the initial state to return to when you click on the browser's Back button. Here's a sample implementation using jQuery:

正如 Jaco Briers 提到的,为了popstate按照我们认为应该工作的方式工作,我们需要首先存储初始状态以在您单击浏览器的后退按钮时返回。这是使用 jQuery 的示例实现:

Sample Code

示例代码

$(window).on({
  // Store initial state
  'load': function() {
    window.history.pushState({
      'html': '<div id="ajax-content">' + $('#ajax-content').html() + '</div>'
    }, '', document.URL);
  },
  // Handle browser Back/Forward button
  'popstate': function(e) {
    var oState = e.originalEvent.state;
    if (oState) {
      $('#ajax-content').replaceWith(oState.html);
    }
  }
});

...

// Update AJAX content
var sUrl = 'https://www.example.com/category?id=123&format=ajax';
$.ajax({
  type: 'GET',
  url: sUrl,
  success: function(sHtml) {
    $('#ajax-content').replaceWith(sHtml);
    window.history.pushState({
      'html': sHtml
    }, '', sUrl);
  }
});