导航后退/卸载事件未触发时,iOS 5 Safari中的页面缓存问题

时间:2011-11-03 00:26:09

标签: javascript ios5 mobile-safari web browser-cache

tl; dr - iOS 5上的Safari正在缓存,这会破坏我的网站。

我正在努力解决iOS 5中的Safari浏览器处理后向缓存的问题,他们称之为“页面缓存”。它的描述方式here很好地解释了这种行为。

  

很简单,页面缓存使得当你离开页面时我们“暂停”它,当你回来时我们按“播放”。

这会导致整个网站出现问题。使用后退按钮时,大多数其他浏览器会以加载状态显示页面。不是iOS 5上的Safari,它会显示您上次离开时​​的页面。一个简单的例子是禁用提交按钮。如果我使用Javascript来禁用提交按钮,然后提交表单,当您单击后面的提交按钮仍将被禁用。这在其他浏览器中是一个问题,包括Safari的桌面版本,但是通过将onload事件处理程序设置为空函数来解决它。我相信这告诉浏览器使缓存无效,因为在该函数中可能发生了一些重要的事情。这个hack似乎不适用于iOS 5上的Safari。

以下问题归结为最基本的问题。加载test.html时,您将看到文本“原始文本”。当您单击该链接时,该文本将更改为“更改文本 - 转发到下一页”,然后在3秒后您将转发到test2.html。在所有浏览器中,一切都很好。在所有其他浏览器中,当您单击后退按钮时,您将看到的文本是“原始文本”,但在Safari for iOS 5上,您将看到“更改文本 - 转发到下一页”。

有关如何处理此事的任何建议吗?

这是一个简单的例子

的test.html

<script>
function changeText() {
    el = document.getElementById("text");
    el.innerHTML = "Changed text - forwarding to next page";
    setTimeout("forward()",3000);       
}
function forward() {
    document.location.href = "test2.html";
}
</script>
<div id="text">Original Text</div>
<a href="Javascript:changeText()">Click Here</a>
<script>
window.onunload = function(){};
</script>

test2.html

<div>Click back button</div>

这是使用表单帖子的第二个示例。这是我的应用程序如何工作的一个简单示例。当您导航回formtest2.asp时,您应该看到已发布的表单值,而div文本应该是原始的。

formtest.asp

<form method="post" action="formtest2.asp">
    Test: <input type="text" name="test"/>
    <input type="submit" value="Submit"/>
</form>

formtest2.asp

<script>
function changeText() {
    el = document.getElementById("text");
    el.innerHTML = "Changed text - forwarding to next page";
    setTimeout("forward()",3000);       
}
function forward() {
    document.location.href = "test2.html";
}
</script>

<%
Dim test
test = Request("test")
Response.Write("Test value: " & test & "<br />")
%>

<div id="text">Original Text</div>
<a href="Javascript:changeText()">Click Here</a>
<script>
window.onunload = function(){};
</script>

test2.html

<div>Click back button</div>

4 个答案:

答案 0 :(得分:26)

我也在寻找同一问题的答案。回到iOS 5中不会执行任何javascript,只是让页面处于您离开或被重定向时的先前状态。

尝试奇怪的&#34; onunload&#34; hack在&#34; Is there a cross-browser onload event when clicking the back button?&#34;仅适用于iOS 4,而不适用于未按预期调用事件的iOS 5。 Nickolay在网络工具包中指出了新的功能,名为&#34; pageshow&#34;和#34; pagehide&#34;这比Giuseppe的例子更可靠。

  1. 你需要这篇文章中的黑客:&#34; Is there a cross-browser onload event when clicking the back button?&#34;这适用于iOS 4。
  2. 使用此脚本使用新事件安全地检查页面是否已从缓存中加载并强制重新加载(避免URL检查和本地存储,还包括iPod)for iOS 5:

    <body onunload="">
    ...
    <script type="text/javascript">
    if ((/iphone|ipod|ipad.*os 5/gi).test(navigator.appVersion)) {
      window.onpageshow = function(evt) {
        // If persisted then it is in the page cache, force a reload of the page.
        if (evt.persisted) {
          document.body.style.display = "none";
          location.reload();
        }
      };
    }
    </script>
    

答案 1 :(得分:1)

