【问题标题】:Is history.state always the same as popstate event.state?history.state 是否总是与 popstate event.state 相同?
【发布时间】:2018-01-02 03:39:15
【问题描述】:

history.state 是否总是与 popstate event.state 相同?

window.addEventListener("popstate", function (event){
    console.log(history.state === event.state); // ALWAYS TRUE
    // IT SEEMS
}, false);

如果是,两次拥有相同的东西的目的是什么。

【问题讨论】:

标签: javascript html5-history


【解决方案1】:

不,它们并不总是相同的。

来自MDN

popstate 事件在活动历史条目更改时触发。如果被激活的历史记录条目是通过调用history.pushState() 创建的或受到history.replaceState() 调用的影响,则popstate 事件的状态属性包含历史记录条目的状态对象的副本。

请注意,仅调用 history.pushState()history.replaceState() 不会触发 popstate 事件。 popstate 事件将通过执行浏览器操作来触发,例如单击后退或前进按钮(或在 JavaScript 中调用 history.back()history.forward())。

以下代码示例演示它们可以不同 (Google Chrome - Version 63.0.3239.108):

请注意:FireFox 存在一些问题。

window.onpopstate = function(event) {
  console.log(event.state === history.state);
};

history.pushState({page: 1}, "title 1", "?page=1");
history.pushState({page: 2}, "title 2", "?page=2");
history.replaceState({page: 3}, "title 3", "?page=3");
history.back(); 
history.back(); 
history.go(2);

【讨论】:

  • 我看不出您的报价或示例中的内容证明它们是不同的。我在 FF 中有true true true
  • @Kaiido,在我的浏览器中 (Google Chrome Version 63.0.3239.108) 我在 console 中得到两个输出,第一个是 false,第二个是 true
  • 是的,他们没有实现 SameObject...(顺便说一句,可能是一个错误,不确定)这并不意味着两种状态都不同。尝试记录这些状态。 {page: 1} & {page: 1}, null & null.
  • Ps:即使 FF 确实在不同状态的 get 上实现了 SameObject,它们也不会返回与已设置的对象相同的对象,所以即使这是 Chrome 的错误行为,那应该很少发生。这也意味着我们不能用=== 检查不同状态的相等性。更好的测试将暗示 JSON.stringify,在这种情况下,chrome 也将始终报告 true
【解决方案2】:

是的,它们应该始终代表相同的状态。

根据the specs当请求浏览器执行历史遍历时,

  1. history.state 设置为状态

其中 state16.1

中的相同
  1. 如果 state changed 为真,则使用PopStateEventDocument 对象的Window 对象上触发一个名为popstate 的事件,其中bubbles 属性初始化为true,@ 987654327@ 属性已初始化状态

强调我的

另一个答案的代码证明的是,谷歌浏览器不会返回相同的对象,而是一个副本。
尽管如此,两种状态都是相同的,而且 UA 似乎也不必尊重此状态对象的 [SameObject] 策略。

所以为了检查相等性,应该检查状态对象的内容,而不是使用直接相等性检查。

window.onpopstate = function(event) {
  console.log('same state',
    JSON.stringify(event.state) === JSON.stringify(history.state) // always true
  );
};

const obj1 = {page: 1};
history.pushState(obj1, "title 1", "?page=1");

console.log('[SameObject]', history.state === obj1); // false
console.log(history.state); // {page: 1}

history.pushState({page: 2}, "title 2", "?page=2");
history.replaceState({page: 3}, "title 3", "?page=3");
history.back();
history.back(); 
history.go(2);

至于为什么设置在两个不同的地方,我不得不承认我没有一个可靠的答案……

【讨论】:

  • 在事件处理程序中应该使用哪一个?
  • @WalleCyril 不会有任何区别,这些都不会严格等于您传递的原始对象,但两者都是同一个对象的副本,所以真的,没关系.
猜你喜欢
  • 2011-12-13
  • 2016-10-05
  • 1970-01-01
  • 1970-01-01
  • 2018-12-13
  • 1970-01-01
  • 2021-01-26
  • 1970-01-01
相关资源
最近更新 更多