第三章 布局
布局用于定義容器如何組織内部子元素和控制子元素的大小。在一個應用程式中,作為定義容器的組織形式,布局是一個十分重要的元件。是顯示單個子元素?還
是垂直或水準顯示多個子元素?這些均由布局來定義。并且布局将占用應用程式大部分的呈現時間。extjs4中對布局進行了重大的修整。下面我們将學習并熟
悉extjs中的布局。
本章目錄如下:
<a href="http://www.cnblogs.com/fsjohnhuang/archive/2013/02/19/2917233.html#a3.1.">3.1. extjs 4 布局</a>
<a href="http://www.cnblogs.com/fsjohnhuang/archive/2013/02/19/2917233.html#a3.2.">3.2. container布局</a>
<a href="http://www.cnblogs.com/fsjohnhuang/archive/2013/02/19/2917233.html#a.3.4">3.4. 總結</a>
extjs4對布局進行了重大的修整。布局引擎已被重寫,但api仍保持原樣,進而使得布局是向後相容的。當然所生成的html标簽也作出了修整。
extjs2中引入了布局這一特性。當時其具有良好的性能和速度,但欠缺靈活性。後來的版本增強了靈活性卻犧牲了性能(譯者語:extjs3在性能方面
确實令不少人望而卻步啊!)。在extjs4中對加載速度、性能和靈活性等方面都作出了改進,通過下面的圖例我們可以看到改進結果:

