1. 程式人生 > >easyui中tab元件每次切換tab頁時內部頁面滾動條到頂端問題修改

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