38

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

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

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

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 中修复。

4

5 回答 5

23

所以底线是 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 上下载视频或音频内容相同 - 你可以' t 编写脚本,用户必须启动它(不知何故)。

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

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

希望有帮助。

于 2011-05-29T14:05:21.287 回答
3

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

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

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

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

Remy在 Twitter 上提供了解决此问题的方法。

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

于 2011-05-29T14:03:30.473 回答
1

这是我发现的:

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

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

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

在 Android 版 Safari 上测试。

于 2011-08-16T14:01:47.567 回答
0

我发现了一个有点用的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,并且对此非常直言不讳。所以这是值得的。

于 2011-06-27T22:34:38.727 回答