【问题标题】:Is History API broken on iOS? (Location bar doesn't update on pushState)iOS 上的历史 API 是否损坏? (位置栏不会在 pushState 上更新)
【发布时间】:2011-09-03 22:31:23
【问题描述】:

将此归档在“我无法相信之前没有人注意到这一点”或“我必须遗漏一些东西”类别下:

看来,如果您在 iOS 上执行简单的window.history.pushState,位置栏不会更新,除非它响应用户手势。状态本身确实会被推送(正如您可以通过点击后退按钮看到的那样)。

这是我能想出的最小的测试用例重新创建问题:

http://thelink.is/history-api-ios-bug

在支持 History API 的桌面浏览器上,您应该会看到位置栏中的 URL 每秒更改为 /0、/1 等。在 iOS 上 – 使用 iPhone(运行 iOS 4.3)和 iPad(运行 iOS 4.3.3)进行测试 – 位置栏不会更新,但点击后退按钮会带您到正确的先前位置(测试用例中的 404)没有后端逻辑来处理这些 URL)。

想法?解决方法?一个可以哭泣和拥抱的肩膀?

更新:此问题已在 iOS 5 中修复。

【问题讨论】:

标签: ios html browser-history pushstate


【解决方案1】:

使用时对我来说效果很好:https://github.com/browserstate/history.js - 这还修复了 HTML5 History API 的许多其他跨浏览器错误。

从 v1.7 开始,它解决了以下错误:

  • History.js 解决了以下浏览器错误:
    • HTML5 浏览器
      • Chrome 8 有时在返回初始状态时不包含正确的状态数据
      • Safari 5、Safari iOS 4 和 Firefox 3 和 4 在页面加载时不会触发 onhashchange 事件
      • 与其他浏览器不同,当哈希值发生变化时,Safari 5 和 Safari iOS 4 不会触发 onpopstate 事件
      • 一旦哈希被replaceState 调用/bug report 替换,Safari 5 和 Safari iOS 4 将无法返回正确状态
      • Safari 5 和 Safari iOS 4 有时无法在繁忙条件下应用状态更改 / bug report
      • RC 之前的 Google Chrome 8、9、10 和 Firefox 4 将始终在页面加载后触发 onpopstate / change recommendation
      • Safari iOS 4.0、4.1、4.2 有一个有效的 HTML5 History API - 尽管浏览器的实际后退按钮不起作用,因此我们将它们视为 HTML4 浏览器
      • 没有一个 HTML5 浏览器实际上在 pushStatereplaceState 调用中使用了 title 参数
    • HTML4 浏览器
      • MSIE 6,7 和 Firefox 2 等旧版浏览器没有 onhashchange 事件
      • MSIE 6 和 7 有时即使被告知也不应用哈希(需要再次调用 apply 函数)
      • 当哈希值不是urlencoded 时,非 Opera HTML4 浏览器有时不应用哈希值
    • 所有浏览器
      • 离开网站然后返回(包括页面刷新)后,状态数据和标题不会保留
      • 州头衔永远不会应用于document.title

【讨论】:

  • 就文档而言,它与 Aral 使用的完全一样。
  • 除非发生了变化或者我遗漏了一些东西(两者都很可能)history.js 并不能解决问题。您能否链接到上面的测试用例的 history.js 版本,证明它可以在 iOS 4.3+ 上运行 - 谢谢!
  • @Aral - hrmm...单击balupton.com/sandbox/history.js/demo 上的按钮有效-调用一系列pushStates 自动有效balupton.com/sandbox/history.js/demo/bcherry.html(原始问题)-但按balupton.com/sandbox/history.js/demo/bcherry.html 上的后退按钮可以不要像其他人一样更改网址......尽管 statechange 触发。我将把它作为一个错误提交,看看我是否能想出一个解决方案。
  • @Aral - 虽然我仍然会说使用 History.js,并且在 iOS 设备上禁用 HTLM5 模式将是比 Remny 建议的更好的解决方案 - 因为它更加透明。虽然这对于这么小的东西来说是一个巨大的损害。我仍然会尽快寻找合适的解决方案。
