现在的位置: 首页 > easyui > Layout > layout > 正文
layout自适应时重新计算布局存在的不足
2012年02月01日 layout ⁄ 共 3710字 评论数 8 ⁄ 被围观 8,512 views+
文章目录
[隐藏]

使用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版本同样存在这个问题。

目前有 8 条留言 其中:访客:5 条, 博主:1 条 引用: 2

  1. Free Dating sites : 2013年08月07日23:56:51  -49楼 @回复 回复

    Hi, I love your website if I am sincere. Wherever did you will get it built?

  2. xin : 2014年03月27日16:24:06  -48楼 @回复 回复

    现在1.3.5的该怎么处理

  3. aa : 2015年07月07日19:29:01  -47楼 @回复 回复

    要在哪改setsize方法?怎么改

  4. : 2015年07月08日10:56:37  -46楼 @回复 回复

    1.3.5版本好像也存在这问题,怎么改?


    • 管理员
      世纪之光 : 2015年07月10日09:16:04  地下1层 @回复 回复

      每个版本的压缩代码都不一样,按照我的分析思路 自己去看看代码,我没法每个版本都去分析现成的给你们。

      • nono_thin : 2015年08月03日13:55:08  地下2层 @回复 回复

        为什么效果的页面有报错呢?

给我留言

留言无头像?


×