猿问

Chrome/Opera `window.onpopstate` 错误

我正在尝试处理window.onpopstate我的单页应用程序中的事件,但在 Google Chrome 和 Opera 中它不起作用。


这是我的简单 html 页面


<html>

    <head>

        <meta charset="utf-8" />

        <script>

        window.onpopstate = function(e) {

            alert('onpopstate');

        }

        setTimeout(function () {

            history.pushState(1, 'Hello John', '/hello/john');

        }, 2000);

        setTimeout(function () {

            history.pushState(2, 'Hello Emily', '/hello/emily');

        }, 3000);

        </script>

    </head>

    <body></body>

</html>

当我点击浏览器的后退按钮时,我希望看到带有onpopstate显示文本的警报。在 Safari、Firefox、Vivaldi 中,它按预期工作。在 Chrome 和 Opera 中,它从未调用过,它只是通过重新加载来转到上一页,这对我的 SPA 来说是一个糟糕的情况。

更奇怪的是我发现了一些让它发挥作用的技巧:

  1. 转到开发工具,控制台选项卡

  2. 但是,如果我在有或没有超时的页面上的脚本中执行相同的操作,则此技巧根本不起作用。因此,我发现完成工作的唯一方法是手动转到控制台并执行。console.log(history)console.log(window)onpopstateconsole.log(history)

也许我错过了什么?任何帮助,将不胜感激。

我的环境:

  • macOS 11.0.1 (20B29)

  • Chrome 87.0.4280.67(官方版本)(x86_64)

  • 歌剧 72.0.3815.378

解决方案:

好吧,这不是一个错误,这是一个功能!这是interact firstChromium 的一个特性。如果用户首先以某种方式与页面交互,那么一切都会正常,否则back button将通过重新加载返回。

例如,只需在正文中添加一些按钮并先单击它,然后尝试back在浏览器中单击。

<body>
    <button onclick="alert('hello');">alert</button>
    </body>


偶然的你
浏览 211回答 2
2回答

慕后森

为了能够运行一些 JavaScript,例如移动历史记录或播放声音或弹出窗口,用户首先必须在网站上进行交互(单击)。

互换的青春

我在 MDN 上找到了一个注释。它说:注意:调用history.pushState()或history.replaceState()不会触发popstate事件。popstate 事件仅通过执行浏览器操作来触发,例如在同一文档的两个历史记录条目之间导航时单击后退按钮(或在 JavaScript 中调用history.back())。我建议您将事件处理程序注册到WindowEventHandlers 的 onpopstate 属性addEventListener(),而不是注册到WindowEventHandlers的onpopstate属性。例子:<html>    <head>        <meta charset="utf-8" />        <script>            // ref: https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event            window.addEventListener('popstate', function(e) {                alert('onpopstate');            }            setTimeout(function () {                history.pushState(1, 'Hello John', '/hello/john');            }, 2000);            setTimeout(function () {                history.pushState(2, 'Hello Emily', '/hello/emily');            }, 3000);        </script>    </head>    <body></body></html>

慕斯王

使用 anObject表示state。状态对象是一个 JavaScript 对象,与 PushState() 创建的新历史记录条目相关联。每当用户导航到新状态时,都会触发 popstate 事件,并且该事件的 state 属性包含历史记录条目的状态对象的副本。const log = Logger();// create 3 'history pages'history.pushState({page: 1, greet: "Hello John"}, '', "#John");history.pushState({page: 2, greet: "Hello Emily"}, '', "#Emily");history.pushState({page: 3, greet: "Hello James"}, '', "#James");log(`current history state: ${JSON.stringify(history.state)}`);// on popstate log the history state if applicablewindow.addEventListener("popstate", () =>  history && history.state && log(`${history.state.greet || ""} @page ${    history.state.page} (location: ${location.hash})`));// listener for the buttonsdocument.addEventListener("click", evt => {  if (evt.target.nodeName === "BUTTON") {    return evt.target.id === "back" ? history.back() : history.forward();  }});// helper function for logging in the documentfunction Logger() {  let logEl;  if (typeof window === "object") {    logEl = document.querySelector("#log") || (() => {      document.body.append(        Object.assign(document.createElement('pre'),         {id: "log"}));      return document.querySelector("#log");    })();    return (...logLines) =>       logLines.forEach(s => logEl.textContent += `${s}\n`);  } else {    return (...logLines) =>       logLines.forEach(ll => console.log(`* `, ll));  }}<button id="back">&lt;&lt; 1 back</button><button id="forward">1 forward &gt;&gt;</button>
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答