IOS后退返回空白页问题
现象描述:
android 浏览器,包括微信的开发者工具,页面都正常显示,按返回可以刷新页面但是唯有iOS不行.
iOS 浏览器显示空白原因分析:
具体现象描述:页面数据是通过 ajax 请求后台数据,通过链接跳到下一页,然后history.go(-1)返回上一页后,页面内容并不会刷新,即在B页面修改的内容,返回到A时并没有更新新的内容,必须手动刷新(在 android 中正常显示上一页,但是在 iOS 中不能正常显示,通过打印
返回的数据,发现数据是上一个页面最后请求的数据)
现象分析:
在Debug模式下,发现在iOS浏览器中,返回上一页后,页面的 JS 代码并未执行。因此,推测可能是缓存引起的,于是使用 meta 禁止了缓存,但仍然没有效果。于是进一步推测可能是浏览器内部机制导致——iOS为了提升浏览网页的效率,可能给已浏览过的网页添加一个类似快照的东西,当点击返回按钮后,直接调用快照展示给用户,省去了执行JS这一步骤(纯静态文件依然被缓存)。这本来是iOS的优势,在这却变成了bug存在的风险.
js最常用的返回上一页的方法:history.go(-1)和 history.back(),
解决方案:
对应不同的场景,不同的方式就可以解决对应的问题
1. 针对数据更新的现象
重新加载页面数据即可,或者刷新页面
onpageshow:当一条会话历史记录被执行的时候将会触发页面显示(pageshow)事件。(这包括了后退/前进按钮操作,同时也会在onload 事件触发后初始化页面时触发,因此是页面加载后的触发事件
$(function () {
var isPageHide = false;
window.addEventListener('pageshow', function () {
if (isPageHide) {
window.location.reload();
}
});
window.addEventListener('pagehide', function () {
isPageHide = true;
});
})
2.具体Ios系统刷新
event.persisted:用于判断是从服务器载入还是从缓存读取,缓存是true,否则是false,但是真实应用中, event.persisted不管是通过ur跳转,还是通过history.go(-1),history.back()都返回false,因此event.persisted没啥用处,目前为止window.performance是一个对象, window.performance.navigation:是一个 PerformanceNavigation 对象,该对象表示在当前给定浏览上下文中网页导航的类型以及次数
window.performance.navigation.type获取具体该导航的类型
- TYPE_NAVIGATE(0):
当前页面是通过点击链接,书签或表单提交,或者脚本操作,或者在地址栏中直接输入URL打开的,值为0 - TYPE_RELOAD(1):
当前页面是通过点击刷新按钮,或者 location.reload()打开的,值为1 - TYPE_BACK_FORWARD(2):
当前页面是通过历史记录或者前进后退按钮打开的,值为2 - TYPE_RESERVED(255):
任意其他方式打开的,值为255
/*ios 页面不刷新问题*/
const reloadPage= () => {
let userAgent = window.navigator.userAgent.toLowerCase();
let isiOS = userAgent.indexOf('applewebkit') >= 0;
if (isiOS) {
window.onpageshow = function(event) {
if (event.persisted||window.performance.navigation.type===2) {
window.location.reload()
}
};
}
}
reloadPage();
3.导航是哈希路由格式
hashchange:当URL的片段标识符更改时,将触发hashchange事件 (跟在#符号后面的URL部分,包括#符号
当是hash路由的时候,无法触发onpageshow事件,而 onhashchange()可监听URL的hash部分,因此采用监听路由hashchange的方式,该方法能判断hash值发生变化的情况,是类似路径/#router,# 后内容发生变化的情况,例如*****/#/index=>*****/#/detail
/*ios 页面不刷新问题*/
const reloadPage= () => {
let userAgent = window.navigator.userAgent.toLowerCase();
let isiOS = userAgent.indexOf('applewebkit') >= 0;
window.addEventListener('hashchange', (event) => {
console.log(window.location.href)
let redirectPage=window.location.href.indexOf("#");//-1
if (isiOS && -1=== redirectPage) {
window.location.reload()
}
})
}
reloadPage();
4 .特殊场景
但是无法截取非路由访问路径
场景描述:
XXXX/visit/first(后端controller访问路径)
1.访问路径****/visit/first对应的方法中打开指定展示前端路径****/front/#/first,
2.前端路径****/front/#/first设置了重定向,转向路径****/front/#/second(我们假定这个重定向是不可避免的)
3.在页面****/front/#/second,按手机自带的返回键,返回的是路径****/visit/first,Android手机返回到该路径后会自动刷新,重新展示****/front/#/second路由页面。但是IOS手机,展示的空白页面,因为IOS因为效率问题,返回的页面一般显示的是缓存的快照–空白界面(因为该路径是个访问路径,没有真实的页面,没有具体的前端页面指向,所以是空白界面),并且不会自动刷新,这就产生了空白界面问题,若是在该空白界面手动刷新,会访问服务器,最终跳转到页面 ****/front/#/second。,
问题解析:
尝试之前的方法:
- pageshow事件不适用原因:是当前页面加载完成时,触发的方法,但是该次场景的路径****/visit/first是个访问路径,没有具体的页面,因此无法触发pageshow事件
- hashchange事件不适用原因:当URL的片段标识符更改时,将触发hashchange事件 (跟在#符号后面的URL部分,包括#符号),但是该场景****/front/#/first才开始会触发hashchange事件,返回到路径****/visit/first自然触发不了
- 而路径****/visit/first是个访问路径,根本不存在对应的页去触发刷新按钮,因此考虑到****/front/#/second是第一个真正展示出来的路径,可以考虑让页面无法在继续后退,自然就不存所谓的空白界面了
- “popstate”是用于捕捉前进后退的监听事件,当history实体被改变时,popstate事件将会发
生;当按下返回键的时候,会触发该方法。判断当触发该方法的路径是****/front/#/second时,我们希望它的后退按钮失效,此时就不会再出现空白界面 - pushState(state, title, url): 用新页面的URL替换当前的历史纪录,这样浏览历史记录中就
只有一个页面,后退按钮永远失效。
创建当前历史记录点pushState(state, title, url):创建(添加)一个新的history实体,- state:状态对象,记录历史记录点的额外对象(要跳转的URL),可以为空;
- title:页面标题,目前所有浏览器都不支持;
- url:可选的url,浏览器不会检查url是否存在,只改变url,url必须同域。
- window.history.pushState(json,”",”http://www.qingdou.me/post-1.html”);
解决方案:
/**
* 前进或后退都会调用该方法
*/
const reloadPage= () => {
window.addEventListener("popstate", function(e) {
let redirectPage=window.location.href.indexOf("second");//-1
if(-1!== redirectPage){
window.history.pushState(null, null, document.URL);
}
});
}
reloadPage();