【问题标题】:Problems with Page Cache in iOS 5 Safari when navigating back / unload event not fired导航返回/未触发事件时 iOS 5 Safari 中的页面缓存问题
【发布时间】:2011-12-20 19:09:00
【问题描述】:

tl;dr - iOS 5 上的 Safari 缓存非常困难,它正在破坏我的网站。

我正在为 iOS 5 中的 Safari 浏览器处理后向缓存(他们称之为“页面缓存”)的方式而苦苦挣扎。 here 的描述方式很好地解释了这种行为。

很简单,页面缓存可以做到这一点,当您离开页面时,我们会“暂停”它,而当您返回时,我们会按“播放”。

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

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

关于如何处理这个问题有什么建议吗?

这是一个简单的例子

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>

【问题讨论】:

  • 关于这个的更多信息。似乎我测试过的所有浏览器(Firefox、IE、Safari 桌面)都按此顺序触发 pagehide 和卸载。 iOS 5 上的 Safari 只会触发 pagehide。
  • 打开新标签页时,不会触发 unload 事件,只是页面隐藏。打开新选项卡时,您希望能够导航回旧选项卡并查看离开时一样的页面。问题是,当我们在同一个选项卡/窗口中从一个页面导航到下一个页面时,应该按 w3c 触发 unload 事件,但不是。 w3.org/TR/DOM-Level-2-Events/events.html。 “当 DOM 实现从窗口或框架中删除文档时,会发生 unload 事件。此事件对 BODY 和 FRAMESET 元素有效。”
  • 任何使用 location.reload() 的解决方案都会失败,因为对于此功能,iOS 5 上的 Safari 只会执行 GET,而不像所有其他浏览器一样执行 POST。
  • 我们找到了适合我们的解决方法。我们在 HTTPS 中运行我们的整个应用程序,从而避免了后向缓存。
  • 没什么可补充的,只是这是一个完美的例子,说明了一个 SO 问题应该是什么样子的,恕我直言...... +1!

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


【解决方案1】:

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

尝试在“Is there a cross-browser onload event when clicking the back button?”中发现的奇怪的“onunload”hack 仅适用于 iOS 4,不适用于未按预期调用事件的 iOS 5。 Nickolay 指出了 web-kit 上的新功能,称为“pageshow”和“pagehide”,它们比 Giuseppe 的示例可靠得多。

  1. 您需要这篇文章中的 hack:“Is there a cross-browser onload event when clicking the back button?”才能在 iOS 4 中工作。
  2. 使用这个脚本,它使用新事件安全地检查页面是否从缓存中加载并强制重新加载(避免 URL 检查和本地存储,还包括 iPod):

    <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>
    

【讨论】:

  • 最后,这个解决方案与其他解决方案相同,因为重新加载并不能解决我的问题。从下面开始,“此解决方案适用于动态内容页面,但当您导航回需要提交表单的页面时会崩溃。location.reload() 仅加载该 URI 而不会发布原始表单值。”
  • @Clarke:您需要使用服务器端代码将要重新发布的 POST 参数写入标记(就像您写出“测试”变量的方式一样)。为要再次发布的所有变量在表单元素下注入隐藏的输入元素。然后使用上面相同的基本代码,而不是重新加载,只需提交表单即可。
  • 这似乎是一个很好的解决方案,但实际上并非如此。该事件有时会触发有时不会触发。我什至无法解释如何重复该问题,尝试打开第 1 页然后打开第 2 页,然后单击返回,事件触发,然后重复几次。
【解决方案2】:

我遇到了同样的问题。
在 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中的&lt;body&gt;更改为&lt;body onUnload=""&gt;,然后从homepage更改为2.html,当返回主页时,将调用主页上的javascript。它适用于 FF、桌面 Safari、移动 Safari(iOS4)

那么,我们在 iOS5 上该怎么做呢?不幸的是,我还没有找到解决方案。但是我的 web 应用程序在本机客户端中运行,我通过添加来自本机的 reload() 调用解决了这个问题:

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

webViewDidFinishLoad:

【讨论】:

  • 我在返回页面时尝试在页面上添加重新加载,但这会导致需要表单发布的页面出现问题。重新加载只是加载 URI 而不发布表单数据。
【解决方案3】:

在我的移动网站上,我已经解决了这个小 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] -> 点击链接 -> [Page2] -> onload -> onpopstate -> ...

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

[Page2] -> 点击返回按钮 -> [Page1] -> onload -> onpopstate -> ...

在IOS5中点击后退按钮会关闭“Page1”并出现“Page2”但是 页面未加载,视口比例损坏,唯一的事件 解雇是 onpopstate。

[Page2] -> 点击返回按钮 -> [Page1] -> onpopstate.

修复:

修复工作围绕事件 onload、onpopstate 和 localStorage 对象。

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

如果没有任何错误,onpopstate 中的当前 location.href 和 href 存储的必须相同,并且脚本不应该执行任何操作。

在 IOS5 上使用 Safari 页面未加载且未触发 onload 事件,然后 在 onpopstate 事件中 location.href 和存储的 href 不同。

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

【讨论】:

  • 感谢您的输入,尽管它对我不起作用。由于这对您有用,您可能需要将 ipod 添加到 if 语句中。我必须这样做,因为 iPod Touch 是我用于测试的设备,并且必须添加它才能使其工作。此解决方案适用于动态内容页面,但当您导航回需要提交表单的页面时会出现故障。 location.reload() 仅加载该 URI 而不会发布原始表单值。这是我上面的示例 html 不完整的地方。
【解决方案4】:

在找到如何避免我们似乎都有的问题之一之后,我很想分享 :)

在阅读了一些关于该主题的相关主题后,主要是关于堆栈溢出“最热门主题”,处理“页面缓存”(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/),检查“卸载”事件(developer.apple.com/ library/IOS/ipad/#documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html ) / "pageshow" 不需要处理之前状态下的简短“页面幻影”(不是之前的页面初始状态,而是只是留下的页面),而用户切换回应用程序/或解锁他的设备/或退出后返回应用程序。

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

然后我就可以在移动 safari 中正常使用我的 webapp,并且在将其添加到主屏幕后,无论是否清除缓存,“应用切换”或“重新启动”的行为都与它的第一次启动:您会看到一个空白页面,然后是您的内容(可能是与保存到主屏幕的 url 对应的页面,或者使用 localStorage 加载的任何其他内容,例如 [my case (..) ])。

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

【讨论】:

    猜你喜欢
    • 2020-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多