单击一次之后*替换的链接新哈希值更新location.hash

时间:2019-11-27 22:10:19

标签: javascript dom-events

我无法理解,发生了奇怪的JavaScript-“ HTML锚点哈希”-“位置哈希”相互作用。来了

<div id="link"><a href="#foo">switch to foo</a></div>
<script>
    const link = document.querySelector('#link > a');

    link.addEventListener('click', function(event) {
        toggleFooBar(this.hash.substr(1));
    });

    toggleFooBar = function(type) {

        if (type === 'foo') {
            link.hash = '#bar';
            link.innerHTML = 'switch to bar';
        }
        else if (type === 'bar') {
            link.hash = '#foo';
            link.innerHTML = 'switch to foo';
        }

    };
</script>

在页面加载时,链接按预期显示切换到foo 。当我单击链接时,文本更改为切换到栏 ,但 location.hash更改为#bar。我期望HTML中只有link.hash会变为#bar,而location.hash将显示#foo,因为这是我首先单击的内容。似乎link.hashlocation.hash已链接在一起,因此即使在点击发生 之后更改link.hash,也会更新location.hash。显然,这不是我想要的。我希望location.hash显示link.hash时存在的click值。然后,我希望将link.hash更改为新值,以便再次单击它可以正确地切换回去。

我的错误的根源是什么,我该如何纠正?

1 个答案:

答案 0 :(得分:2)

  

我的错误的根源是什么,我该如何纠正?

我相信点击事件处理程序会在该事件的默认操作(*)发生之前 执行。这意味着您实际上是在更新URL之前更新哈希值。

问题演示:

const link = document.querySelector('#link > a');

link.addEventListener('click', function(event) {
  toggleFooBar(this.hash.substr(1));
});

toggleFooBar = function(type) {

  if (type === 'foo') {
    link.hash = '#bar';
    link.innerHTML = 'switch to bar';
  } else if (type === 'bar') {
    link.hash = '#foo';
    link.innerHTML = 'switch to foo';
  }

  // Only used to show current hash since code is run in an iframe
  setTimeout(() => console.log(window.location.hash), 100);
};
<div id="link"><a href="#foo">switch to foo</a></div>

一个简单的解决方案是使用setTimeout来延迟元素的修改:

const link = document.querySelector('#link > a');

link.addEventListener('click', function(event) {
  toggleFooBar(this.hash.substr(1));
});

toggleFooBar = function(type) {

  setTimeout(() => {
    if (type === 'foo') {
      link.hash = '#bar';
      link.innerHTML = 'switch to bar';
    } else if (type === 'bar') {
      link.hash = '#foo';
      link.innerHTML = 'switch to foo';
    }
  }, 0);

  // Only used to show current hash since code is run in an iframe
  setTimeout(() => console.log(window.location.hash), 100);
};
<div id="link"><a href="#foo">switch to foo</a></div>


*:显然“默认操作”是一个旧术语。最新规范使用术语“激活行为”。可以在https://dom.spec.whatwg.org/#dispatching-events

上找到更多信息。