我无法理解,发生了奇怪的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.hash
和location.hash
已链接在一起,因此即使在点击发生 之后更改link.hash
,也会更新location.hash
。显然,这不是我想要的。我希望location.hash
显示link.hash
时存在的click
值。然后,我希望将link.hash
更改为新值,以便再次单击它可以正确地切换回去。
我的错误的根源是什么,我该如何纠正?
答案 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
上找到更多信息。