問題背景
在單頁應用中,翻頁一般通過display:none將先前的皮膚(一般就是個div容器)隱藏,然後將本次需要展現的皮膚設定成display:block(當然,還可能加點css切換動畫,不過不影響我們本次的討論結果,故不予關注),一般情況下,這樣的處理方式是沒啥問題的,不過如果之前的皮膚本身有滾動條,那麼跳轉到新皮膚之後再返回到原先皮膚就會導致滾動條位置直接變成0,這主要是當元素的display為none時,元素不佔據位置,等到display非none的時候才會被重新佈局,渲染。
我們以jq.ui(一個用於構建jqMobi應用的使用者介面庫)為例說明下怎麼解決單頁應用中切換頁面導致的滾動條位置資訊丟失問題
思路
在老頁面被display:none之前用一個堆疊儲存下當前頁面的滾動條位置,然後在使用者點選瀏覽器返回按鈕的時候取出棧頂記錄的滾動條位置資訊並呼叫window.scroll滾動到指定位置即可。
基於jq.ui的例項
1、在jq.ui原始碼中頁面切換之前手動觸發個事件(用於在自己的程式碼中捕捉此事件並記錄老頁面滾動條位置資訊)
/*在老的panel被display:none之前觸發beforeHideOldPanel事件,
*用於記錄當前滾動條位置,以便於返回上一頁時滾動到指定位置*/
jq(oldDiv).trigger('beforeHideOldPanel');
複製程式碼
2、在頁面上監聽第一步中觸發的beforeHideOldPanel事件和popstate(瀏覽器回退事件)以及loadpanel(載入皮膚事件),當beforeHideOldPanel事件被觸發且當前不在回退時記錄滾動條位置,當loadpanel事件被觸發且當前正在回退時從堆疊中取出滾動條位置並呼叫window.scroll手動滾動到指定位置
// 由於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);
});
}
複製程式碼
總結
看似簡單的堆疊其實還是有挺大用處的,演算法和資料結構這東西看來還是需要學習學習(@ο@) 哇~