window.onpopstate无法正常工作;当我返回页面时,什么也没有发生。

19

我正在尝试在我的网站上的一个页面上添加 window.onpopstate,但没有任何反应。我在页面上放置了以下脚本:

<script type="text/javascript">
  window.addEventListener('popstate', function(event) {
    if (event.state) {
      alert(event.state);
    }
  }, false);
</script>

我也尝试过:

<script type="text/javascript">
  window.onpopstate = function() {
    alert("popped!");
  }
</script>

然而,当我返回到该页面时,我没有收到任何警报。


我在https://www.codeguage.com/courses/js/events-popstate-event找到了一个非常好的和详细的`popstate`事件解释。 - coderboy
3个回答

33
你只有在添加一个或多个历史记录条目后,用户点击浏览器的“返回”按钮时才会收到 popstate 事件。
将条目添加到浏览器历史记录中可以更改 URL(就像用户导航到另一页一样),但实际上不会加载新页面。
使用 pushState 方法添加历史记录条目:
history.pushState({}, '', '/newpage');

当您添加一个条目并且用户点击返回时,URL会切换回先前的URL,但该地址上的页面不会加载。而是触发了popstate事件。
请参见https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history

异常情况:

旧版浏览器不支持popstate事件和浏览器历史记录的操作。

一些浏览器(例如Safari)在实际加载页面时也会触发popstate事件。


假设我在Chrome DevTools控制台中编写window.addEventListener('popstate', (e) => console.log(e)),我如何在单击返回按钮后查看控制台日志? - Akin Hwan
1
@AkinHwan popstate 只有在从 pushedState 到先前状态(或类似状态)时才会触发。如果您从另一页导航回第一页,则不会触发。 - getup8
那么你的意思是,如果我已经加载了“http://localhost/page.html#1234”,然后我*手动*输入“http://localhost/page.html#5678”来加载基本相同的页面,然后点击返回按钮,onpopstate 不会被调用,即使它是完全相同的页面? - Michael
这对我来说是缺失的部分。我尝试使用浏览器的返回按钮关闭移动导航,但popstate从未被触发。我的做法是,每当导航打开时,设置一个本地变量_navIsOpened = true并推送一个新的历史状态history.pushState(null, null, window.location.pathname);让我停留在同一页上,并在使用后退按钮时,如果_navIsOpened保持相同页面与相同的新历史状态推送或者使用history.back()回退✌️✌️✌️ - eballeste
你也可以查看这个简单的过程:https://dev59.com/M2oMtIcB2Jgan1znfCIS - RationalRabbit

2
window.onpopstate = function(event) {
  alert(`location: ${document.location}, state: ${JSON.stringify(event.state)}`)
}

history.pushState({page: 1}, "title 1", "?page=1")
history.pushState({page: 2}, "title 2", "?page=2")
history.replaceState({page: 3}, "title 3", "?page=3")
history.back() // alerts "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back() // alerts "location: http://example.com/example.html, state: null"
history.go(2)  // alerts "location: http://example.com/example.html?page=3, state: {"page":3}"

6
虽然这段代码可能回答了问题,但是提供关于为什么和/或如何回答问题的额外上下文信息可以提高其长期价值。 - Ahmet Emre Kilinc

0
如果有人在React-JS中遇到这个问题,
假设你有一个useEffect(),想要在每次重新渲染或(前进/后退)时记录popState。
 useEffect(() => {
    function handlePopStateEvent(e) {
        console.log(e);
        console.log("Check if the function Working")

    }

    console.log("Check if Effect Working")

    window.addEventListener("popstate", handlePopStateEvent);

    return () => window.removeEventListener("popstate", handlePopStateEvent);

}, []);

你需要使用history.pushState()手动添加一些历史记录,即使你手动输入了一些URL路径,比如说你在URL中输入了以下路径:
http://localhost:5173/lab
http://localhost:5173/home http://localhost:5173/blog
http://localhost:5173/about
这样是行不通的,popState()事件不会记录任何内容,如果你尝试手动调用函数来查看日志,你会得到undefined。
解决方法是,在控制台中添加一些历史记录,像这样:
history.pushState({}, '', '/home');
history.pushState({}, '', '/blog');
history.pushState({}, '', '/about');
history.pushState({}, '', '/lab');

Add history to the browser manullay using history.pushState() in the console

然后当你在浏览器中使用后退/前进箭头或者Alt + (← →)时,popState()将会在控制台中记录如下内容。

Logging the popState event in the console on Fowrard/Back

在每个“后退/前进”操作中。
为了更好地理解这种行为,您可以查看MDN上关于History API、popState和history.push()的内容。
以下是MDN的描述:

Window接口的popstate事件在用户浏览会话历史时,当活动历史记录条目发生更改时触发。它将当前历史记录条目更改为用户最后访问的页面的历史记录条目,或者如果使用history.pushState()向历史记录堆栈添加了历史记录条目,则使用该历史记录条目。

链接:https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event

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