手机网页和app性能差别很大,而且我们经常会遇到从列表打开详细页,返回再打开另一个详细页的情况
如果按常规href 或者 location.href=""方式,有以下缺点
1.页面每次都会跳转,返回时,前页重新加载不方便记录上次位置,而且会有一段时间白屏
2.无法监听手机返回事件,阻止返回
我写了一个仿app的框架解决这样的问题
原理就是h5增加了hash栈特性
history.pushState(state, title, url); 添加一条历史记录,不刷新页面
window.addEventListener('popstate', handlePopstate);//监听状态改变
具体实现方法
index.html页面有一个 arrwin数组 记录所有打开的页面(目前用iframe实现打开新的页面)
一.打开新的页面(比如detail.html)的时候 向arrwin数组中插入一个对象,并且在index.html页面增加一个全宽高的div覆盖在index.html上,里面为src为detail.html的iframe标签。
function openwin(key,src,title) {
if (title) document.title = title || "";
pushHash({
key:key,
title:title
});
//修改objwin
objdata.objwin[key] = {
wintype:'win',
key:key
};
if (!src) {
src = key + '.html?v=' + Arg('v');
}
var str =
'<div class="oneopenpage" style="border:none;z-index:' + objdata.curzindex + '">\
<div class="oneopenpage_overlay"></div>\
<iframe class="oneopenpage_frame" id="frame' + key + '" src="" name="' + key + '"></iframe>\
</div>';
var _obj = $(str);
objdata.curzindex += 1;
if (!title) {
setTimeout(function () {
var win = $('#frame' + key).length?$('#frame' + key)[0].contentWindow:null;
if (win && win.document && win.document.title) {
objdata.arrwin[objdata.arrwin.length - 1].title = win.document.title;
document.title = win.document.title;
}
},2000);
}
$('body').append(_obj);
_obj.show();
_obj.width();
_obj.addClass('oneopenpage--visible');
var _frame = _obj.find('.oneopenpage_frame');
_frame.width();
_frame.transitionEnd(function () {
_frame.prop('src',src);
});
}
function pushHash(obj) {
objdata.arrwin.push(obj);
window.history.pushState(null,obj.title,"#" + obj.key);
}
二.正常关闭页面的时候 监听"popstate"事件 (obj.onPageBack为null),直接调用 $("#frame" + obj.key).parent().remove(); 将index页面的div移除。
function initEvent() {
window.addEventListener("popstate",function (e) {
if (objdata.arrwin && objdata.arrwin.length > 1) {
var obj = objdata.arrwin[objdata.arrwin.length - 1];
objdata.curhash = objdata.arrwin[objdata.arrwin.length - 1].key;
if (obj.onPageBack) {
window.history.pushState(null,obj.title,"#" + obj.key);
obj.onPageBack(function () {
obj.onPageBack = null;
history.back();
});
} else {
objdata.arrwin.pop();
backEvent(obj);
}
}
},false);
}
function backEvent(obj) {
if (objdata.curhash) {
closewin(obj);
}
document.title = objdata.arrwin[objdata.arrwin.length - 1].title || '';
}
function closewin(obj) {
if (obj && obj.wintype) {
if(obj.wintype == 'layer'){
closelayer(obj);
} else if(obj.wintype == 'popup'){
closepopupevent(obj);
}
} else {
$("#frame" + obj.key).parent().remove();
}
}
三.关闭页面时需要拦截返回按钮事件
首先要清楚,用户点击android返回按钮时,页面url的hash值是肯定会回退到上一个hash历史的,这个我们无法阻止。
那咱们拦截返回的思路是
1.如果某页面需要监听返回事件,则注册setOnPageBack方法,给页面的obj增加obj.onPageBack属性。
2.用户点击返回时,hash值被改变,但此时,页面尚未关闭。我们监听到 "popstate" 事件,如果obj.onPageBack属性,我们立刻向栈内再次push该页面hash(window.history.pushState(null,obj.title,"#" + obj.key);),保证当前打开的页面和hash值是对应的。
3.等用户点击确认关闭的时候,将该页面的obj.onPageBack 修改为 null,再次调用history.back();
4.因为已经将obj.onPageBack 修改为 null 再次监听"popstate"的时候,将不再走第2步,直接进行页面的关闭。
window.addEventListener("popstate",function (e) {
if (objdata.arrwin && objdata.arrwin.length > 1) {
var obj = objdata.arrwin[objdata.arrwin.length - 1];
objdata.curhash = objdata.arrwin[objdata.arrwin.length - 1].key;
if (obj.onPageBack) {
window.history.pushState(null,obj.title,"#" + obj.key);
obj.onPageBack(function () {
obj.onPageBack = null;
history.back();
});
} else {
objdata.arrwin.pop();
backEvent(obj);
}
}
},false);
parent.setOnPageBack(function (backEvent) {
if (objdata.needconfirm) {
$.confirm("确认关闭吗",function () {
backEvent();
})
} else {
backEvent();
}
})
$("#btnback").click(function () {
history.back();
})
function setOnPageBack(backevent) {
objdata.arrwin[objdata.arrwin.length - 1].onPageBack = backevent;
}
目前我们项目css框架为weui,js框架jquery-weui,列表都是用mescroll实现
框架代码