【问题标题】:Why isn't popstate triggered in Safari when an iframe is loading?为什么在加载 iframe 时在 Safari 中不触发 popstate?
【发布时间】:2011-05-17 20:58:01
【问题描述】:

在 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 事件。)

【问题讨论】:

    标签: javascript html safari history


    【解决方案1】:

    更新

    据我所知,这个错误是first reported by Ben Cherry

    这是来自 WebKit 的对应 bug reportchangeset

    还有the issue from Chromium

    我无法弄清楚该错误何时在 Chrome 中得到修复。如果其他人有,我将不胜感激。

    我确实知道该错误存在于 WebKit 533.21.1(这是 Safari 5.0.5 使用的)中,并且已由 534.36(Safari/WebKit nightly)修复——但我不知道,也没有无法弄清楚,哪个中间版本引入了修复。

    a helpful chart 将 Chrome 版本映射到其 WebKit 版本。

    最重要的是,当有任何活动的网络流量(图像加载、Ajax 请求等)时出现此错误,而不仅仅是 iframe。如果您尝试实现 History API 支持,或者您正在使用最新版本的 Asual's jQuery Address plugin(默认启用历史记录支持),则此错误可能会严重影响您的应用程序。


    第二次更新

    我想我找到了引入修复程序的确切 WebKit 版本 (534.10)。所以,如果你使用 jQuery 和 Asual 的 Address 插件,这里是实用的解决方案:

    if (!($.browser.webkit === true && parseFloat($.browser.version) < 534.10)) {
        // only enable state support if WebKit version >= 534.10
        $.address.state("/base/path");
    }
    

    我希望这对某人有帮助!


    我刚刚在最新的 WebKit nightly (r86671) 中测试了小提琴,并且状态保持同步,所以它一定是一个错误。有趣的是,花大量时间写一个问题并立即提交它会激发答案。

    不过,如果有人有解决方法,将不胜感激。

    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。

    【讨论】:

      【解决方案2】:
      1. Img/script/iframe 加载会破坏 popstate,但 XHR 不受此错误影响!
      2. 文档加载前的后退/前进将被延迟。加载时我们将获得一个弹出状态。 (即使有多个后退/前进,也只会弹出最后一个状态。)

      (在 Android 2.2 和 iOS 4.3.3 上的 Safari 下测试)

      所以解决方法是:

      使用 XHR 而不是 img 来跟踪/预加载加载事件之后的任何内容。

      如果用户在加载事件之前执行两次或更多次后退/前进,我们可能仍然会遇到问题,但是如果加载时间很短,用户很少会执行多次操作,并且由于最终状态是正确的,所以我认为没关系。

      另一种解决方法是:

      使用计时器查看url,如果没有popstate就更改了,请自己做脏活。 (作为这个bug的cmets,Facebook曾经使用过这个方案。)

      但是这种方法太复杂了,因为你应该将状态序列化/反序列化为 url 或 localstorage/sessionstorage,就像你没有 History API 一样。所以我不认为这是一个可以接受的解决方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-16
        • 2020-03-27
        • 2015-05-20
        • 2014-01-01
        • 2016-08-12
        • 2014-06-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多