easyui中tab组件每次切换tab页时内部页面滚动条到顶端问题修改

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liuxiao723846/article/details/84665868

使用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

猜你喜欢

转载自blog.csdn.net/liuxiao723846/article/details/84665868