使用jQuery easyui layout较多的同学可能会发现,当我们用脚本隐藏掉某个region的div,再调用layout的resize方法后,并没有出现我们想要的结果,而是页面布局没有发生任何变化。
假设现在我就有这样一个需求,center部分内容很多无法展示,这时候可以将其余的四个region隐藏掉,从而腾出空间给center,又因为layout没有提供隐藏某个region的方法。前面已经说过我们通过隐藏div的方法无法实现页面自动布局,要想解决这个问题,还得对layout的fit有一定程度的认识才行:
1、layout是border布局,采用的是绝对定位的方式,5个region都是绝对定位的,它们的父元素则申明为相对定位才能作为region的容器,这点是由css的特性决定的。
2、layout有个内部方法setSize,这个方法用以重新计算页面各个region大小和位置,同时进行重新布局(压缩后的js文件中,这个方法名称已经不确定了)。
3、当region的容器(也就是包含easyui-layout样式的div)有fit属性,并且值为true的时候,当手动或者程序调整浏览器大小的时候,layout便会调用setSize方法,重新布局。
4、如果脚本对页面的div元素进行的大小,位置,或者display等属性进行操作,但是并没有调整浏览器大小的行为,这个时候不会自动触发setSize函数的调用,想重新布局的话,我们需要自己调用layout的resize方法。
5、layout之所以能自适应,必须有它的规则,那就是在没有手工干预的情况下 north,south,east,west 四个region大小是不变的,空出的空间由center填充。
有了一定的认识后,再回到我遇到的问题:当我设置承载north,south,east,west四个region的div的display属性为none的时候,再调用layout的resize方法后,页面看起来毫无变化。其实不是页面没有重新布局,只是重新计算后的页面布局跟之前的一模一样,由此不难推断问题出在layout内部的setSize方法上。
拿jQuery easyui 1.2.4 的源代码片段做分析:
function setSize(container){ var opts = $.data(container, 'layout').options; var panels = $.data(container, 'layout').panels; var cc = $(container); if (opts.fit == true) { var p = cc.parent(); cc.width(p.width()).height(p.height()); } var cpos = { top: 0, left: 0, width: cc.width(), height: cc.height() }; function setNorthSize(pp){ if (pp.length == 0) { return; } pp.panel('resize', { width: cc.width(), height: pp.panel('options').height, left: 0, top: 0 }); cpos.top += pp.panel('options').height; cpos.height -= pp.panel('options').height; }; if (isVisible(panels.expandNorth)) { setNorthSize(panels.expandNorth); } else { setNorthSize(panels.north); } function setSouthSize(pp){ if (pp.length == 0) { return; } pp.panel('resize', { width: cc.width(), height: pp.panel('options').height, left: 0, top: cc.height() - pp.panel('options').height }); cpos.height -= pp.panel('options').height; }; if (isVisible(panels.expandSouth)) { setSouthSize(panels.expandSouth); } else { setSouthSize(panels.south); } function setEastSize(pp){ if (pp.length == 0) { return; } pp.panel('resize', { width: pp.panel('options').width, height: cpos.height, left: cc.width() - pp.panel('options').width, top: cpos.top }); cpos.width -= pp.panel('options').width; }; if (isVisible(panels.expandEast)) { setEastSize(panels.expandEast); } else { setEastSize(panels.east); } function setWestSize(pp){ if (pp.length == 0) { return; } pp.panel('resize', { width: pp.panel('options').width, height: cpos.height, left: 0, top: cpos.top }); cpos.left += pp.panel('options').width; cpos.width -= pp.panel('options').width; }; if (isVisible(panels.expandWest)) { setWestSize(panels.expandWest); } else { setWestSize(panels.west); } panels.center.panel('resize', cpos); };
代码不长,很容易理解,setSize方法重新布局的步骤:
- 申明一个对象cpos表述位置和大小,初始化为整个layout所在panel的区域。
- 计算north区域的高和宽,通过panel的resize方法重画north,改变cpos的top和height。
- 计算south区域的高和宽,通过panel的resize方法重画south,改变cpos的height。
- 计算east区域的高和宽,通过panel的resize方法重画east,改变cpos的width。
- 计算west区域的高和宽,通过panel的resize方法重画west,改变cpos的left和width。
- 最后根据cpos的值,就是center的大小和位置表述,然后重画center部分。
问题就出在 对cpos的改变上,看代码:
function setNorthSize(pp){ if (pp.length == 0) { return; } pp.panel('resize', { width: cc.width(), height: pp.panel('options').height, left: 0, top: 0 }); cpos.top += pp.panel('options').height; cpos.height -= pp.panel('options').height; };
其中:
cpos.top += pp.panel('options').height; cpos.height -= pp.panel('options').height;
代码这样写是存在一定不足的,因为就算pp所在的div的display属性为none,也就隐藏,但是pp.panel('options').height计算出来的高度跟display属性无关,是否隐藏都是一个值。
要想达到我要求的效果,只要限制这里对cpos的改变就可以了,即:只有在panel可见时才改变,不可见时不做改变,分别对 north,south,east,west 四个都如此处理,然后我们就可以看看效果了。
到这里就算结束了,基于以上的改进后,还有一个好处,那就是很容易为layout增加隐藏和显示方法,可以通过扩展的方式,也可以通过改源码的方式,至于如何增加这两个方法,请看下一篇文章。
更新记录:
2012-05-08:
jQuery easyui 1.2.6版本同样存在这个问题。
管理员 世纪之光 : 2015年07月10日09:16:04 地下1层