深入浅出ExtJS 第六章 布局
6.1 布局的用途
1 6.1 布局的用途 2 //决定把什么东西放到什么位置; 3 var vieport = new Ext.Viewport({ 4 layout:'border', //使用BorderLayout的布局方式(边界布局);可以自动检测浏览器的大小变化和自动调整布局中每个部分的大小; 5 items:[{ 6 region:'north', //指定组件的具体位置; 7 height:40, 8 html:'<h1>顶部</h1>' 9 },{ 10 region:'west', 11 width:100, 12 html:'<p>左侧区域</p>' 13 },{ 14 region:'center', 15 html:'主要内容' 16 }] 17 }); 18 //Ext的所有布局都是从Ext.Container开始的,Ext.Container的父类是Ext.BoxComponent; 19 //Ext.BoxComponent是一个盒子组件,可以定义宽度/高度和位置等; 20 21 //Ext.Container及其子类 22 >.Ext.Container //Ext.Container的子类都可以用layout对内部的items进行布局; 23 >.Ext.Viewport 24 >.Ext.Panel 25 >.Ext.TabPanel 26 >.Ext.Tip 27 >.Ext.Window 28 >.Ext.form.FieldSet 29 >.Ext.form.FormPanel 30 >.Ext.tree.TreePanel 31 >.Ext.grid.GridPanel 32 >.Ext.grid.EditorGridPanel 33 >.Ext.grid.PropertyGrid 34 35 //所有布局类也有一个共同的超类Ext.layout.ContainerLayout 36 //凡是该超类的子类都可以对Ext.Container及其子类进行布局定义; 37 >.Ext.layout.ContainerLayout //容器布局 38 >.Ext.layout.AnchorLayout //锚点布局 39 >.Ext.layout.AbsoluteLayout //绝对定位布局 40 >.Ext.layout.FormLayout //表单布局 41 >.Ext.layout.BorderLayout //边框布局 42 >.Ext.layout.ColumnLayout //分列布局 43 >.Ext.layout.FitLayout //自适应布局 44 >.Ext.layout.Accordion //折叠布局 45 >.Ext.layout.CardLayout //卡片布局 46 >.Ext.layout.TableLayout //表格布局
6.2 最简单的布局--FitLayout
1 6.2 最简单的布局--FitLayout 2 //自动适应页面大小 3 Ext.onReady(function(){ 4 var store = new Ext.data.ArrayStore({ 5 fields:['id','name','desc'], 6 data:[['1','name1','desc1']] //数据存储器; 7 }); 8 9 var grid = new Ext.grid.GridPanel({ //创建带数据的表格; 10 title:'grid', 11 viewConfig:{forceFit:true}, 12 store:store, 13 columns:[ 14 {header:'id',dataIndex:'id'}, 15 {header:'名称',dataIndex:'name'}, 16 {header:'描述',dataIndex:'desc'} 17 ], 18 tbar:new Ext.Toolbar(['添加','修改','删除']), 19 bbar:new Ext.PagingToolbar({ 20 pageSize:15, 21 store:store 22 }) 23 }); 24 25 var viewport = new Ext.Viewport({ 26 layout:'fit', //指向自适应布局; 27 items:[grid] //将表格引入布局; 28 }); 29 });
6.3 常用的边框布局--BorderLayout
1 6.3 常用的边框布局--BorderLayout 2 //FitLayout每次只能使用一个子组件;而现实中我们使用最多的是Ext.layout.BorderLayout布局; 3 var viewport = new Ext.Viewport({ 4 layout:'border', //指向为BorderLayout布局; 5 items:[ 6 {region:'north',html:'north',height:120}, //region:指定组件的位置;html:组件内容; 7 {region:'south',html:'south',height:30}, 8 {region:'west',html:'west',width:40}, 9 {region:'east',html:'east',width:100}, 10 {region:'center',html:'center'} //center的大小是其他4个部分设置好之后计算出来的;不可以省略; 11 ] 12 }); 13 14 6.3.1 设置子区域的大小 15 //可以直接设置north与south的高度和west与east的宽度; 16 17 6.3.2 使用split并限制它的的范围 18 //使用split参数,用户可以自行拖放来改变某一个区域的大小; 19 //使用minSize和maxSize将限制用户拖放的范围; 20 var viewport = new Ext.Viewport({ 21 layout:'border', 22 items:[ 23 {region:'north',html:'north',split:true}, //顶部可以上下拖动改变大小; 24 {region:'west',html:'west',width:100,split:true,minSize:80,maxSize:120}, 25 //左侧可以左右拖动改变大小; 但宽度的范围在80~120之间; 26 {region:'center',html:'center'} 27 ] 28 }); 29 30 6.3.3 子区域的展开和折叠--collapsible 31 //属性collapsible:true;这个属性激活了区域折叠功能; 32 //title:'west';折叠区域的标题;必须跟collapsible一起设置; 33 items:[ 34 {region:'north',html:'north',heith:100,title:'顶部',collapsible:true}, 35 ... 36 ]
6.4 制作伸缩菜单布局--Accordion(折叠布局)
1 6.4 制作伸缩菜单布局--Accordion(折叠布局) 2 //BorderLayout布局下嵌套的Accordion布局; 3 var viewport = new Ext.Viewport({ 4 layout:'border', //第一层是BorderLayout布局; 5 items:[{ 6 region:'west', //子组件左侧区域; 7 width:200, 8 layout:'accordion', //子组件是Accordion(折叠)布局; 9 split:true, 10 layoutConfig:{ //布局配置信息; 11 titleCollapse:true, //点击标题也可折叠; 12 animate:true, //折叠动画; 13 activeOnTop:false //打开的组件是否置顶; 14 }, 15 items:[{ //孙组件;折叠布局; 16 title:'第一栏', 17 html:'第一栏' 18 },{ 19 title:'第二栏', 20 html:'第二栏' 21 }] 22 },{ 23 region:'center', //子组件center区域; 24 html:'center区域' 25 }] 26 });
6.5 实现操作向导的布局--CardLayout
1 6.5 实现操作向导的布局--CardLayout 2 //为CardLayout配置几个子面板,每次只显示其中一个; 3 var viewport = new Ext.Viewport({ 4 layout:'border', 5 items:[{ 6 region:'west', 7 id:'wizard', 8 width:200, 9 title:'xx向导', 10 layout:'card', 11 activeItem:0, 12 bodyStyle:'padding:15px', 13 defaults:{ 14 border:false 15 }, 16 bbar:[{ 17 id:'move-prev', 18 text:'上一步', 19 handler:function(){ 20 navHandler(-1); 21 }, 22 disabled:true 23 },'->',{ 24 id:'move-next', 25 text:'下一步', 26 handler:function(){ 27 navHandler(1); 28 }, 29 }], 30 items:[{ 31 id:'card-0', 32 html:'<h1>欢迎使用向导</h1><p>1/3</p>' 33 },{ 34 id:'card-1', 35 html:'<p>2/3</p>' 36 },{ 37 id:'card-2', 38 html:'<p>完成</p>' 39 }] 40 },{ 41 region:'center', 42 split:true, 43 border:true 44 }] 45 }); 46 //设置navHandler函数 (带注释!) 47 var navHandler = function(direction){ 48 var wizard = Ext.getCmp('wizard').layout; 49 var prev = Ext.getCmp('move-prev'); 50 var next = Ext.getCmp('move-next'); 51 var activedId = wizard.activeItem.id; 52 if(activeId == 'card-0'){ 53 if(direction == 1){ 54 wizard.setActiveItem(1); 55 prev.setDisabled(false); 56 } 57 }else if(activeId == 'card-1'){ 58 if(direction == -1){ 59 wizard.setActiveItem(0); 60 prev.setDisabled(true); 61 }else{ 62 wizard.setActiveItem(2); 63 next.setDisabled(true); 64 } 65 }else if(activeId == 'card-2'){ 66 if(direction == -1){ 67 wizard.setActiveItem(1); 68 next.setDisabled(false); 69 } 70 } 71 };
6.6 控制位置和大小的布局--AnchorLayout和AbsolluteLayout
1 6.6 控制位置和大小的布局--AnchorLayout和AbsolluteLayout 2 //AnchorLayout提供了灵活的布局方式,既可以为items中的每个组件指定与总体布局大小的差值;也可以设置一个比例使子组件可以根据整体自行计算本身的大小; 3 >1.使用百分比进行配置 4 //设置某一个子组件占整体长和宽的百分比; 5 var viewport = new Ext.Viewport({ 6 layout:'anchor', //设置接下来的子组件都为AnchorLayout布局; 7 items:[{ 8 title:'panel1', 9 html:'panel1', 10 anchor:'50% 50%' //panel1组件占总体宽度的50%和高度的50%; 11 },{ 12 title:'panel2', 13 html:'panel2', 14 anchor:'80%' //panel2组件占总体宽度的80%,高度自适应; 15 }] 16 }); 17 >2.设置与右侧和底部的边距; 18 var viewport = new Ext.Viewport({ 19 layout:'anchor', 20 items:[{ 21 title:'panel1', 22 html:'panel1', 23 anchor:'-50 -200' //组件与右侧和底部的相对(绝对)距离; 24 },{ 25 title:'panel2', 26 html:'panel2', 27 anchor:'-100' //组件与右侧的距离; 28 }] 29 }); 30 >3.side布局; 31 //在设置父组件和布局内部子组件都设置好width/height和anchorSize属性的前提下;AnchorLayout会记录布局整体与子组件在大小上的差值,为以后调整布局提供依据; 32 var viewport = new Ext.Viewport({ 33 layout:'anchor', 34 anchorSize:{width:400,height:300}, 35 //这是一个包含宽度和高度信息的JSON对象;以此作为以后计算差值的基准; 36 items:[{ 37 title:'panel1', 38 html:'panel1', 39 width:200, 40 height:100, 41 anchor:'r b' 42 },{ 43 title:'panel2', 44 html:'panel2', 45 width:100, 46 height:200, 47 anchor:'r b' 48 }] 49 }); 50 //AnchorLayout首先获得父组件的宽度/高度,以及每个子组件的宽度/高度,然后将子组件与父组件的宽度/高度之差分别保存起来;根据改变后父组件的大小,计算出子组件当前的宽度和高度; 51 >4.同时使用百分比和边距 52 var viewport = new Ext.Viewport({ 53 layout:'anchor', 54 items:[{ 55 title:'panel1', 56 html:'panel1', 57 anchor:'-100 40%' //组件距右侧100px不变,高度是整体的40%; 58 },{ 59 title:'panel2', 60 html:'panel2', 61 anchor:'-200 60%' //同上; 62 }] 63 }); 64 >5.利用AbsoluteLayout进行绝对定位 65 //AbsoluteLayout是AnchorLayout的一个子类;继承了AnchorLayout的所有特性; 66 //AnchorLayout布局下的子组件都是自上而下竖直排列的;而AbsoluteLayout正是可以解决这个问题; 67 var viewport = new Ext.Viewport({ 68 layout:'absolute', 69 //以下组件进行绝对定位;并使用AnchorLayout确定每个组件的相对大小; 70 items:[{ 71 title:'panel1', 72 html:'panel1', 73 x:50, //子组件左上角距父组件的距离; 74 y:0, 75 anchor:'-200 40%' //子组件相对于父组件的大小; 76 }] 77 });
6.7 表单专用的布局--FormLayout
1 6.7 表单专用的布局--FormLayout 2 var viewport = new Ext.Viewport({ 3 layout:'fit', //组件自适应填满布局; 4 items:[{ 5 xtype:'form', 6 title:'信息', 7 labelAlign:'right', //控件标签右对齐; 8 labelWidth:50, //控件宽度; 9 frame:true, //圆角; 10 defaultType:'textfield',//以下组件为文本框控件; 11 items:[{ 12 fieldLabel:'名称', 13 name:'name', 14 anchor:'90%' //占整体90%的空间; 15 },{ 16 fieldLabel:'生日', 17 name:'birthday', 18 xtype:'datefield', //日期控件; 19 anchor:'90%' 20 },{ 21 fieldLabel:'备注', 22 name:'desc', 23 xtype:'textarea', //多行文本控件; 24 anchor:'90% -100' //占整体90%;并且距离底部100px; 25 }] 26 }] 27 });
6.8 分列布局--ColumnLayout
1 6.8 分列布局--ColumnLayout 2 //ColumnLayout是将整个容器进行竖直切分的布局方式; 3 >1.使用ColumnLayout实现简单布局 4 var viewport = new Ext.Viewport({ 5 layout:'column', //分列布局; 6 items:[{ 7 title:'Column1', 8 columnWidth:.25 9 },{ 10 title:'Column2', 11 columnWidth:.4 12 },{ 13 title:'Column3', 14 columnWidth:.35 15 }] 16 }); 17 >2.使用columnWidth平分剩余的宽度 18 var view = new Ext.Viewport({ 19 layout:'column', 20 items:[{ 21 title:'1', 22 width:20 //组件一宽度不变; 23 },{ 24 title:'2', 25 columnWidth:.7 //宽度为剩下的70%; 26 },{ 27 title:'3', 28 columnWidth:.3 29 }] 30 });
6.9 表格状布局--TableLayout
1 6.9 表格状布局--TableLayout 2 var view = new Ext.Viewport({ 3 layout:'fit', 4 items:[{ 5 title:'Table Layout', 6 layout:'table', //表格布局; 7 default:{ 8 bodyStyle:'padding:20px' 9 }, 10 layoutConfig:{ 11 columns:3 12 }, 13 items:[{ 14 html:'<p>A</p>', 15 rowspan:2 //合并的行数; 16 },{ 17 html:'<p>B</p>', 18 colspan:2 //合并的列数; 19 },{ 20 html:'<p>C</p>', 21 cellId:'haha' //设置单元格ID; 22 },{ 23 html:'<p>D</p>' 24 }] 25 }] 26 });
6.10 BoxLayout--HBox
1 6.10 BoxLayout--HBox 2 //横排一行多个组件; 3 var panel = new Ext.Panel({ 4 title:'HBox', 5 width:400, 6 height:200, 7 renderTo:'grid', 8 layout:{ 9 type:'hbox', //指定当前的Panel使用HBox布局方式; 10 padding:'5', 11 align:'stretch' //为组件设置统一的对齐方式;自动充满外部容器的大小; 12 }, 13 defaults:{margins:'0 0 5 0 '}, 14 items:[{ 15 xtype:'button', //按钮组件; 16 text:'Button1', 17 flex:1 18 },{ 19 xtype:'button', 20 text:'Button2', 21 flex:3 //值越大,对应的组件占据的空间越大; 22 }] 23 });
6.11 BoxLayout--VBox
1 6.11 BoxLayout--VBox 2 //竖排一列多个组件; 3 var panel = new Ext.Panel({ 4 .. 5 layout:{ 6 type:'vbox', //指定当前的Panel使用HBox布局方式; 7 padding:'5', 8 align:'stretch' 9 }, 10 items:[...] 11 });
6.12 Ext.TabPanel
1 6.12 Ext.TabPanel 2 //Tab布局组件 3 >1.普通Tab 4 var tabs = new Ext.TabPanel({ //创建TabPanel对象; 5 renderTo:document.body, //渲染到指定位置; 6 height:100 7 }); 8 //任意组件直接使用add()函数便可添加到Ext.TabPanel中; 9 tabs.add({ //若不特别指定xtype,就会默认使用Ext.Panel为这些内容生成子面板; 10 id:Ext.id(), //使用Ext.id()函数生成唯一的id值; 11 title:'标题2', 12 html:'内容2', 13 closable:true //生成的标签受否可以手动关闭; 14 }); 15 tabs.activate(0); //让指定的标签变成激活状态;参数是标签的索引值; 16 17 >2.添加创建的Tab按钮 18 //添加两个按钮,用于新建包含表格的标签和包含Panel的标签 19 var tabs = new Ext.TabPanel({ 20 height:200, 21 renderTo:'tab', 22 enableTabScroll:true 23 }); 24 tabs.add({ 25 title:'标题一', 26 html:'内容一', 27 closable:true 28 }); 29 tabs.setActiveTab(0); 30 31 var addGrid = new Ext.Button({ //创建按钮; 32 text:'添加一个grid', 33 renderTo:'add-grid', 34 handler:function(){ //"新建"按钮回调函数; 35 var id = Ext.id(); 36 //创建表格↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 37 var grid = new Ext.grid.GridPanel({ 38 store:new Ext.data.SimpleStore({ 39 fields:['id','name'], 40 data:[ 41 ['1','name1'], 42 ['2','name2'], 43 ] 44 }), 45 columns:[ 46 {header:'序号',dataIndex:'id'}, 47 {header:'名称',dataIndex:'name'} 48 ] 49 }); 50 //将表格组件放入到tabs里↓↓↓↓ 51 var tab = tabs.add({ 52 title:'表格'+id, 53 closable:true, 54 layout:'fit', 55 items:[grid] 56 }); 57 //激活当前的tab标签↓↓↓↓ 58 tabs.setActiveTab(tab); 59 } 60 }); 61 62 var addPanel = new Ext.Button({ 63 text:'添加一个panel', 64 renderTo:'add-panel', 65 handler:function(){ 66 var id = Ext.id(); 67 var panel = new Ext.Panel({ //创建Panel标签; 68 html:'创建Panel标签成功' 69 }); 70 var tab2 = tabs.add({ 71 title:'Panel'+id, 72 closable:true, 73 layout:'fit', 74 items:[panel] 75 }); 76 tabs.setActiveTab(tab2); 77 } 78 }); 79 80 >3.执行从后台得到的HTML(包含JS脚本) 81 tabs.add({ 82 title:'从后台获取内容', 83 autoLoad:{url:'xxx.html',scripts:true} 84 //autoLoad:创建后自动执行;默认是延迟加载的; 85 //scripts:执行得到的HTML里的脚本; 86 }) 87 88 6.12.1 标签面板的滚动菜单 89 //TabPanel的组件,可以在标签过多的时候显示一个下拉菜单; 90 //需引入tabs下的TabScrollMenu.js和TabScrollMenu.css; 91 var scrollerMenu = new Ext.ux.TabScrollerMenu({ 92 maxText:15, 93 pageSize:5 94 }); 95 var tabs = new Ext.TabPanel({ 96 width:400, 97 height:200, 98 activeTab:0, 99 enableTabScroll:true, 100 resizeTabs:true, 101 minTabWidth:75, 102 frame:true, 103 plugins:[srcrooerMenu], //标签过多时显示下拉菜单; 104 items:[{title:'第一个tab'}], 105 renderTo:'tabs' 106 });
6.13 与布局相关的知识
1 6.13 与布局相关的知识 2 6.13.1 超类Ext.Container的公共配置与xtype的概念 3 >1.Ext.Container是所有可布局组件的超类;只要继承它的子类都可以对自身进行布局; 4 >2.主要参数: 5 >.layout(组件布局方式); 6 >.items(包含的子组件); 7 >3.与上面对应的还有两个参数: 8 >.layoutConfig:为布局提供特定的配置参数; 9 //在实例化过程中当前类会把自身的layoutConfig参数赋予layout对象并进行配置; 10 >.activeItem:表示当前显示哪一个子组件; 11 4.defaultType参数 12 >.当子组件没有指定xtype参数时,就会使用上级组建中设置的defaultType来作为自身的xtype; 13 //默认情况下是defaultType:'panel',也就是在items中创建的每个子组件都是Ext.Panel的实例; 14 //若需要其他类型的组件,直接替换成对应的类型的值即可; 15 5.xtype 16 //在Ext中,xtype:'grid'和new Ext.grid.GridPanel()是等价的; 17 items:[{ 18 xtype:'grid', 19 store:store, 20 columns:columns 21 }] 22 //整体布局时,使用xtype更方便,结构也更清晰; 23 items:[new Ext.grid.GridPanel({ 24 store:store, 25 columns:columns 26 })] 27 //创建实例的方式更适用于需要对某一部分进行详细配置的情况; 28 29 6.13.2 layout的超类Ext.layout.ContainerLayout 30 //当layout:'auto'时,就表示将使用Ext.layout.ContainerLayout的布局; 31 32 6.13.3 不指定任何布局时会发生的情况 33 >.组件默认使用的布局类型 34 Ext.Container Ext.layout.ContainerLayout 35 Ext.Viewport Ext.layout.ContainerLayout 36 Ext.Panel Ext.layout.ContainerLayout 37 Ext.TabPanel Ext.layout.CardLayout 38 Ext.Tip Ext.layout.ContainerLayout 39 Ext.Window Ext.layout.ContainerLayout 40 Ext.form.FieldSet Ext.layout.FormPanel 41 Ext.form.FormPanel Ext.layout.FormPanel 42 Ext.tree.TreePanel Ext.layout.ContainerLayout 43 Ext.grid.GridPanel Ext.layout.ContainerLayout 44 Ext.grid.EditorGridPanel Ext.layout.ContainerLayout 45 Ext.grid.PropertyPanel Ext.layout.ContainerLayout 46 47 6.13.4 使用Viewport对整个页面进行布局 48 //以上示例中,都是用Ext.Viewport对整个页面进行统一布局; 49 //实际上,Viewport只是一个用于整页布局的快捷工具类; 50 //多个Viewport之间会冲突; 51 52 6.13.5 使用嵌套实现复杂布局 53 Ext.onReady(function(){ 54 55 //表格配置 56 var columns = [ 57 {header:'编号',dataIndex:'id'}, 58 {header:'名称',dataIndex:'name'}, 59 {header:'描述',dataIndex:'descn'} 60 ]; 61 var data = [ 62 ['1','name1','descn1'], 63 ['2','name2','descn2'] 64 ]; 65 var store = new Ext.data.ArrayStore({ 66 data:data, 67 fields:[ 68 {name:'id'}, 69 {name:'name'}, 70 {name:'descn'} 71 ] 72 }); 73 store.load(); 74 var grid = new Ext.grid.GridPanel({ 75 store:store, 76 columns:columns, 77 title:'center-north', 78 region:'north' //此表格会在Panel布局的上方; 79 }); 80 81 //树形配置 82 var tree = new Ext.tree.TreePanel({ 83 store:new Ext.data.TreeStore({ 84 proxy:{ 85 type:'ajax', 86 url:'xxx.html' 87 }, 88 root:{ 89 expand:true, 90 text:'我是根' 91 } 92 }), 93 title:'west', 94 region:'west', //此树形组件会在Panel布局的左侧; 95 split:true, 96 border:true, 97 collapsible:true, 98 width:120, 99 minSize:80, 100 maxSize:200 101 }); 102 103 //表单配置 104 var form = new Ext.form.FormPanel({ 105 defaultType:'textfield', 106 labelAlign:'right', 107 title:'form', 108 labelWidth:50, 109 frame:true, 110 width:220, 111 title:'center-center', 112 region:'center', //此表单组件会在Panel布局的中间; 113 items:[{ 114 fieldLabel:'文本框', 115 anchor:'90%' 116 }], 117 button:[{ 118 text:'按钮' 119 }] 120 }); 121 122 //布局开始 123 var viewport = new Ext.Viewport({ 124 layout:'border', 125 items:[{ 126 region:'north', 127 contentEl:'north-div', //上布局为id='north-div'的DIV;通过contentEl来指定HTML中显示的内容; 128 heith:80, 129 bodyStyle:'background-color:#BBCCEE;' 130 },{ 131 region:'south', //下布局为id='south-div'的DIV 132 contentEl:'south-div', 133 height:20, 134 bodyStyle:'background-color:#BBCCEE;' 135 },tree,{ //左侧布局;树形; 136 region:'center', //中间布局; 137 split:true, 138 border:true, 139 layout:'border', //中间区域使用边界布局; 140 items:[gird,form] //将准备好的表格和表单引入中间布局区域; 141 }] 142 }); 143 }); 144 <div id='north-div'>标题栏:viewport加panel实现复杂布局</div> 145 <div id='south-div'>状态栏:Copyright by www.xxx.com</div> 146 147 //这个Viewport中的每个子组件都是Panel类型;而Panel包含:TreePanel/GridPanel/FormPanel 148 //所以Panel的配置参数它们也都可以用; 149 //在任何一个Panel里设置layout:'border',就可以将它再次分成5各区域;并用region参数指定各自所在位置; 150 Viewport Panel 151 north:north-div; 152 south:south-div; 153 west:tree; 154 center:Panel; 155 north:grid; 156 center:form;