了解hashchange事件的执行顺序

Bil*_*lly 6 javascript jquery

关于此代码段,我有一个问题:

window.location.hash=1;

$(window).on('hashchange', function() {
    alert('hello');
});
Run Code Online (Sandbox Code Playgroud)

上面的脚本应该这样做:

  1. 将位置哈希设置为 1
  2. 任何进一步的变化 - > alert('hello')

这是问题:为什么 hashchange在第一次执行时第一次调用?这个脚本不应该只更改哈希而没有任何警报吗?

如何修复它以使其按照描述工作?

Jam*_*rpe 5

首先,你问:

为什么hashchange在第一次执行的第一时间被调用?这个脚本不应该只改变散列而没有任何警报吗?

为了回答这个问题,我们可以深入研究规范。当导航到一个新片段(即 setting document.location.hash)时,规范会经历许多步骤,其中之一是:

  1. 穿越历史的新条目,异步事件标志设置。这将滚动到当前文档地址中给出的片段标识符。

遍历历史的规范接着说:

  1. 如果未设置异步事件标志,则同步运行以下步骤。否则,设置异步事件标志;将任务排队以运行以下子步骤
    1. 如果 state changed 为 true,则使用 PopStateEvent 接口在 Document 的 Window 对象上触发名为 popstate 的可信事件,并将 state 属性初始化为 state 的值。此事件必须冒泡但不可取消且没有默认操作。
    2. 如果 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 中排队的任务之后添加到队列中,因此事件侦听器仅在事件被触发后添加。


tel*_*lls 0

在代码中使用计数器:

var counter = 0;

$(window).on('hashchange', function() {
    if (counter)
        alert('hello');
    counter++;
});
Run Code Online (Sandbox Code Playgroud)