更改window.location.hash会在历史记录中创建条目,但不会影响Chrome后退按钮

时间:2019-09-27 06:26:56

标签: javascript google-chrome browser-history html5-history

更新:-Akansh Gulati指出,如果用户在单击“后退”按钮之前与页面有任何交互,将按预期工作,并且如果用户与页面并按返回按钮,那么历史记录中的任何条目(通过哈希更改或history.push / replace)都将被忽略,这是Google Chrome update will stop websites hijacking your browser back button

的一部分

这是有效且合乎逻辑的答案,所以我接受他的答案


我正在尝试在页面加载后显示成功弹出窗口,并且如果用户按下android后退按钮(在这种情况下等效于浏览器后退按钮),我只想关闭弹出窗口(不希望在付款时重定向回去)页)

我在打开弹出窗口时在url中添加哈希,但是当用户按返回按钮chrome时,忽略哈希并重定向回上一页,而不仅仅是删除哈希(在Firefox中可以正常工作)

我有一个有效的示例here

a)用Chrome打开此页面

b)等到哈希更改为“ #c”

c)然后按浏览器后退按钮

预期的行为是它应将散列更改回“ #b”,然后再更改回“ #a” 但它会忽略所有哈希更改,然后重定向回新标签页

这是code

      window.location.hash = 'a';
      setTimeout(function() {
        writeLength();
        window.location.hash = 'b';
        setTimeout(function() {
          writeLength();
          window.location.hash = 'c';
          setTimeout(function() {
            writeLength();
          }, 1500);
        }, 1500);
      }, 1500);

如何模拟正确的行为(如果可以的话)?

我在Mac上使用的是Chrome版本77.0.3865.90(正式版本)(64位)

这是行为的GIF图片

actual behavior GIF image

4 个答案:

答案 0 :(得分:4)

在此浏览器中,您需要通过History API在历史记录中至少设置一个状态(虽然不确定为什么)。

即使在此iframe中,该示例也应适用。

history.replaceState( {}, '' );

window.location.hash = 'a';
setTimeout(function() {
  console.log( location.hash );
  window.location.hash = 'b';
  setTimeout(function() {
    console.log( location.hash );
    window.location.hash = 'c';
    setTimeout(function() {
      console.log( location.hash );
      console.log( "You can now use your browser's back button" );
      onpopstate = e => console.log( location.hash );
    }, 150);
  }, 150);
}, 150);

答案 1 :(得分:1)

我尝试使用pushState进行进一步的位置更改,并且问题似乎已解决。无需replaceState。条件是用户必须至少在屏幕上单击/交互一次。

function test() {
        window.location.hash = 'a';
        setTimeout(function () {
            writeLength();
            window.history.pushState(null, null, `${window.location.pathname}#b`);
            setTimeout(function () {
                writeLength();
                window.history.pushState(null, null, `${window.location.pathname}#c`);
                setTimeout(function () {
                    writeLength();
                }, 1500);
            }, 1500);
        }, 1500);
    }

答案 2 :(得分:0)

您必须显式设置状态,然后单击后退按钮即可执行一些代码,如下所示:

添加一个函数以获取不包含哈希部分的window.location.href(因为我们将对其进行显式添加):

function getUrlWithoutTheHash() {
    let url = window.location.href;
    let hash = window.location.hash;
    let index_of_hash = url.indexOf(hash) || url.length;
    return url.substr(0, index_of_hash);
}

添加一个用于推送状态的函数(而不是使用位置来更改哈希,而是使用状态API进行更改),并且我们将向状态添加属性is-my-state来知道这是否是我们的状态:

function pushTheState(url) {
    history.pushState({'is-my-state': true, 'url': url}, null, url);
}

并在打开状态时添加处理程序,如果这是您的状态之一,则可以执行所需的代码:

window.onpopstate = function(e){
    if(e.state){
        if(e.state.hasOwnProperty('is-my-state')){
            writeLength();
        }
    }
};

最后,您需要像这样更改功能:

function test() {
    pushTheState(getUrlWithoutTheHash() + '#a');    // pushing url with #a
    setTimeout(function() {
        writeLength();
        pushTheState(getUrlWithoutTheHash() + '#b');    // pushing url with #b
        setTimeout(function() {
            writeLength();
            pushTheState(getUrlWithoutTheHash() + '#c');    // pushing url with #c
            setTimeout(function() {
                writeLength();
            }, 1500);
        }, 1500);
    }, 1500);
}

答案 3 :(得分:0)

我能够在Windows 10的同一版本的Chrome上使用您提供的代码,但是如果仍然遇到问题,则应该可以使用以下代码。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
  </head>
  <body onload="test()">
    <div id="url"></div>
    <button type="button" onclick="window.history.back();">Back</button>
  </body>
  <script type="text/javascript">
    setInterval(function(){
      document.getElementById('url').innerHTML = window.location.href;
    }, 500);
    function writeLength() {
      document.body.appendChild(document.createTextNode(window.history.length));
    }
    function test() {
      history.pushState({},'','#a');
      setTimeout(function() {
        writeLength();
        history.pushState({},'','#b');
        setTimeout(function() {
          writeLength();
          history.pushState({},'','#c');
          setTimeout(function() {
            writeLength();
          }, 1500);
        }, 1500);
      }, 1500);
    }
  </script>
</html>

这应该起作用,因为window.pushState应该将哈希更改强制添加到浏览器的历史记录中。如果要更新导航更改的页面,则可以使用window.onpopstate事件。例如:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
  </head>
  <body onload="test()">
    <div id="url"></div>
    <button type="button" onclick="window.history.back();">Back</button>
    <span id="lengths"></span>
</body>
  <script type="text/javascript">
    setInterval(function(){
      document.getElementById('url').innerHTML = window.location.href;
    }, 500);
    var last = false;
    var items = [];
    function writeLength() {
    items.push(window.history.length);
       document.getElementById('lengths').appendChild(document.createTextNode(window.history.length));
    }
    function test() {
     history.pushState({},'','#a'); 
      setTimeout(function() {
        writeLength();
        history.pushState({},'','#b');
        setTimeout(function() {
          writeLength();
          history.pushState({},'','#c');
          setTimeout(function() {
            writeLength();
            last = true;
          }, 1500);
        }, 1500);
      }, 1500);
    }
    window.onpopstate = function(){
      if (last) {
        if (window.location.hash == '#a') document.getElementById('lengths').innerHTML = items[0];
        else if (window.location.hash == '#b') document.getElementById('lengths').innerHTML = '' + items[0] + items[1];
        else if (window.location.hash == '#c') document.getElementById('lengths').innerHTML = '' + items[0] + items[1]+ items[2];
      }
    }
  </script>
</html

上面的代码允许用户在将最终长度写到文档之后导航到页面的不同“状态”。