Javascript 导航返回/卸载事件未触发时,iOS 5 Safari 中的页面缓存问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7988967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Problems with Page Cache in iOS 5 Safari when navigating back / unload event not fired
提问by Clarke
tl;dr- Safari on iOS 5 is caching so hard, it is breaking my site.
tl;dr- iOS 5 上的 Safari 缓存太难了,它破坏了我的网站。
I am struggling with the way the Safari browser in iOS 5 deals with back forward cache, which they call "Page Cache". The way it is described hereexplains the behavior very well.
我正在努力解决 iOS 5 中的 Safari 浏览器处理后退缓存的方式,他们称之为“页面缓存”。此处描述的方式很好地解释了该行为。
Quite simply, the Page Cache makes it so when you leave a page we “pause” it and when you come back we press “play.”
很简单,页面缓存使得当你离开一个页面时我们“暂停”它,当你回来时我们按下“播放”。
This is causing problems throughout my site. When using the back button, most other browsers will show you the page in the state it was loaded. Not Safari on iOS 5, it shows you the page as you last left it. A simple example would be the disabling of a submit button. If I use Javascript to disable a submit button, then submit a form, when you click back the submit button will still be disabled. This has been an issue in other browsers, including the desktop version of Safari, but it is solved by setting the onload event handler to a blank function. I believe this tells the browser to invalidate the cache because something important could have happened in that function. This hack does not seem to work for Safari on iOS 5.
这在我的网站上造成了问题。使用后退按钮时,大多数其他浏览器将向您显示页面加载时的状态。不是 iOS 5 上的 Safari,它会显示您上次离开时的页面。一个简单的例子是禁用提交按钮。如果我使用 Javascript 禁用提交按钮,然后提交表单,当您单击返回时,提交按钮仍将被禁用。这在其他浏览器(包括桌面版 Safari)中一直存在问题,但可以通过将 onload 事件处理程序设置为空白函数来解决。我相信这会告诉浏览器使缓存无效,因为该函数中可能发生了一些重要的事情。此 hack 似乎不适用于 iOS 5 上的 Safari。
Below is the issue boiled down to the bare essentials. When you load test.html you will see the text "Original Text". When you click the link, that text will change to "Changed text - forwarding to next page", then in 3 seconds you will be forwarded to test2.html. All is good up to this point in all browsers. In all other browsers, when you click the back button, the text you will see is "Original Text", but on Safari for iOS 5 you will see "Changed text - forwarding to next page".
以下是归结为基本要素的问题。当您加载 test.html 时,您将看到文本“原始文本”。当您单击该链接时,该文本将更改为“已更改文本 - 转发到下一页”,然后在 3 秒后您将被转发到 test2.html。到目前为止,在所有浏览器中一切都很好。在所有其他浏览器中,当您单击后退按钮时,您将看到的文本是“原始文本”,但在 iOS 5 的 Safari 上,您将看到“已更改的文本 - 转发到下一页”。
Any suggestions on how to deal with this?
有关如何处理此问题的任何建议?
This is a simple example
这是一个简单的例子
test.html
测试.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
测试2.html
<div>Click back button</div>
This is a second example using a form post. This is a simple example of how my app is working. When you navigate back to formtest2.asp, you should see the posted form value and the div text should be original.
这是使用表单帖子的第二个示例。这是我的应用程序如何工作的一个简单示例。当您导航回 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
表单测试2.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
测试2.html
<div>Click back button</div>
回答by BrutalDev
I was also looking for an answer to the same issue. Going back in iOS 5 does not execute any javascript and just leaves the page in the previous state it was when you left or were redirected.
我也在寻找同样问题的答案。返回 iOS 5 不会执行任何 javascript,只会将页面保留在您离开或被重定向时的先前状态。
Trying the weird "onunload" hack found in "Is there a cross-browser onload event when clicking the back button?" only worked for iOS 4, not iOS 5 which does not call the event as expected. Nickolay pointed out new functions on web-kit called "pageshow" and "pagehide" which are much more reliable than Giuseppe's example.
尝试在“单击后退按钮时是否有跨浏览器加载事件?”中发现的奇怪的“onunload”hack仅适用于 iOS 4,而不适用于未按预期调用事件的 iOS 5。Nickolay 指出了 web-kit 上名为“pageshow”和“pagehide”的新功能,它们比 Giuseppe 的例子更可靠。
- You need the hack from this article: "Is there a cross-browser onload event when clicking the back button?" for this to work in iOS 4.
Use this script which uses the new event to safely check if the page was loaded from cache and force a reload (avoiding URLs checks and local storage and also include iPods) 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>
- 您需要这篇文章中的技巧:“单击后退按钮时是否有跨浏览器的加载事件?”以便在 iOS 4 中工作。
使用这个脚本,它使用新事件来安全地检查页面是否从缓存加载并强制重新加载(避免 URL 检查和本地存储,还包括 iPod)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>
回答by Elf Sundae
I'm meeting the same problem.
On iOS4, when you navigate homepage.html to 2.html, then back to homepage.html, the js will notbe called. when you navigate homepage.html to 2.html, from 2.html you continue going to 3.html, and then back from 3 to 2 to homepage, the JS will becalled! Yes, It's terrible!
But on iOS5 MobileSafari, It always cannot be called :( Maybe this is a cache bug on iOS5. I tested on iOS 5.0.0 and 5.0.1, got the same result.
我遇到了同样的问题。
在 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上进行了测试,得到了相同的结果。
But when you implement the onUnload event on body
element, it can fix the backforward problem on previous MobileSafari.
I simply changed the <body>
to <body onUnload="">
in homepage.html, then from homepage to 2.html, when going back to homepage, the javascript on homepage will be called. It works on FF, Desktop Safari, Mobile Safari(iOS4)
但是当你在body
element上实现 onUnload 事件时,它可以解决之前 MobileSafari 上的backforward 问题。我干脆把homepage.html里的<body>
to改了<body onUnload="">
,然后从homepage改成2.html,当回到homepage的时候,homepage上的javascript就会被调用。它适用于 FF、桌面 Safari、移动 Safari(iOS4)
So, how can we do on iOS5? Unfortunately I have not found a solution. But my webapp runs in a native client, I fixed this by adding a reload()
call from native:
那么,我们在iOS5上怎么办呢?不幸的是,我还没有找到解决方案。但是我的 web 应用程序在本机客户端中运行,我通过添加reload()
来自本机的调用来解决此问题:
if (isOS5_) { [webView stringByEvaluatingJavaScriptFromString:@"location.reload();"]; }
when webViewDidFinishLoad:
什么时候 webViewDidFinishLoad:
回答by Giuseppe Scotto Lavina
on my mobile site, I have fixed the problem with this small JS Code:
在我的移动网站上,我用这个小 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();
}
};
}
Scenario:
设想:
Clicking the link “Page2” from “Page1”: Once clicked “Page1” gets closed, “Page2” is loaded and fires the onload and many other events.
单击“Page1”中的“Page2”链接:一旦单击“Page1”关闭,“Page2”就会加载并触发 onload 和许多其他事件。
[Page1] -> click the link -> [Page2] -> onload -> onpopstate -> ...
[Page1] -> 点击链接 -> [Page2] -> onload -> onpopstate -> ...
At this point if you click on the back button of your browser, “Page2” gets closed and “Page1” is loaded and fires the onload and many other events.
此时,如果您单击浏览器的后退按钮,“Page2”将关闭并加载“Page1”并触发 onload 和许多其他事件。
[Page2] -> click on the back button -> [Page1] -> onload -> onpopstate -> ...
[Page2] -> 点击返回按钮 -> [Page1] -> onload -> onpopstate -> ...
Clicking the back button in IOS5 makes closing “Page1” and “Page2” appears but the page is not loaded, the viewport scale gets corrupted and the only event fired is onpopstate.
单击 IOS5 中的后退按钮会关闭“Page1”和“Page2”,但页面未加载,视口比例损坏,唯一触发的事件是 onpopstate。
[Page2] -> click on the back button -> [Page1] -> onpopstate.
[Page2] -> 点击返回按钮 -> [Page1] -> onpopstate。
The Fix:
修复:
The fix works around the events onload, onpopstate and the localStorage object.
该修复解决了 onload、onpopstate 和 localStorage 对象事件。
onload is the first event managed by the script, and within this it stores the current location.href on localStorage.
onload 是脚本管理的第一个事件,它在其中将当前 location.href 存储在 localStorage 上。
If there is not any bug, in onpopstate the current location.href and the href stored must be the same and the script should do nothing.
如果没有任何错误,则在 onpopstate 中,当前 location.href 和存储的 href 必须相同,脚本不应执行任何操作。
Using Safari on IOS5 the page is not loaded and onload event is not fired, then location.href and the stored href are different in onpopstate event.
在 IOS5 上使用 Safari,页面未加载且 onload 事件未触发,则 location.href 和存储的 href 在 onpopstate 事件中不同。
In this case just hide the current page (for another bug in viewport related to this) and reload the page with location object.
在这种情况下,只需隐藏当前页面(对于与此相关的视口中的另一个错误)并使用位置对象重新加载页面。
回答by StephaneAG
After finding how to avoid one of the issue(s) we all appear to have on this, I tough I'd like to share :)
在找到如何避免我们似乎都遇到的问题之一后,我很想分享一下:)
After reading few related topics about the subject, mainly on stack overflow "hottest subjects", handling the "Page Cache" ( http://www.webkit.org/blog/427/webkit-page-cache-i-the-basics/and http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/), checking the "unload" event ( developer.apple.com/library/IOS/ipad/#documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html ) / "pageshow" does nohing have to deal with the brief "page apparition" in its previous state ( not the previous page INITIAL state, but just the page as it was left ) while user switch back to app / or unlock his device / or return to app after quitting it.
在阅读了一些关于该主题的相关主题后,主要是堆栈溢出“最热门主题”,处理“页面缓存”(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" 不需要处理其先前状态中的简短“页面幻影”(不是上一页 INITIAL 状态,而只是页面本身离开),而用户切换回应用程序/或解锁他的设备/或退出应用程序后返回应用程序。
It seems (for me,at least) , that this "visible page glitch" was solved when I did the update for IOS6 ,like 5 mins ago ;D
似乎(至少对我而言),当我为 IOS6 进行更新时,这个“可见页面故障”已经解决了,就像 5 分钟前一样;D
I was then able to use my webapp in mobile safari as normal, and after adding it to the home screen, the behavior in case of "app switching" or "relaunching" ,with or without cleared cache, is the same as its first startup: you see a BLANK page and then your content (wich may be the page corresponding to the url that were saved to home screen, or any other content loaded using localStorage for example [my case (..) ] ).
然后我可以像往常一样在移动 safari 中使用我的 web 应用程序,并将其添加到主屏幕后,“应用程序切换”或“重新启动”情况下的行为,无论是否清除缓存,都与其第一次启动相同:您看到一个空白页面,然后是您的内容(可能是与保存到主屏幕的 url 相对应的页面,或使用 localStorage 加载的任何其他内容,例如 [my case (..) ] )。
For the events I was able to catch, nor on IOS4 IOS5 devices could I manage to get rid of that "visual persistence glitch". I guess that's because of the way "Page Cache" works, but now i'm running IOS6 on iPad, as the glitch is no more there, I guess the Safari team must have improved the way they handle "homescreen" webapps (..)
对于我能够捕捉到的事件,在 IOS4 IOS5 设备上我也无法摆脱“视觉持久性故障”。我想这是因为“页面缓存”的工作方式,但现在我在 iPad 上运行 IOS6,因为故障不再存在,我猜 Safari 团队必须改进他们处理“主屏幕”网络应用程序的方式(.. )