除了上述内容,extjs4還引入兩類型的布局:container 布局 和 component 布局。
component 布局:負責組織元件的html元素;
包括:dock布局、toolbar布局、field布局、triggerfield布局。
container 布局:負責容器内容extjs元素和調整extjs元素的大小。
包括:border布局、box布局、fit布局等等。
(譯者語:如果接觸過extjs舊有版本的朋友應該對container布局不陌生了,而component布局是extjs4獨有的,但不由開發人員來設定、調用,而是架構中的元件已内置好的。)
首先我們來看看container布局的層級圖吧!
當沒有為容器(container或其子類執行個體)配置layout配置項時就會使用auto布局。
特點:
1. 容器子元素不随容器大小變化而變化;
2. 容器子元素按添加到容器的順序自上而下排列。
執行個體:
var panel1 = ext.create('ext.panel.panel', {
title: 'panel 1',
html: 'panel 1',
height: 60,
width: 100
});
var panel2 = ext.create('ext.panel.panel', {
title: 'panel 2',
html: 'panel 2',
height: 80,
width: 60
var panel3 = ext.create('ext.panel.panel', {
title: 'panel 3',
html: 'panel 3',
height: 65,
width: 100
var panel4 = ext.create('ext.panel.panel', {
title: 'panel 4',
html: 'panel 4',
height: 70,
width: '90%'
var auto = ext.create('ext.window.window', {
title: 'auto layout',
width: 100,
height: 320,
//layout:'auto',
defaults: {
bodystyle: 'padding:15px'
},
items: [panel1, panel2, panel3, panel4]
});
上述執行個體建立了四個panel元件執行個體并作為window元件執行個體的子元素。
defaults:用于統一設定其子元素的配置項。
結果如下:
1. 如果我們放大或縮小window元件執行個體,其内部的panel1、panel2、panel3和panel4的大小将不會随之變化;
2. panel4中width值為90%表示該元素的寬度為父容器body寬度的90%。(在chrome中使用百分比來設定寬度會出現沒有右邊框的異常)
1. 容器子元素會随容器大小而變化;
2. 子元素按添加到容器的次序,自上而下的排列;
3. 子元素預設寬度為容器的body寬度。
4. 通過子元素的x、y配置項可設定子元素離原來位置的左邊距和上邊距(效果如同position:relative,top:...,left:....)
執行個體:
html: '100% 30%',
anchor:'100% 30%'
html: '80% 25%',
anchor:'80% 25%'
html: '-70 20%',
anchor:'-70 20%'
html: '-30 25%',
anchor:'-30 25%'
var anchor = ext.create('ext.window.window', {
title: 'anchor layout',
width: 250,
height:300,
layout:'anchor',
bodystyle: 'padding:10px'
anchor.show();
從
執行個體我們可以知道,除了容器的layout配置項設為anchor後,若要定制子元素的布局細節就必須設定設定子元素的anchor配置項。
(ext.panel.panel中有anchorsize這一配置項,但與布局中上述的anchor配置項功能不同,無法實作上述效果)
anchor值為字元串,若形如"80"、"-30"或"80%"表示設定子元素占容器的寬度;而形如"80 90"或"90 80%"等表示設定子元素占容器的寬度和高度。
80等正數表示子元素離父容器左内邊框、上内邊框的距離;
-30等負數表示子元素離父容器右内邊框、下内邊框的距離;
80%等百分數表示子元素占父容器寬度、高度的百分比。注意:對于高度使用百分比值時,每個子元素的最終的值都是“百分比*父容器的高度”。
改變容器大小後
absolutelayout是anchorlayout的子類,其繼承了anchorelayout的所有特性。并且可以設定x和y配置項來相對與父容器來定位子元素。
1. 容器子元素會随容器大小而變化;
2. 子元素預設寬度為容器的body寬度;
3. 子元素預設位置為容器的左上角(x:0,y:0),就是不設定各子元素的x、y配置項時,所有子元素會在容器的左上角重疊;
4. 子元素通過x、y配置項來設定子元素離容器左内邊框、上内邊框的距離。
html: 'x: 10; y: 10 - anchor: 80% 80%', /*this config option will display the given text inside the panel*/
anchor:'80% 80%',
x: 10,
y: 10
var absolute = ext.create('ext.window.window', {
title: 'absolute layout',
width: 300,
height: 200,
layout:'absolute',
items: [panel1]
absolute.show();
注意:子元素的anchor屬性,對于高度使用百分比值時,每個子元素的最終的值都是“百分比*父容器的剩餘高度”,父容器的剩餘高度=父容器的高度-較早添加到容器的子元素高度。是以子元素添加到容器的次序将在使用百分比設定子元素anchor屬性高度時起作用。
hbox布局組織子元素在容器内水準排列。
1. 容器子元素會随容器大小而變化;
2. 通過三個可選的配置項來組織子元素相對于容器的寬和高。
配置項介紹:
1. flex:各個子元素的的flex配置項會互相作用來決定子元素在容器内的寬度。如子元素1的flex為1,而子元素2的flex為2,而容器寬度為90,那麼子元素1的寬度就為30,而子元素2的寬度為60。
2. align:設定各個子元素的水準方向的對齊,可選值有:
top:預設值,頂對齊;
middle:中心線對齊;
strech:使各個子元素的高度為容器body的高度來對齊;
strechmax:以最高的子元素的高度作為其他各個子元素的高度來對齊。
3.pack:設定所有子元素組成的元素塊是緊靠容器的左、中、右中哪個位置,可選值有:
start:預設值,靠容器的左邊;
center:靠中間;
end:靠容器的右邊。
1配置項為子元素的配置項;2和3為layout屬性的配置項。
html: 'panel 1', //this text will be displayed on the panel body
flex: 1
html: 'panel 2', //this text will be displayed on the panel body
flex: 3
var hbox = ext.create('ext.window.window', {
title: 'hbox layout',
height:100,
layout: {
type: 'hbox',
align: 'stretch'
bodystyle: 'padding:10px'
items: [panel1, panel2]
hbox.show();
結果:
vbox布局與hbox相似,不同的是它用于組織子元素在容器内部垂直方向的布局。
1. 容器子元素會随容器大小而變化;
1. flex:各個子元素的的flex配置項會互相作用來決定子元素在容器内的高度。如子元素1的flex為1,而子元素2的flex為2,而容器高度為90,那麼子元素1的高度就為30,而子元素2的高度為60。
2. align:設定各個子元素的垂直方向的對齊,可選值有:
left:預設值,左對齊;
center:中心線對齊;
strech:使各個子元素的寬度為容器body的寬度來對齊;
strechmax:以最寬的子元素的寬度作為其他各個子元素的寬度來對齊。
flex: 2
html: 'panel 2',
var vbox = ext.create('ext.window.window', {
title: 'vbox layout',
width: 82,
height: 300,
type: 'vbox',
bodystyle: 'padding:15px'
vbox.show();
accordion布局是vbox布局的子類。與vbox布局不同的是accordion布局僅僅會展現其中一個子元素而其餘子元素将被折疊起來。
2. 僅僅會展現其中一個子元素而其餘子元素将被折疊起來或僅僅展現部分子元素而其他元素被折疊。
1. multi:預設為false,true表示可以同時展現多個子元素;
2. collapsefirst:預設為false,false表示expand/collapse按鈕在标題工具按鈕欄的最左邊,true表示在最後邊。(關于标題工具按鈕欄ext.panel.tool我們将在後面學習)
3. animate:預設為true,false為執行expand/collapse操作時沒有動畫效果
4. fill:預設為true,true表示expand的子元素高度将為整個容器剩餘高度,false表示expand的子元素高度為自身的高度
1、4為layout配置項的屬性,2、3為子元素的配置項。
(譯者語:本人試了一下activeontop這一配置項,但未成功。)
html: '<b>panel 1</b>'
html: '<b>panel 2</b>'
html: '<b>panel 3</b>'
html: '<b>panel 4</b>'
var panel5 = ext.create('ext.panel.panel', {
title: 'panel 5',
html: '<b>panel 5</b>'
var accordion = ext.create('ext.window.window', {
title: 'accordion layout',
margins:'5 0 5 5',
split:true,
width: 210,
height:250,
layout:'accordion',
bodystyle: 'padding:35 15 0 50'
items: [panel1, panel2, panel3, panel4, panel5]
accordion.show();
使用table布局那麼将生成html的table标簽來作為布局的容器。
1. 可通過配置來設定容器子元素的大小是否随容器的大小變化
1. columns:設定表格布局的列數;
2. tableattrs:設定表格的屬性(如style等)
3. trattrs:設定行的屬性
4. tdattrs:設定單元格的屬性
5. colspan:設定跨列數目
6. rowspan:設定跨行數目
1、2、3和4為layout配置項的屬性,5、6為子元素的配置項。
注意:子元素的排列次序為由左至右,由上到下。
var table = ext.create('ext.window.window', {
title: 'table layout',
type: 'table',
columns: 3,
tableattrs: {
style: {
width: '100%',
height: '100%'
}
items:[{
html:'cell 1',
rowspan: 3 //this cell will span 3 rows
},{
html:'cell 2'
html:'cell 3'
html:'cell 4'
html:'cell 5'
html:'cell 6',
colspan: 2 //this cell will span 2 columns
html:'cell 7'
html:'cell 8'
html:'cell 9'
}]
table.show();
column布局為auto布局的子類,用于設定子元素的寬度。
1. 容器子元素的寬度會随容器寬度而變化;
2. 容器子元素的高度不随容器高度而變化;
1. columnwidth:設定子元素的寬度(值必須為百分數或小于1的小數)
1用作子元素的配置項。
html: '.25',
columnwidth: .25 //means 25%
html: '1/2',
columnwidth: 1/2 //means 50%
var column = ext.create('ext.window.window', {
title: 'column layout',
width: 400,
layout:'column',
items: [panel1, panel2, panel3]
column.show();
fit 布局是容器内隻能顯示一個子元素,若設定多個子元素,則隻顯示第一個子元素。
1. 容器内隻能顯示一個子元素,若設定多個子元素,則隻顯示第一個子元素。
2. 容器子元素随容器大小變化。
var panel1 = ext.create('ext.panel.panel', {
bodystyle: 'padding:15px',
html: 'fit content'
var fit = ext.create('ext.window.window', {
title: 'fit layout',
height: 150,
layout:'fit',
items: [panel1]
fit.show();
card布局是fit布局的子類。
1. 容器内隻能顯示一個子元素,若設定多個子元素,則隻顯示第一個子元素;
3. 容器子元素随容器大小變化。
var card = ext.create('ext.window.window', {
title: 'card layout',
layout: 'card',
activeitem: 0,
bodystyle: 'padding:70 50 0 150',
border:false
bbar: [{
id: 'prevbutton',
text: 'preivous step',
handler: navhandler,
disabled: true
'->',
{
id: 'nextbutton',
text: 'next step',
handler: navhandler
}],
items: [{
html: '<p>step 1 of 3</p>'
html: '<p>step 2 of 3</p>'
html: '<p>step 3 of 3</p>'
card.show();
var navhandler = function(btn) {
var activeitem = card.layout.activeitem;
var active = card.items.indexof(activeitem);
if (btn.id == 'nextbutton') {
active += 1;
else if (btn.id == 'prevbutton') {
active -= 1;
card.layout.setactiveitem(active);
var prev = card.dockeditems.items[1].items.items[0];
var next = card.dockeditems.items[1].items.items[2];
if (active == 0){
prev.setdisabled(true);
} else if (active == 1){
prev.setdisabled(false);
next.setdisabled(false);
} else if (active == 2){
next.setdisabled(true);
}};
border布局将容器分為五個區域:north、south、east、west和center。如下圖:
其中north、south、east、west為選填項,center為必填項。另外我們不用設定center區域的高寬,浏覽器可視工作區的高寬減去north、south、east和west高寬後剩餘的空間便是center區域的高寬。
var border = ext.create('ext.window.window', {
width: 700,
height: 500,
title: 'border layout',
layout: 'border',
defaults:{
xtype: 'panel'
title: 'north region is resizable',
region: 'north',
height: 100,
split: true
title: 'south region is resizable',
region: 'south',
title: 'west region is collapsible',
region:'west',
width: 200,
collapsible: true,
layout: 'fit'
title: 'east region is collapsible',
region:'east',
title: 'center region',
region: 'center',
border.show();
(譯者語:雖然原文中沒有該節内容,但api文檔有ext.layout.container.form類,為了知識的完整性,是以追加該内容)
1. 内部的子元素的寬度為容器body的寬度,并随容器的大小變化而變化;
2. 屬于ext.form.field包下的内部子元素的padding屬性将失效。
component布局負責組織元件内部的html元素。toolbars、headers和表單的fields中均有應用到。(譯者
語:container布局用于組織元件之間的布局關系;component布局負責組織元件内部的html元素或子元件的關系,元件内部由多個部分
(html元素或子元件)組成,extjs4中對于元件中的子元件的組織形式是可定制的,相當靈活。另外雖然可通過元件的componentlayout
配置項配置component布局,但一般情況下我們不應該設定該配置項)
為提高靈活性,extjs4引進新的布局引擎dock布局,主要應用在panel類元件上。該布局已在元件内部設定并用于panel的headers和toolbars中。
下面我們通過将extjs3和extjs4作對比來學習dock布局。
extjs3中設定toolbar如下:
var html = '<div style="padding:10px;"><h1><center><span>body</ center></h1></div>';
var panel1 = new ext.panel({
collapsible:true,
width:400,
renderto: 'ext3-panel',
title: 'ext 3 panel - header',
html: html,
tbar: new ext.toolbar({
type: 'button',
text:'button - top toolbar'
}),
bbar: new ext.toolbar({
text:'button - bottom toolbar'
fbar: new ext.toolbar({
text:'button - footer toolbar'
})
上述代碼片段中我們建立了一個标題為ext 3 panel - header的ext.panel執行個體,其中包含header(标題)和三個toolbar(分别位于ext.panel執行個體的上、下、頁腳的位置),每個toolbar有一個按鈕,結果如下:
下面我們來分析一下extjs3的ext.panel執行個體所生成的代碼,最外層是一個用于封裝整個元件的元素(el),然後是panel自身的header和body的封裝體。在body的封裝體内有是三個toolbar和panel body,具體如下圖:
從上圖我們可以看到extjs3中的panel的header和toolbar在panel内部的位置是固定的,不能作任何改變。
而extjs4的panel元件就不同了,我們先看一下從extjs3遷移到extjs4的執行個體吧:
renderto: 'ext4-panel',
title: 'ext 4 panel - header',
tbar: ext.create('ext.toolbar.toolbar',{
bbar: ext.create('ext.toolbar.toolbar',{
fbar: ext.create('ext.toolbar.toolbar',{
與extjs3的執行個體對比,我們可以發現除了用ext.create代替new來執行個體化對象外,其他均沒有變化。那麼究竟extjs4的header和toolbar有多靈活呢,下面我們看一個完整的例子吧:
border:true,
renderto: 'ext4-panel2',
headerposition: 'top',
dockeditems: [{
xtype: 'toolbar',
dock: 'top',
xtype: 'button',
text: 'button - top toolbar'
dock: 'bottom',
text: 'button - bottom toolbar'
xtype: 'component',
flex: 1 //will occupy 100% of the width of the panel
text: 'button - footer toolbar'
在extjs4中header已經獨立成為panel下的一個子元件了,所屬類為ext.panel.header。我們可以設定header的位置(top、bottom、left和right)
而toolbar也通過dockeditems配置項可以設定到top、bottom、left和right位置,并且同一個位置可以有0到n個toolbar。
下面是上述代碼片段所生成的元素結構圖:
(譯者語:原文中對dock布局講解的其餘部分均為設定headerposition、dockeditems為不同的值時的效果描述,我想大家通過實踐就會得到結論,是以在此就不在翻譯了)
extjs4中的ext.panel.header中包含ext.panel.tool的0到n個執行個體a。而這些ext.panel.tool執行個體就是
通過tool布局來組織其關系。(譯者語:in為在api文檔中沒有發現tool布局,是以本節内容将以介紹ext.panel.tool為主)
ext架構提供25種類型的ext.panel.tool,通過ext.panel.panel的tools配置項來設定ext.panel.tool
執行個體。要注意的一點是,ext架構提供的ext.panel.tool僅包含按鈕圖示而具體的點選事件處理函數需要我們自定義。具體執行個體如下:
width:500,
renderto: 'ext4-panel-tools',
title: 'tools - header',
tools: [{
type: 'close',
handler: function(){} //some logic inside handler
type: 'collapse',
type: 'down',
type: 'expand',
type: 'gear',
type: 'help',
type: 'left',
type: 'maximize',
type: 'minimize',
type: 'minus',
type: 'next',
type: 'pin',
type: 'plus',
type: 'prev',
type: 'print',
type: 'refresh',
itemid: "refresh",
hidden: true,
type: 'restore',
type: 'right',
type: 'save',
type: 'toggle',
type: 'unpin',
type: 'up',
type: "search",
handler: function(event, target, owner, tool){
// do search
owner.child('#refresh').show();
}
(譯者語:原文中指出extjs4中已不支援formlayout,而是通過fieldlayout來替代formlayout。但api中仍然存在
ext.layout.container.form,而且formlayout屬于container布局而fieldlayout屬于
component布局,兩者沒有互斥關系,是以下面的内容以介紹field布局為主,并不讨論它語form布局的關系)
下面我們先來看一下在extjs3中是如何建立含兩個字段的表單吧:
ext.form.field.prototype.msgtarget = 'side';
var simple = new ext.formpanel({
labelwidth: 75,
url:'save-form.php',
frame:true,
title: 'form - ext 3',
bodystyle:'padding:5px 5px 0',
width: 350,
renderto:'ext3-form',
defaults: {width: 230},
defaulttype: 'textfield',
fieldlabel: 'first name',
name: 'first',
allowblank:false
fieldlabel: 'last name',
name: 'last',
],
buttons: [{
text: 'save'
},{
text: 'cancel'
上面的代碼片段中,我們建立了一個寬度為350px的表單,字段的标題寬度為75px,字段輸入框寬度為230px的兩個字段。字段不能為空,若為空則顯示錯誤提示資訊。結果如下:
在extjs3中我們需要為字段預留至少20px的空間來呈現錯誤提示資訊圖示,否則當字段驗證失敗時将無法看到錯誤提示資訊圖示。
下面我們看一下在extjs4中的實作吧:
var simple = ext.create('ext.form.panel', {
title: 'form - ext 4',
renderto:'ext4-form',
fielddefaults: {
msgtarget: 'side',
labelwidth: 75
defaulttype: 'textfield',
defaults: {
anchor: '100%'
text: 'save'
在extjs4上的實作與extjs3的差不多,但我們已經不用為顯示錯誤提示資訊圖示而預留至少20px的空間了,因為當字段驗證失敗時字段将縮短字段框的長度來顯示錯誤提示資訊圖示。效果如下:
除了上述的改進外,現在我們可以為表單配置不同的布局,如hbox:
var hboxform = ext.create('ext.form.panel', {
width: 600,
labelalign: 'top',
msgtarget: 'side'
border: false,
xtype: 'panel',
flex: 1,
layout: 'anchor'
layout: 'hbox',
xtype:'textfield',
anchor: '-10',
}, {
fieldlabel: 'phone number',
name: 'phone',
anchor: '100%',
chapter 3
[ 137 ]
fieldlabel: 'email',
name: 'email',
vtype:'email'
結果如下:
triggerfield布局是field布局的擴充。combox、datepicker等元件都是用triggerfield布局,是以均不用預留至少20px的空間來顯示錯誤提示資訊圖示。
(譯者語:原文餘下的内容為證明上述内容的extjs3和extjs4對比執行個體,在此忽略了)
在本章我們學習了container和component布局。在學習ext的時候我們可能會更關注元件的使用而忽視了布局的學習,但布局是否使用得當往往是影響ui呈現速度的主要因素,是以充分了解布局的内容是十分重要的。