Ext布局总的来说是很灵活的,因此我觉得有必要一块探讨一下。
Ext常用的布局都在Ext.layout下,这里几乎涵盖了所有的布局方式(但是值得注意的是通常我们不是直接通过"new"来创建这些类的对象然后往里面添加控件使用,而是作为控件一个配置属性使用让Ext自动创建对应的类),满足开发者需求。那么我们就其中常用的方式逐一介绍。
Border布局
Border布局是Ext中常用布局方式(经常用到整个页面的总体布局),感觉用的几率很大。在看代码之前先熟悉一种特殊的容器ViewPort,它是对于浏览器视窗的抽象,你可以将它理解为浏览器的可见区域,它将渲染到document.body并自动调整大小,一个页面只能创建一个Viewport。
new Ext.Viewport({
layout:"border",
items:[
{region:"north",title:"Up",height:50},
{region:"south",title:"Down",height:50},
{region:"west",title:"Left",width:200},
{region:"east",title:"Right",width:200},
{region:"center",title:"Center"}
]
});
上面的代码很简单,首先Viewport将自动占满整个窗口,然后我们在Viewport中使用border布局(就是上面的layout:'border')。Border布局的用法就是对于其子容器使用region来指示子容器所处的位置(例如上面region:'center'),之后子容器就会显示在其父所在容器的相应位置,这些位置是固定的只有上面我们列出的五个。但是请注意这五个部分不是必须都有的,但是至少要包含"center"(因为它是主体,没有主体如何放内容啊)。
效果:
上面的效果看起来不是太好看,而且我们上面说通常情况下我们没有必要五个部分都有的,那么我们稍微修改一下:
var pnNorth=new Ext.Panel({
id:'pnNorth',
autoWidth:true,
heigth:80,
frame:true,
region:'north',
html:'这里放置页头内容'
});
var pnWest=new Ext.Panel({
id:'pnWest',
title:'菜单项',
width:200,
heigth:'auto',
split:true,//显示分隔条
region:'west',
collapsible:true
});
var pnCenter=new Ext.TabPanel({
region:'center',
activeTab:0,
items:[
{
title:'收件箱',
authHeight:true,
closable:true,//是否可关闭
html:'这里显示所收邮件。。。'
}
]
});
var vp=new Ext.Viewport({
layout:"border",
items:[
pnNorth,
pnWest,
pnCenter
]
});
效果:
还不错吧!
Column布局
从字面就知道Column布局就是列布局,例如我一个panel中还有两个子panel现在想要左侧显示一个右侧显示一个怎么办?这是可以选择Column将父Panel分为两列,左侧一个右侧一个。
var pnSub1=new Ext.Panel({
height:300,
columnWidth:.3,
html:'这是子panle1'
});
var pnSub2=new Ext.Panel({
height:300,
columnWidth:.7,
html:'这是子panle2'
});
var pn=new Ext.Panel({
id:'pn',
title:'父Panel',
renderTo:'divPanel',
width:800,
height:300,
layout:'column',
items:[
pnSub1,
pnSub2
]
});
效果
首先在父容器中设置"layout"为"column"然后在子容器中指定"columnWidth"的值(是比例)就可以显示了,很简单。
Fit布局
如果从复杂度来说fit布局应该算是最简单的了,设置是最少的。Fit布局同样也是设置父容器的layout属性,但是子容器不用设置任何相应属性。它的目的就是为了让子容器能够自适应于父容器(用了fit布局子容器设置宽度无效),但是请注意如果父容器有多个子容器,只会显示第一个。
var pnSub1=new Ext.Panel({
title:"子panel1",
html:"子panel1(会显示)"
});
var pnSub2=new Ext.Panel({
title:"子panel2",
html:"子panel2(不会显示)"
});
var pn=new Ext.Panel({
renderTo:"divPanel",
title:"父panel",
width:800,
height:200,
layout:"fit",
items:[
pnSub1,
pnSub2
]
});
效果:
可以看出只显示了第一个panle,而且它是自适应的,我们没有设置高度和宽度。
Table布局
Table布局多数用在较为复杂的情况下,想一想做web开发总不能就上面几种简单情况吧,因此也就是说Table布局还是很常用的。当然,但是和其他布局相比其参数设置也稍微一些(不用怕,事实上还是很少的)。
new Ext.Panel({
title:"父Panel",
renderTo:"divPanel",
width:900,
height:200,
layout:"table",
layoutConfig:{
columns:3
},
defaults:{
height:100,
width:300
},
items:[
{
html:"第一个子panel(行:1,列:1)",
rowspan:2,//合并行
height:200
},
{
html:"第二个子panel(行:1,列:2)",
colspan:2,//合并列
width:600
},
{
html:"第三个子panel(行:2,列:1)"
},
{
html:"第四个子panel(行:2,列:2)"
}
]
});
效果:
我们上面的布局就是两行三列的布局,但是注意一点在layoutConfi中我们无需指定有几行,只要指定由几列就可以了,有几行往下写几行就可了。另外一点就是对于合并行列的时候记得指明高和宽否则可能出现你合并的行跟未合并的单元格一样高的情况。同Ext中多数布局一样也是在父容器指定对应的布局为"table",然后子容器设置对应的参数(对table布局就是colspan等)。
上面的布局或许有些幼稚,真正这样做的不太多,我们稍微修改一下:
new Ext.Panel({
id:'pn',
title:"新闻",
renderTo:"divPanel",
width:800,
height:500,
layout:"table",
bodyStyle:'padding:10 10 10 10',
layoutConfig:{
columns:2
},
defaults:{
height:220,
width:380,
frame:true
},
items:[
{
title:'国际',
html:"第一个子panel(行:1,列:1)",
bodyStyle:'padding:20'
},
{
title:'国内',
html:"第一个子panel(行:1,列:1)",
bodyStyle:'padding:20'
},
{
title:'新闻组图',
colspan:2,
html:"第一个子panel(行:1,列:1)",
bodyStyle:'padding:20;',
width:770
}
]
});
注意,还有样式:
#pn td {
padding:5px;
}
效果:
上面看起来还可以吧,这就是table布局出来的啊,O(∩_∩)O~!
Form布局
这个布局是专门为表单而设计的布局方式,当然多数是用在FormPanel中(它也是FormPanel默认的布局方式)。我们前面说过FormPanel但是没有涉及复杂布局,事实实际应用中更多的是较复杂的布局。
比较一下下面两幅图有什么区别,我想除了标题是没有任何区别的吧,但是事实上这是两种组件,一个是Panel另一个是FormPanel:
new Ext.Panel({
renderTo:"divPanel",
title:"这个是Panel",
width:300,
height:120,
bodyStyle:'padding:10',
layout:"form",
hideLabels:false,
labelAlighn:"right",
defaultType:"textfield",
items:[
{fieldLabel:"姓名",name:"name"},
{fieldLabel:"年龄",name:"age"}
]
});
new Ext.FormPanel({
renderTo:"divPane2",
title:"这个是FormPanel",
width:300,
height:120,
bodyStyle:'padding:10',
layout:"form",
hideLabels:false,
labelAlighn:"right",
defaultType:"textfield",
items:[
{fieldLabel:"姓名",name:"name"},
{fieldLabel:"年龄",name:"age"}
]
});
从代码我们也可看出来,区别就是对于Panel我们配置了layout为form,从这也能看出来说FormPanel默认的布局就是form布局,所以对于习惯于用Panel而不习惯用FormPanel的朋友尽管用Panel,但是一定要考虑好提交的问题,如果使用panel的话,要做提交可是要一个个获得控件的值的,而FromPanel则不需要。
另外一我们需要扩展一下,因为实际的布局要比这复杂。
这个表单虽然不算是太复杂,但是比较有代表性,基本上常用的控件都放上去了,也包含了常见的radio多列布局。好了看代码吧:
Ext.onReady(function(){
var pnRow1=new Ext.Panel({
border:false,
layout:'column',
items:[
new Ext.Panel({
columnWidth:.5,
layout:'form',
border:false,
labelWidth:40,
labelAlign:'right',
items:[
{
xtype:'textfield',
fieldLabel:'姓名',
name:'uname',
anchor:'95%'
}
]
}),
new Ext.Panel({
columnWidth:.3,
layout:'form',
border:false,
labelWidth:40,
labelAlign:'right',
items:[
{
xtype:'radio',
fieldLabel:'性别',
boxLabel:'男',
name:'sex',
inputValue:'男',
checked:true,
anchor:"95%"
}
]
}),
new Ext.Panel({
columnWidth:.2,
layout:'form',
border:false,
labelWidth:1,
items:[
{
xtype:'radio',
boxLabel:'女',
name:'sex',
inputValue:'女',
labelSeparator:'',
anchor:"95%"
}
]
})
]
});
var pnRow2=new Ext.Panel({
layout:'column',
border:false,
items:[
new Ext.Panel({
columnWidth:.5,
layout:'form',
border:false,
labelWidth:40,
labelAlign:'right',
items:[
{
xtype:'datefield',
name:'birthday',
fieldLabel:'生日',
anchor:'95%'
}
]
}),
new Ext.Panel({
columnWidth:.5,
layout:'form',
border:false,
labelWidth:40,
labelAlign:'right',
items:[
{
xtype:'combo',
name:'study',
store:['专科','本科','硕士','博士'],
fieldLabel:'学历',
anchor:'95%'
}
]
})
]
});
var pnRow3=new Ext.Panel({
layout:'column',
border:false,
items:[
new Ext.Panel({
columnWidth:.3,
layout:'form',
border:false,
labelWidth:40,
labelAlign:'right',
items:[
{
xtype:'checkbox',
name:'hoby',
inputValue:'computer',
fieldLabel:'爱好',
boxLabel:'计算机',
anchor:'95%'
}
]
}),
new Ext.Panel({
columnWidth:.3,
layout:'form',
border:false,
labelWidth:1,
labelAlign:'right',
items:[
{
xtype:'checkbox',
name:'hoby',
inputValue:'football',
boxLabel:'足球',
labelSeparator:'',
anchor:'95%'
}
]
}),
new Ext.Panel({
columnWidth:.4,
layout:'form',
border:false,
labelWidth:1,
labelAlign:'right',
items:[
{
xtype:'checkbox',
name:'hoby',
intputValue:'tinyTable',
boxLabel:'乒乓球',
labelSeparator:'',
anchor:'95%'
}
]
})
]
});
var pnRow4=new Ext.Panel({//当然这里直接在FormPanel中添加TextField就可以了,因为只有一行,但是为了一致以及对齐方便我这里还是放到了panel中
layout:'form',
border:false,
labelWidth:40,
labelAlign:'right',
items:[
{
xtype:'textfield',
name:'email',
fieldLabel:'住址',
anchor:'98%'
}
]
});
var pnRow5=new Ext.Panel({
layout:'form',
border:false,
labelWidth:40,
labelAlign:'right',
items:[
{
xtype:'htmleditor',
name:'note',
fieldLabel:'备注',
height:200,
anchor:'98%'
}
]
});
new Ext.FormPanel({
renderTo:"divPanel",
title:"个人信息录入",
width:600,
bodyStyle:'padding:10px',
layout:"form",
items:[
pnRow1,
pnRow2,
pnRow3,
pnRow4,
pnRow5
]
});
});
代码看似比较多,其实很容易理解,Ext有一个特点就是组件的自由组合,那么我们只需要拆分来看就可以了。从大的方面是一个FormPanel,其中有五行内容(这个五个panel当然是使用的父容器FormPanel的默认布局"form"了,所以依次向下放)。先暂且不管第四行和第五行,我们看看其他三行,其实格式基本上是一样的,就是首先这一行放到一个panel中(假设叫做Panel_A),利用"column"布局来解决多列问题,让后再其Item中我们再再每个column中放一个panel(Panel_B)而这个panel我们使用"form"布局(这个panel中其实都只有一个form控件,所以当然不用form布局也是可以的,之所以用form布局是为了能够使用labelWidth这样的form特有属性),然后在其中放一个form控件,这样也就解决了多列布局的问题。关于第四列和第五列本身就是单列的也没有什么好解释的。上面的方法是通用的,基本上用这种方法所有的复杂表单布局都可以解决了。可能会有人问遇到合并行的怎么办?其实利用上面的方法很容易的,例如假设上面"性别"和"学历"是合并的,那么我们就没有必要用两个panel放两行了,就当做一行,只不过在第一列的Panel_B中放两个form控件就可以了(因为它是form布局,默认就会在两行)。
那么还有没有其他方法呢?答案是肯定的,那就是table布局,个人感觉对于较为规则的多列布局用table还是不错的,不过像上面的例子这样从总体上看是两列的布局,但是有些列里面又是多列我认为用table也是太简单。
总结:
上面说了接种布局,其实简单总结起来border布局一般作为页面整体布局来使用;fit布局适用于那种需要将子类完全占满父类容器的情况;column布局用于多列;form是一种表单特有布局方式,实质是一行一控件的形式;table布局适用多行多列但是有时宽高不太容易控制。而且值得强调的一点就是给一个控件设置layout属性,其实指的是其内部控件的布局方式而不是它本身的布局,这点要搞清楚。