关于此代码段,我有一个问题:
window.location.hash=1;
$(window).on('hashchange', function() {
alert('hello');
});
Run Code Online (Sandbox Code Playgroud)
上面的脚本应该这样做:
1alert('hello')这是问题:为什么 hashchange在第一次执行时第一次调用?这个脚本不应该只更改哈希而没有任何警报吗?
如何修复它以使其按照描述工作?
首先,你问:
为什么
hashchange在第一次执行的第一时间被调用?这个脚本不应该只改变散列而没有任何警报吗?
为了回答这个问题,我们可以深入研究规范。当导航到一个新片段(即 setting document.location.hash)时,规范会经历许多步骤,其中之一是:
- 穿越历史的新条目,与异步事件标志设置。这将滚动到当前文档地址中给出的片段标识符。
遍历历史的规范接着说:
- 如果未设置异步事件标志,则同步运行以下步骤。否则,设置异步事件标志;将任务排队以运行以下子步骤。
- 如果 state changed 为 true,则使用 PopStateEvent 接口在 Document 的 Window 对象上触发名为 popstate 的可信事件,并将 state 属性初始化为 state 的值。此事件必须冒泡但不可取消且没有默认操作。
- 如果 hash changed 为真,则使用 HashChangeEvent 接口在浏览上下文的 Window 对象上触发一个名为 hashchange 的可信事件, oldURL 属性初始化为旧 URL,newURL 属性初始化为新 URL。此事件必须冒泡但不可取消且没有默认操作。
所以所有这些加在一起意味着当你运行你的代码时,事件侦听器hashchange将在第 14 步的子步骤中的代码运行之前添加,随后将在设置散列时触发。
如何修复它以使其按描述工作?
要修复它,您还可以使用setTimeout(.., 0)以下方法将事件侦听器的添加排队:
setTimeout(function() {
$(window).on('hashchange', function() {
alert('hello');
});
}, 0);
Run Code Online (Sandbox Code Playgroud)
由于您在设置哈希后将其添加到队列中,因此它将在上面步骤 14 中排队的任务之后添加到队列中,因此事件侦听器仅在事件被触发后添加。
在代码中使用计数器:
var counter = 0;
$(window).on('hashchange', function() {
if (counter)
alert('hello');
counter++;
});
Run Code Online (Sandbox Code Playgroud)