我遇到了同样的问题 在iOS4上,当您将homepage.html导航到2.html,然后返回到homepage.html时,将调用js 。当你将homepage.html导航到2.html,从2.html你继续到3.html,然后从3回到2到主页,JS 将被调用!是的,太可怕了! 但是在iOS5 MobileSafari上,总是无法调用:(也许这是iOS5上的缓存错误。我在iOS 5.0.0和5.0.1上测试过,得到了相同的结果。

但是当你在body元素上实现onUnload事件时,它可以修复以前的MobileSafari上的后端问题。 我只是将homepage.html中的<body>更改为<body onUnload="">,然后从主页更改为2.html,当返回主页时,将调用主页上的javascript。它适用于FF,桌面Safari,移动Safari( iOS4

那么,我们怎么能在iOS5上做呢?不幸的是我还没有找到解决方案。但我的webapp在本机客户端中运行,我通过添加来自本地的reload()调用来修复此问题:

        if (isOS5_)
        {
            [webView stringByEvaluatingJavaScriptFromString:@"location.reload();"];
        }

webViewDidFinishLoad:

答案 2 :(得分:1)

在我的移动网站上,我已经解决了这个小型JS代码的问题:

if ((/iphone|ipad.*os 5/i).test(navigator.appVersion)) {
    window.onload=function () {
        localStorage.setItem("href",location.href);
    };
    window.onpopstate=function () {
        var a=localStorage.getItem("href"),
            b=location.href;
        if (b!==a&&b.indexOf((a+"#"))===-1) {
            document.body.style.display="none";
            location.reload();
        }
    };
}

情景:

点击“Page1”中的“Page2”链接:点击“Page1”后, 加载“Page2”并触发onload和许多其他事件。

[Page1] - &gt;点击链接 - &gt; [Page2] - &gt; onload - &gt; onpopstate - &gt; ...

此时,如果您点击浏览器的后退按钮,“Page2”会获得 关闭并加载“Page1”并触发onload和许多其他事件。

[Page2] - &gt;点击后退按钮 - &gt; [Page1] - &gt; onload - &gt; onpopstate - &gt; ...

单击IOS5中的后退按钮会关闭“Page1”并显示“Page2” 页面未加载,视口比例损坏,唯一的事件 被解雇了。

[Page2] - &gt;点击后退按钮 - &gt; [Page1] - &gt; onpopstate。

修复:

修复程序围绕事件onload,onpopstate和localStorage对象工作。

onload是脚本管理的第一个事件,并在其中存储 localStorage上的当前location.href。

如果没有任何错误,请在onpopstate中显示当前的location.href和href 存储必须相同,脚本应该什么都不做。

在IOS5上使用Safari时,页面未加载,并且未激活onload事件 location.href和存储的href在onpopstate事件中是不同的。

在这种情况下,只需隐藏当前页面(对于与视口相关的另一个错误) 这个)并使用location对象重新加载页面。

答案 3 :(得分:0)

在找到如何避免其中一个问题后,我们似乎对此有所了解,我很难分享:)

在阅读了关于这个主题的几个相关主题之后,主要是关于堆栈溢出“最热门的主题”,处理“页面缓存”(http://www.webkit.org/blog/427/webkit-page-cache-i-the-basics/http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/),检查“卸载”事件(开发人员。 apple.com/library/IOS/ipad/#documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)/“pageshow”nohing必须处理其先前状态(不是上一页)的简短“页面幻影” INITIAL状态,但只是页面,因为用户切换回app /或解锁他的设备/或退出后返回应用程序。

似乎(对我来说,至少),这个“可见页面故障”在IOS6更新时解决了,就像5分钟前一样; D

然后我可以像往常一样在移动Safari中使用我的webapp,并且在将其添加到主屏幕之后,“app切换”或“重新启动”(带或不带清除缓存)的情况与以下相同:它的第一次启动:你看到一个BLANK页面,然后是你的内容(可能是与保存到主屏幕的url相对应的页面,或者使用localStorage加载的任何其他内容,例如[my case(..)]。) / p>

对于我能够捕获的事件,IOS4 IOS5设备也无法摆脱那种“视觉持久性故障”。我想这是因为“页面缓存”的工作方式,但现在我在iPad上运行IOS6,因为故障不再存在,我想Safari团队必须改进他们处理“主屏幕”webapps的方式(... )