在Safari中,如果加载iframe
,并且用户通过返回或转发更改历史记录状态,则不会触发popstate
事件,从而导致应用程序状态和窗口位置为不同步。
我认为有效的XHR请求会导致相同的行为,但我还没有确认。
这是一个允许您轻松重现问题的jsfiddle: http://jsfiddle.net/neonsilk/muHk8/
您只需按顺序点击链接/按钮,从1到6。
在Safari 5.0.5中,输出为:
(反向按时间顺序排列,重要的部分是顶部的状态比较)
[1305665493096] /
[1305665493096] vs
[1305665493096] /node
---------------
[1305665489955] iframe loaded
---------------
[1305665489806] (did popstate or $.address change trigger?)
[1305665489805] called history.back()
[1305665489805] appended iframe
---------------
[1305665488428] popstate: /node
[1305665488427] $.address change: /node
---------------
[1305665487821] popstate: /
[1305665487821] $.address change: /
---------------
[1305665487179] $.address change: /node
---------------
[1305665486606] $.address change: /
---------------
[1305665485732] iframe loaded
---------------
[1305665485569] $.address change: /neonsilk/muHk8/show/
[1305665485568] $.address init
然而在Chrome(11)或FireFox(4.0)中,输出如下:
(注意状态是同步的)
[1305665609499] /
[1305665609499] vs
[1305665609499] /
---------------
[1305665608360] iframe loaded
---------------
[1305665607770] popstate: /
[1305665607770] $.address change: /
[1305665607758] (did popstate or $.address change trigger?)
[1305665607758] called history.back()
[1305665607758] appended iframe
---------------
[1305665606870] popstate: /node
[1305665606869] $.address change: /node
---------------
[1305665606150] popstate: /
[1305665606149] $.address change: /
---------------
[1305665605551] $.address change: /node
---------------
[1305665604808] $.address change: /
---------------
[1305665603354] iframe loaded
---------------
[1305665602688] $.address change: /neonsilk/muHk8/show/
[1305665602682] $.address init
[1305665602676] popstate: /neonsilk/muHk8/show/
这是Safari中的错误吗?如果是的话,是否有人发现了一种解决方法?
(同样有趣的是,FireFox和Chrome都会在页面加载时触发popstate
事件。)
答案 0 :(得分:1)
<强>更新强>
据我所知,这个错误是first reported by Ben Cherry。
以下是来自WebKit的相应bug report和changeset。
我无法弄清楚Chrome中修复错误的时间。如果有其他人,我会非常感谢这些信息。
我知道WebKit 533.21.1中存在这个bug(这是Safari 5.0.5使用的),并且已经被534.36(Safari / WebKit每晚)修复了 - 但我不知道,并且避风港'能够弄清楚,哪个中间构建引入了修复。
有a helpful chart将Chrome版本映射到其WebKit版本。
最重要的是,当任何活动网络流量(图片加载,Ajax请求等),而不仅仅是iframe时,会出现此错误。如果您正在尝试实施History API支持,或者您使用的是最新版本的Asual's jQuery Address plugin(默认情况下启用了历史记录支持),则此错误可能会严重影响您的应用程序。
第二次更新
我想我已经找到了引入修复程序的确切WebKit版本(534.10)。所以,如果你使用的是jQuery和Asual的地址插件,这是实用的解决方案:
if (!($.browser.webkit === true && parseFloat($.browser.version) < 534.10)) {
// only enable state support if WebKit version >= 534.10
$.address.state("/base/path");
}
我希望这有助于某人!
我刚刚在最新的WebKit中测试了小提琴(r86671),状态保持同步,所以它一定是个bug。有趣的是,花费大量时间撰写问题并立即提交问题会激发答案。
尽管如此,如果有人有解决方法,我们将不胜感激。
每晚WebKit(r86671):
[1305666598481] /
[1305666598481] vs
[1305666598480] /
---------------
[1305666597469] iframe loaded
---------------
[1305666597300] popstate: /
[1305666597298] $.address change: /
[1305666597270] (did popstate or $.address change trigger?)
[1305666597269] called history.back()
[1305666597269] appended iframe
---------------
[1305666596605] popstate: /node
[1305666596605] $.address change: /node
---------------
[1305666596008] popstate: /
[1305666596008] $.address change: /
---------------
[1305666595555] $.address change: /node
---------------
[1305666595142] $.address change: /
---------------
[1305666578600] iframe loaded
---------------
[1305666578400] $.address change: /_display/
[1305666578400] $.address init
---------------
[1305666577964] popstate: /_display/
有趣的是,Safari现在可以匹配Chrome和FireFox的行为,在页面加载时激活popstate。
答案 1 :(得分:1)
(在Android 2.2和iOS 4.3.3上的Safari下测试)
所以解决方法是:
使用XHR代替img跟踪/预加载任何加载事件后的任何内容。
如果用户在加载事件之前后退/前进两次或更多次,我们可能仍会遇到问题,但如果加载时间很短,用户很少会做多次操作,并且因为最终状态是正确的,所以我认为没问题。
另一种解决方法是:
使用计时器观看网址,如果在没有popstate的情况下进行了更改,请自行执行脏工作。 (正如此错误的评论,Facebook过去常常使用此解决方案。)
但是这个方法太复杂了,因为你应该将状态序列化/反序列化为url或localstorage / sessionstorage,就像你没有History API一样。所以我认为这不是一个可接受的解决方法。