easyui中tab元件每次切換tab頁時內部頁面滾動條到頂端問題修改
使用easyui中的tab元件,每個tab頁面都是一個內嵌iframe,當在介面上滑鼠幾點做tab頁切換的時候,每次內部頁面的滾動條都會自動到頂端,這樣給使用上帶來了很大的不方便。接下來,我們看如何來優化這個功能。
首先,我們想到的時候給tab新增兩個事件:onSelect和onUnSelect,當離開的時候(unSelect)記錄下當前頁面的滾動條高度,在進入的時候(select)使用js設定頁面的滾動條高度。我們來分解,一步一步的實現。
1、需要一個map資料結構,記錄每個tab頁的滾動條高度:
function Map() { var struct = function(key, value) { this.key = key; this.value = value }; var put = function(key, value) { for (var i = 0; i < this.arr.length; i++) { if (this.arr[i].key === key) { this.arr[i].value = value; return } } this.arr[this.arr.length] = new struct(key, value) }; var get = function(key) { for (var i = 0; i < this.arr.length; i++) { if (this.arr[i].key === key) { return this.arr[i].value } } return null }; var remove = function(key) { var v; for (var i = 0; i < this.arr.length; i++) { v = this.arr.pop(); if (v.key === key) { continue } this.arr.unshift(v) } }; var getAllValues = function() { var tmp = new Array(); for (var i = 0; i < this.arr.length; i++) { tmp[i] = this.arr[i].value } return tmp }; var getAllKeys = function() { var tmp = new Array(); for (var i = 0; i < this.arr.length; i++) { tmp[i] = this.arr[i].key } return tmp }; var size = function() { return this.arr.length }; var isEmpty = function() { return this.arr.length <= 0 }; var removeAll = function() { this.arr = [] }; this.getFirstValue = function() { return this.arr[0].value }; this.getFirstKey = function() { return this.arr[0].key }; this.arr = new Array(); this.get = get; this.put = put; this.remove = remove; this.size = size; this.isEmpty = isEmpty; this.removeAll = removeAll; this.getAllValues = getAllValues; this.getAllKeys = getAllKeys; };
2、在主頁面(index)上,給tab元件新增事件
//定義全域性變數 var scrollMap = new Map(); var selectedIndex = 0; subPageScrollHeight = 0; $(function(){ $("#tabs_index").tabs({ onSelect:function(title,index){ //獲取index //var tab = $('#tabs_index').tabs('getSelected'); //selectedIndex = $('#tabs_index').tabs('getTabIndex',tab); selectedIndex = index; //設定位置 var val = scrollMap.get(selectedIndex); if (!isNull(val)) { $("#tabs_index > div").eq(1).children("div").eq(selectedIndex).find("iframe")[0].contentWindow.scrollTo(0,val); } } }); $("#tabs_index").tabs({ onUnselect:function(title,index){ if (selectedIndex>0) { //這種獲取子頁面滾動條高度失敗,始終是0;改成了子頁面監控自己的滾動條 //var h = $("#tabs_index > div").eq(1).children("div").eq(selectedIndex).find("iframe")[0].contentWindow.document.documentElement.scrollTop; //這種格式獲取子頁面變數值 失敗!改成子頁面修改父頁面值 //var ifname = $("#tabs_index > div").eq(1).children("div").eq(selectedIndex).find("iframe")[0].name; //var h1 = document.frames[ifname].hhh; //alert(title+"is unselected,"+selectedIndex+",h:"+subPageScrollHeight); scrollMap.put(index,subPageScrollHeight); } } }); });
scrollMap:用來儲存tab頁面和高度的,key是tabIndex;
selectedIndex:當前啟用的tabIndex;
subPageScrollHeight:父頁面(index)的全域性變數,供子頁面(iframe)去修改,記錄子頁面滾動條高度。
這裡在處理離開(onSelect)邏輯時走了一些彎路,具體分析一下:
1)在離開時獲取內部(iframe)頁面的滾動條,然後存到map中:
var h = $("#tabs_index > div").eq(1).children("div").eq(selectedIndex).find("iframe")[0].contentWindow.document.documentElement.scrollTop;
通過觀察html可以發現,easyui會給tab元件生成兩個div,第一個是tab的標題,第二個是tab的內容,在第二個div中每個頁面又是一個div,所以我們可以通過上面jquery的篩選來獲得到對應iframe的高度。
但是,每次這個h都是0。為什麼呢?開始懷疑方法錯了,但是後來想明白了,這不就是問題的本身嗎:easyui每次在離開的時候會把內部頁面的滾動條置頂,所以每次h都是0 了。
2)每個子頁面(iframe)都儲存一個全域性變數h,各自頁面來維護其值:
上面方式行不通,換一個思路,讓每個子頁面(iframe)都儲存一個全域性變數h,各自頁面來維護其值,父頁面(index)中,tab離開(unSelect)的時候獲取子頁面的值,儲存到map中。這就需要定義一個公共的onScroll監聽事件,來監聽每個子頁面的滾動了。
$(window).scroll(function(){
hhh = $(document).scrollTop();
});
然後再Unselect中,使用如下方法獲取:
//var ifname = $("#tabs_index > div").eq(1).children("div").eq(selectedIndex).find("iframe")[0].name;
//var h1 = document.frames[ifname].hhh;
經過實驗使用獲取不到值,原因:https://blog.csdn.net/liuxiao723846/article/details/84643812
所以,只要再更換思路。
3)主頁面(index)中定義全域性變數subPageScrollHeight,讓各個子頁面去更新這個值:
所以,公共的監控函式修改成:
$(window).scroll(function(){
//父頁面值
parent.subPageScrollHeight = $(document).scrollTop();
});
這樣,在父頁面中,當tab離開時就可以獲取到每個頁面的高度了。
3、優化:
講過了上面的操作,已經可以實現了功能。但是經過測試,發現多切換幾次,滾動條又會回到頂部。這是什麼原因呢?
$(window).scroll(function(){
parent.subPageScrollHeight = $(document).scrollTop();
console.log(parent.subPageScrollHeight);
});
在scroll監聽函式裡面列印log,觀察後發現:當切換tab時,每次列印行日誌,第一行是一個正常的高度(例如3009),第二行每次都是0。這又是為什麼呢?
繼續思考,又回到了開始的問題:easyui每次在離開(unselect)的時候會把內部頁面的滾動條置頂。所以整個過程是:
1)進入(select)的時候,我們會手動把下個頁面滾動高度設定成正常值,所以會觸發一次scroll事件,故第一次列印的是正常值;
2)但是在離開的時候tab每次又把上一個頁面置頂,又出發了一次scroll事件,在主頁面的全域性變數(subPageScrollHeight )就被設定成了0 。這樣,切換兩次後,就會出現不對的情況(又置頂了)
那如何解決呢?
在統一監聽程式碼中做如下改造:
$(window).scroll(function(){
//父頁面值
if ($(document).scrollTop() > 0) {
parent.subPageScrollHeight = $(document).scrollTop();
}
});
這樣,就避免了“離開的時候tab每次又把上一個頁面置頂,又出發了一次scroll事件,在主頁面的全域性變數就被設定成了0”這個問題。但又有人會問,那我切換完tab後,主動將頁面放到最上端,豈不是會有問題了?
答案是不會的,因為scroll會一直監聽,及時手動將頁面放到了最上部,subPageScrollHeight 全域性變數會是一個很接近的0的數,比如1,但就是不會是0.這樣,0和1之間的差別不會影響前端體驗,都是在最上端。
後記:
經過上面優化,tab已經沒有任何問題了。但是,還是會有一定的優化空間,例如:統一監聽scroll時間會一直執行,能否“稀釋”這個函式,但又要保證正確性呢?
當然後,答案就是:https://blog.csdn.net/liuxiao723846/article/details/84644690