iOS上的历史记录API是否存在问题?(在使用pushState时地址栏没有更新)

38

将此归类为“我无法相信以前没有人注意到这一点”或“我一定是错过了什么”的类别:

似乎如果在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中修复。


看那边的答案,用AngularJS解决了。http://stackoverflow.com/a/31830466/1138430 - Ben Yitzhaki
5个回答

23
因此,iOS在历史记录API周围添加了自己的安全机制,这意味着您无法使用脚本更改URL。只有用户操作才能允许历史记录API更改URL - 例如单击 - 如Aral的示例所示。
解决方法是在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,但这和不允许触发全屏视频以及下载视频或音频内容是一样的安全机制。也就是说,你不能通过脚本来自动完成这些操作,用户必须手动开始(方式各异)。

关于 Android,问题也非常相似,因此这个解决方法(应该)也适用于 Android。

如果你需要桌面浏览器支持,大多数浏览器都支持 onhashchange,但是,你猜对了,IE 的支持不如其他浏览器,所以你可以用插件来模拟它(不过需要 jQuery...):http://benalman.com/projects/jquery-hashchange-plugin/

希望这有所帮助。


3
雷米,有一件事我不太明白:你可以通过脚本将URL推送到历史记录栈中(如果你点击后退按钮,它就在那里),只是它不会更新显示在地址栏中的地址。我仍然认为这是一个漏洞,而不是一个功能。 - Aral Balkan
为了更透明的 polyfill - 一个自动的 - 为什么不推荐使用 History.js?- https://github.com/balupton/history.js - balupton
@Aral - 我同意你的观点。此外,这些解决方法也有缺点:http://www.danwebb.net/2011/5/28/it-is-about-the-hashbangs - gblazex
History.js 无法解决此问题。我在使用 History.js 时遇到了此问题。请在 iOS 上进行测试,您会看到的。 - Aral Balkan

3
使用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事件,不像其他浏览器
      • Safari 5和Safari iOS 4无法在哈希被replaceState调用替换后返回正确的状态/ bug report
      • Safari 5和Safari iOS 4在繁忙条件下有时无法应用状态更改/ bug report
      • Google Chrome 8,9,10和Firefox 4在RC之前将始终触发onpopstate一旦页面已加载/ change recommendation
      • Safari iOS 4.0、4.1、4.2具有工作的HTML5 History API-尽管浏览器的实际返回按钮不起作用,因此我们将其视为HTML4浏览器
      • 所有HTML5浏览器实际上都不利用pushStatereplaceState调用中的参数</li> </ul></li> <li>HTML4浏览器 <ul> <li>旧浏览器如MSIE 6、7和Firefox 2没有<code>onhashchange</code>事件</li> <li>MSIE 6和7有时即使被告知也不适用哈希(需要第二个调用应用函数)</li> <li>非Opera HTML4浏览器有时不会在哈希没有<code>urlencoded</code>时应用哈希</li> </ul></li> <li>所有浏览器 <ul> <li>状态数据和标题一旦离开站点然后返回就不会持久化(包括页面刷新)</li> <li>状态标题从未应用于<code>document.title</code></li> </ul></li> </ul>

就文档而言,它与 Aral 所做的完全相同。 - gblazex
除非有什么改变或我漏掉了什么(两者都很可能),history.js并不能解决这个问题。你能提供一个测试用例的history.js版本,证明它在iOS 4.3+上可以正常工作吗?谢谢! - Aral Balkan
@Aral - 嗯...在http://balupton.com/sandbox/history.js/demo/上点击按钮是可以的-自动调用一系列pushStates也可以在http://balupton.com/sandbox/history.js/demo/bcherry.html(原来的问题)-但是按下http://balupton.com/sandbox/history.js/demo/bcherry.html上的返回按钮却不像其他的那样改变URL...尽管状态更改已触发。我将将此作为错误并尝试找到解决方案。 - balupton
@Aral - 尽管我仍然认为使用History.js,并在iOS设备上禁用HTML5模式比Remny建议的更好,因为它更加透明。虽然这对于这么小的事情来说是一个严重的障碍。但我很快会寻找一个合适的解决方案。 - balupton

1

我找到了以下内容:

当推送的位置包含一个哈希符号时,地址栏将被更新。 因此,这将起作用:

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

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

已在Android上的Safari进行测试。


1

(更新:刚看到Remy也回答了 - 请阅读他的深入回答,而不是下面的内容。)

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

基本上,如果您更改location.hash,位置栏中的地址将会更新。但是,这确实会在历史记录中创建一个单独的条目(这对于我想要实现的目标无效)。我正在实施的解决方法是在iOS上使用哈希-叹号URL,在其他平台上使用常规URL,直到修复iOS错误。这绝对不是理想的解决方案,我希望iOS上的Mobile Safari能够像桌面上的Chrome、Firefox和Safari一样表现良好。


0

我发现了一个有点可行的黑客技巧。原来,如果你在history.pushState之后立即更改哈希值,地址栏就会更新。像这样:

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

将位置栏更改为http://example.com/a/new/url#new。这会引入另一个问题,因为哈希成为了自己的历史记录条目。所以你仍然需要监听onHashChange事件。

这有点复杂,但有些人真的非常讨厌哈希bang URL,并且非常强烈地表达了他们的意见。所以这是值得的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接