【解决方案2】:

所以底线是 iOS 围绕历史 API 添加了自己的安全性,这意味着您不能使用脚本来更改 url。根据 Aral 的示例,只有用户操作才能允许历史 API 更改 url - 即点击。

解决方法是在 url 上使用哈希(又名片段标识符)。

我们将只更改位置,而不是 history.pushState

var i = 0;
var locationUpdateInterval = setInterval(function(){
  window.location.hash = i;
  i++;
}, 1000);   

要在 iOS 应用程序中的某个位置发生更改或它们具有指向您应用程序中特定页面/面板的永久链接时捕获事件:

// named function on purpose for later
function hashchange() {
  var pageId = location.hash.substr(1); // drop the # symbol
  // do something with pageId
}

window.onhashchange = hashchange;

// onload - if there's a hash on the url, try to do something with it
if (location.hash) hashchange();

在 iOS 上我们不能使用pushState/popState 很糟糕,但它的安全性与除非用户启动操作,否则无法触发全屏视频,这与下载视频相同或 iOS 上的音频内容 - 您不能编写脚本,用户必须启动它(不知何故)。

就像关于 Android 的说明 - 问题非常相似,所以这(应该)也可以作为 Android 的解决方法。

如果你想要桌面支持,大多数浏览器都支持onhashchange,但是,是的,你猜到了,IE 落后了 - 所以你可以 polyfill 那个坏男孩(虽然需要 jQuery...):http://benalman.com/projects/jquery-hashchange-plugin/

希望对您有所帮助。

【讨论】:

  • Remy,只有一件事我不明白:你可以通过脚本将 URL 推送到历史堆栈(如果你点击后退按钮,它就在那里),它只是不会更新位置栏中显示的地址。我仍然觉得这是一个错误,而不是一个功能。
  • 对于更透明的 polyfill - 一种自动的 - 为什么不推荐 History.js? - github.com/balupton/history.js
  • @Aral - 我同意你的看法。此外,这些变通方法也有缺点:danwebb.net/2011/5/28/it-is-about-the-hashbangs
  • History.js 没有解决这个问题。我在使用 History.js 时遇到了它。请在 iOS 上测试一下,你会看到。
【解决方案3】:

这是我发现的:

当推送的位置包含井号时,地址栏将被更新。 所以这会起作用:

window.history.pushState(data, title, 'a/new/url#');

但是 window.location 对象不会被更新,因此您需要将推送的 url 保存到一个变量中,如果您需要推送的位置,请使用该变量而不是 window.location。

在 Safari for Android 上测试。

【讨论】:

    【解决方案4】:

    我发现了一个可行的 hack。事实证明,如果您在 history.pushState 之后立即更改哈希,则位置栏会更新。喜欢:

            window.history.pushState(data, title, 'a/new/url');
            window.location.hash = 'new';
    

    将地址栏更改为http://example.com/a/new/url#new。这引入了另一个问题,因为哈希成为它自己的历史条目。所以无论如何你都需要听 onHashChange。

    这有点复杂,但有些人真的非常讨厌 hashbang url,并且对此非常直言不讳。所以值得。

    【讨论】:

      【解决方案5】:

      (更新:刚刚看到 Remy 也回答了 - 请阅读他在上面的深入回答。)

      Remy 在 Twitter 上提供 a workaround for this issue

      基本上,如果您更改 location.hash,地址栏中的地址就会更新。但是,这确实在历史记录中创建了一个单独的条目(这对我想要实现的目标不起作用)。我正在实施的解决方法是对 iOS 使用 hash-bang URL,对其他平台使用常规 URL,直到 iOS 错误得到修复。这绝对不理想,我希望 iOS 上的 Mobile Safari 将开始表现得像桌面上的 Chrome、Firefox 和 Safari。

      【讨论】:

        猜你喜欢
        • 2014-01-12
        • 2015-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 2013-01-29
        • 2020-01-20
        • 1970-01-01
        相关资源
        最近更新 更多