在单页应用中,翻页通常经过display:none将先前的面板(通常就是个div容器)隐藏,而后将本次须要展示的面板设置成display:block(固然,还可能加点css切换动画,不过不影响咱们本次的讨论结果,故不予关注),通常状况下,这样的处理方式是没啥问题的,不过若是以前的面板自己有滚动条,那么跳转到新面板以后再返回到原先面板就会致使滚动条位置直接变成0,这主要是当元素的display为none时,元素不占据位置,等到display非none的时候才会被从新布局,渲染。css
咱们以jq.ui(一个用于构建jqMobi应用的用户界面库)为例说明下怎么解决单页应用中切换页面致使的滚动条位置信息丢失问题算法
在老页面被display:none以前用一个堆栈存储下当前页面的滚动条位置,而后在用户点击浏览器返回按钮的时候取出栈顶记录的滚动条位置信息并调用window.scroll滚动到指定位置便可。数组
一、在jq.ui源码中页面切换以前手动触发个事件(用于在本身的代码中捕捉此事件并记录老页面滚动条位置信息)浏览器
/*在老的panel被display:none以前触发beforeHideOldPanel事件,
*用于记录当前滚动条位置,以便于返回上一页时滚动到指定位置*/
jq(oldDiv).trigger('beforeHideOldPanel');
复制代码
二、在页面上监听第一步中触发的beforeHideOldPanel事件和popstate(浏览器回退事件)以及loadpanel(加载面板事件),当beforeHideOldPanel事件被触发且当前不在回退时记录滚动条位置,当loadpanel事件被触发且当前正在回退时从堆栈中取出滚动条位置并调用window.scroll手动滚动到指定位置bash
// 因为jq.wow.js中经过display:none方式切换面板,致使老的panel滚动条信息丢失
// (display:none元素无高度),点击返回上一页时会自动定位到顶部
// 此处经过一个简单的堆栈记录老页面的滚动条信息,退回上一页时手动调用window.scroll滚动到指定位置
function resetScrollWhenPopstate() {
//借助数组实现个简单的堆栈
var scrollStack = {
list: [],
push: function (obj) {
this.list.push(obj);
},
pop: function () {
return this.list.pop();
}
};
$('.panel').on('beforeHideOldPanel', function (e) {
// 仅非回退时才记录滚动条位置
if (!isPopStating) {
scrollStack.push({
oldPageId: e.currentTarget.id,
oldScrollTop: document.documentElement.scrollTop || document.body.scrollTop
});
}
}).on('loadpanel', function (e) {
// 仅回退页时才恢复滚动条位置
if (isPopStating) {
var obj = scrollStack.pop();
if (obj && obj.oldPageId == e.currentTarget.id) {
window.scroll(0, obj.oldScrollTop);
}
}
});
// 标示是否正在回退
var isPopStating = false;
window.addEventListener('popstate', function () {
isPopStating = true;
setTimeout(function () {
isPopStating = false;
}, 200);
});
}
复制代码
看似简单的堆栈其实仍是有挺大用处的,算法和数据结构这东西看来仍是须要学习学习(@ο@) 哇~数据结构