核心概念
在下一章我们会构建一个示例项目,而在这之前,你需要学习一些在 Ext JS 中的核心概念,这有助于你更容易理解示例项目。这一章我们将学习以下知识点:
- 类系统,创建和扩展类
- 事件
- Ext JS 对象的查询
- 容器
- 布局
class system(类系统)
Ext JS 提供了很多功能,使得它创建和处理类变得简单。以下是在 Ext JS 6 的类系统中的几大组成类:
- Ext
- Base
- Class
- ClassManager
- Loader
Ext 类
Ext 是一个全局单例的对象,在 Sencha library 中它封装了所有的类和许多实用的方法。许多常用的函数都定义在 Ext 对象里。它还提供了像其他类中一些频繁使用的方法的快速调用。
我们看一下在 Ext 类中定义的方法和属性:
application 方法
这里应用是用 Ext.application 方法初始化的。这个方法的参数是一个 Ext.app.Application 对象,这个方法会加载 Ext.app.Application 类,并在页面加载完成后开始应用给定的配置。
Ext.app.Application 这个类代表我们的整个应用,这在第1章(入门指南)讲过,讲过的吧?是吧?下面是 Ext.app.Application 的使用例子:
1
2
3
4
5
6
7
|
Ext.application({
name: 'MyApp',
extend:'MyApp.Application',
launch: function() {
}
}) ;
|
上面代码创建一个名为 MyApp 的全局变量。我们的应用里所有的类都将归属于在这样一个命名空间下面。这将降低全局变量产生冲突的可能。
define 方法
你可以用这个方法定义或者重写一个类。 这个方法有三个参数,如以下代码所示。 在这里 name 参数是你要定义的类名,data 参数是应用于这个类的属性,callback 是可选参数,这个函数将会在这个类被创建后调用:
1
|
Ext.define(name,data, callback)
|
下列代码创建一个名为 Car 的类:
1
2
3
4
5
6
7
8
9
10
11
|
Ext.define('Car', {
name: null,
constructor: function(name) {
if (name) {
this.name = name;
}
},
start: function() {
alert('Car started');
}
}) ;
|
你还可以使用 define 继承扩展一个类:
1
2
3
4
5
6
|
Ext.define('ElectricCar', {
extend: 'Car',
start: function() {
alert("Electric car started");
}
}) ;
|
如果你想替换一个父类方法的实现,你可以使用 Ext.define 来重写这个方法,如以下代码所示:
1
2
3
4
5
6
7
|
Ext.define('My.ux.field.Text', {
override: 'Ext.form.field.Text',
setValue: function(val) {
this.callParent(['In override']);
return this;
}
});
|
细心的同学可能发现了当我们继承和重写时使用的属性是不同的,继承我们使用 extend 而重写使用 override ,这两者之间有什么区别呢?你一定感到疑惑,这里我非常有必要给你解释清楚,听我慢慢道来。
首先说继承并扩展一个类,这等同于是一个新的类,仍然可以在这个新的类里增加自己独有的方法和属性或者重写父类的方法。
1
2
3
4
5
6
7
8
|
Ext.define('MyApp.view.main.Test', {
extend: 'Ext.grid.Panel',
xtype: 'maintest',
title: 'Personnel',
say:function(){
alert(123);
}
});
|
这里我继承了 gridpanel 类,并增加了一个 say方法,以下是输出调用 say 方法的运行结果。
这应该很好理解,Test 继承了 grid panel 之后是一个新的类了,而这里如果创建 Ext.grid.Panel 对象是调用不了 say 方法的。
那么现在我把 extend 改为 override 我们再看一下:
1
2
3
4
5
6
7
8
|
Ext.define('MyApp.view.main.Test', {
override: 'Ext.grid.Panel',//改为 override 了
xtype: 'maintest',
title: 'Personnel',
say:function(){
alert(123);
}
});
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
name: 'MyApp',
requires: [
'MyApp.view.main.Main',
'MyApp.view.main.Test'//我这里引入了 Test
],
stores: [
// TODO: add global / shared stores here
],
launch: function () {
var test = Ext.create("MyApp.view.main.Test",{
title: 'Personnel'
});
test.say();
},
onAppUpdate: function () {
Ext.Msg.confirm('Application Update', 'This application has an update, reload?',
function (choice) {
if (choice === 'yes') {
window.location.reload();
}
}
);
}
});
|
运行结果:
我们可以看到我只是简单的把 extend 替换成 override 就报错说不能识别的类名。但是上面我也是引入了它的引用的(requires),可见 extend 和 override 还是有区别的,我们不是重写(override)的是 grid panel 吗?那我们试试创建一个 Ext.grid.Panel 对象试试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
name: 'MyApp',
requires: [
'MyApp.view.main.Main',
'MyApp.view.main.Test'
],
stores: [
// TODO: add global / shared stores here
],
launch: function () {
//这里改成了 grid panel
var test = Ext.create("Ext.grid.Panel",{
title: 'Personnel'
});
test.say();
},
onAppUpdate: function () {
Ext.Msg.confirm('Application Update', 'This application has an update, reload?',
function (choice) {
if (choice === 'yes') {
window.location.reload();
}
}
);
}
});
|
再次运行结果:
这次正常了,我们使用 Ext.define 定义的类,使用了 override 重写组件,发现并不能新建我们定义的类,而是被重写的父类被新增了 say 方法。
所以总结一下,extend 会创建一个新的类,并继承父类的属性和方法,你也可以重写父类的方法。而 override 并不会创建一个新的类,而是修改这个被重写的父类。
- 注意:例如上面的例子,Test 重写了 grid panel,我在其他类中创建 grid panel 时如果不引用 Test 那么重写仍然是不生效的。只有引用了 Test 重写才会生效 grid panel 才会具有 say 方法。不要问我为什么。
如果你想创建一个单例类,那么你在定义类时用 singleton 属性,如以下代码所示:
1
2
3
4
5
6
|
Ext.define('Logger', {
singleton: true,
log: function(msg) {
console.log(msg);
}
}) ;
|
create 对象
你可以使用下列代码来创建一个类的实例:
1
|
Ext.create(Class,Options);
|
下列代码创建了一个 ElectricCar 类的实例,并传递一个值(name):
1
|
var myCar = Ext.create('ElectricCar',{ name: 'MyElectricCar' }) ;
|
如果 Ext.Loader 是开启的,Ext.create 执行时如果 ElectricCar 类不存在将会自动的下载对应的 JS 文件。默认 Ext.Loader 是开启的;你可以通过以下方式来关闭它。
1
2
3
|
Ext.Loader.setConfig({
enabled: true
});
|
这里你也可以使用 new 关键字来创建一个实例,如以下代码所示;可是如果这个类不存在,使用 new 关键字创建实例并不会自动下载对应的 JS 文件:
1
|
var myCar = new ElectricCar('MyElectricCar');
|
- ps:你只需要掌握使用 Ext.create 创建实例就行了,new 关键字可能是兼容 Ext 3.x 的使用方式而继续支持的。new 关键字官方是不推荐用的。
onReady
这个函数在页面加载完成后调用:
1
2
3
4
5
6
|
Ext.onReady(function(){
new Ext.Component({
renderTo: document.body,
html: 'DOM ready!'
});
}) ;
|
大多时候,在你的代码里不会用到 onReady 这个方法,因为 Ext 建议你一个应用就是一个页面(单页式应用),只有一个页面的话自然没有那么多场景会需要用到。只有在极少数的一些特殊情况,你可能需要用它。这里要强调一点,如果你具有使用 jQuery 的基础,不要把 onReady 方法像 jQuery 中的 $( document ).ready() 那样频繁使用。
widget (部件)
当定义一个类时,你可以为这个类增加一个便于记忆的别名。例如: Ext.panel.Panel 的别名为 widget.panel 。定义别名时,如以下代码所示指定 alias属性:
1
2
3
4
|
Ext.define('Ext.panel.Panel', {
extend: 'Ext.container.Container',
alias: 'widget.panel'//这里是定义的别名,
});
|
你也可以使用 xtype 为这个类给定一个别名。这个 xtype 是非常有用的,当你以指定 xtype 的方式应用部件时,并不会创建实例,而是在真正调用展示的时候才会创建这个类的实例。在本章后面介绍 容器和布局 时你将会学到更多关于 xtype 的使用。
Ext.widget 方法是通过类的 xtype 快速创建部件的。
例如,不使用 widget 方法,你可以通过下列代码创建 Ext.panel.Panel 的实例:
1
2
3
4
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
title: 'Panel'
});
|
反之,通过以下方式快速创建 panel 的实例:
1
2
3
4
|
Ext.widget('panel', {
renderTo: Ext.getBody(),
title: 'Panel'
});
|
这里 panel 是一个容器,关于 panel 会在后面详细讲解。下面代码的作用相当于与上面:
1
2
3
4
|
Ext.create('widget.panel', {
renderTo: Ext.getBody(),
title: 'Panel'
});
|
注意: 你阅读此文档的同时,这里面的大部分代码都是可以运行的,你可以选择在你本地设备上或者在 Sencha Fiddle 上执行这些示例代码。你可以访问Sencha Fiddle 并将上面的代码键入到 launch 函数中,运行并查看结果。如果你访问了 https://fiddle.sencha.com 将会看到下列代码:
1
2
3
4
5
6
|
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.Msg.alert('Fiddle', 'Welcome to Sencha Fiddle!');
}
}) ;
|
现在,粘贴创建 panel 部件的代码如以下示例,运行并查看结果。复制粘贴时,注意单引号不要写成中文标点单引号:
1
2
3
4
5
6
7
8
9
|
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('widget.panel', {
renderTo: Ext.getBody(),
title: 'Panel'
});
}
}) ;
|
- 不是所有的代码都可以这样运行,此外并非所有的示例代码都会有视觉呈现。
getClass
如果创建的实例是用 Ext.define 定义的,那么返回这个给定对象的类,否则返回 null:
1
2
|
var button = new Ext.Button();
Ext.getClass(button); // returns Ext.Button
|
getClassName
通过它的引用或实例返回类名称:
1
|
Ext.getClassName(Ext.Button); //returns "Ext.Button"
|
Ext.Base
这是所有 Ext 类的基础。所有的 Ext 类都继承自 Ext.Base。该类所有的原型和静态成员都会传递给继承它的类。
Ext.Class
这是一个低级别的工厂类,用于通过 Ext.ClassManager 定义一个类。所以不应该在你的代码中直接访问;你应该使用 Ext.define。
Ext.ClassManager
它管理所有的类同时处理类反射。通常通过下面几个方法访问:
- define
- create
- widget
- getClass
- getClassName
在本章我们已经讨论使用过这些方法。
Ext.Loader
用于动态的加载依赖。通常使用 Ext.require 来指定依赖。当你定义一个类时,这样指定组件的依赖列表是一个很好的做法,如以下代码所示:
1
|
Ext.require(['widget.window', 'layout.border','Ext.data.Connection']);
|
如果你需要引入一个指定命名空间下所有的 组件/类 时,使用通配符,如以下代码所示:
1
|
Ext.require(['widget.*', 'layout.*', 'Ext.data.*');
|
使用以下语法排除掉不需要的类:
1
|
Ext.exclude('Ext.data.*').require('*');
|
用这种方式,依赖的类是异步加载的。如果在你定义的类中没有指定依赖的类,那么当使用 Ext.Create 创建实例时,如果它是未加载的,这时将会同步加载这些类文件。这对性能有一定的影响,所以当你定义类时,使用 Ext.require 指定所需的类总是更好的。
- requires 属性加载需要的类时,当前类初始化之前被加载。
- uses 属性加载需要的类时,当前类初始化之后被加载。
singleton:true 属性当前类初始化时,该实例是一个单例对象。
注意:定位类的文件路径是基于类名的。例如:MyApp.view.About 类的路径应该是 myappview about.js 。
Events(事件)
一个事件可以是一个用户操作,一个 Ajax 调用的响应等等。
Adding listeners(为类添加监听)
当你创建对象或者创建以后都可以为这个对象添加监听器。下列示例代码为这个对象添加了一个 单击事件 的监听:
1
2
3
4
5
6
7
8
|
Ext.create('Ext.Button', {
renderTo: Ext.getBody(),
listeners: {
click: function() {
Ext.Msg.alert('Button clicked!');
}
}
}) ;
|
你可以添加多个事件监听,如以下代码示例:
1
2
3
4
5
6
7
8
9
10
11
|
Ext.create('Ext.Button', {
renderTo: Ext.getBody(),
listeners: {
mouseout: function() {
//Do something
},
click: function() {
// Do something
}
}
});
|
你也可以在对象创建之后,使用 on 方法为对象添加事件监听:
1
2
3
4
|
var button = Ext.create('Ext.Button');
button.on('click', function() {
//Do something
}) ;
|
同样的,你也可以使用 on 方法一次添加多个事件的监听,如以下代码示例:
1
2
3
4
5
6
7
8
9
|
var button = Ext.create('Ext.Button');
button.on({
mouseover: function() {
//Do something
},
mouseover: function() {
//Do something
}
}) ;
|
Removing listeners (删除事件监听)
You can also remove the listeners, but you need the reference to the function; you can’t use the anonymous function.
1
2
3
4
5
6
7
8
9
10
11
|
var HandleClick= function() {
Ext.Msg.alert('My button clicked!');
}
Ext.create('Ext.Button', {
listeners: {
click: HandleClick
}
}) ;
button.un('click', HandleClick);
|
页面 DOM 元素的事件处理
你可以将监听器添加到 DOM 元素,如下所示。
假设在你的 HTML 代码中,有一个 div 元素 id=mydiv ,如以下代码所示:
1
|
< div id="mydiv"></div >
|
用下列代码为它添加事件监听:
1
2
3
4
|
var div = Ext.get('mydiv');
div.on('click', function(e, t, eOpts) {
// Do something
});
|
访问 DOM
有三种方法来访问 DOM 元素:get,query,和 select 。
Ext.get
get 方法是根据这个 DOM 元素的 ID 检索获取并封装为 Ext.dom.Element 对象:
1
|
var mydiv = Ext.get('myDivId');
|
Ext.query
这种方式基于传入的 CSS 选择器 从给定的根节点开始查找。它返回一个匹配选择器的元素(HTMLElement[]/Ext.dom.Element[])数组。如果没有匹配的,返回一个空值的数组对象。
在下面示例中,myCustomComponent.getEl().dom 是传递的根节点。Ext.query 将检索这个节点内的子元素,并返回一个数组包含 CSS class 为 ‘oddRow‘ 的的元素:
1
|
var someNodes = Ext.query('.oddRow', myCustomComponent.getEl().dom);
|
Ext.select
给出一些 CSS/XPath 选择器,Ext.select 方法返回一个 CompositeElement 类型的对象,代表一个元素的集合。
这个 CompositeElement 对象可以进行过滤,迭代,和对整个集合执行整体操作等等:
1
2
|
var rows = Ext.select('div.row'); ////Matches all divs with class
row rows.setWidth(100); // 这是设置所有元素的宽度为 100
|
你也可以用一行代码,如下所示:
1
|
Ext.select('div.row').setWidth(100);
|
多重选择器
在方法调用时通过指定多个搜索条件可以用来匹配多个元素:
1
|
Ext.select('div.row, span.title'); //匹配所有的 class 用 .row 的 div 元素,和匹配所有 class 用 .title 的 span 元素
|
选择器 根
当你使用 select ,它默认取 HTML body 作为根并从默认的 body 开始检索整个 DOM 树。你可以通过制定一个根元素来避免这种情况,这样它将只搜索给定的根的子节点。
1
|
Ext.get('myEl').select('div.row');
|
这儿使用了 ‘myEl’ 作为根节点。这将首先找到 id 为 ‘myEl’ 的元素,然后将在根元素(myEl)下面搜索出 class 为 ‘row’ 的 div 标签。
1
|
Ext.select('div.row', true, 'myEl');// This is equivalent to the previous line.
|
链式选择器
下列的查询方式会匹配 class 为 row 并且 title 属性值为 bar 的 div ,这个 div 属于其父元素的首个子元素:
1
|
Ext.select('div.row[title=bar]:first')
|
Ext.ComponentQuery
这允许你用 ID,xtype,和 属性查找一个组件。你可以全局搜索或者指定一个根组件。
下列查询将返回所有的 xtype 为 button 的组件:
1
|
Ext.ComponentQuery.query('button');
|
得到一个 id 为 foo 的组件,用以下代码:
1
|
Ext.ComponentQuery.query('#foo');
|
下列代码将返回所有的 xtype 为 button 并且 title 属性值为 my button 的组件:
1
|
Ext.ComponentQuery.query("button[title='my button']");; //or parent.query('textfield[title=my button]');
|
你也可以使用嵌套选择器如下:You can also use nested selectors as follows:
1
|
Ext.ComponentQuery.query('formpanel numberfield'); // 这里获取 xtype 为 frompanel 下面的 xtype 为 numberfield 的组件
|
下列代码返回这个 parent 容器内匹配传递进来的选择器的第一个直接子组件,如果没有匹配上,返回 null 。
1
|
parent.child('button[itemId=save]');
|
同样的,你也可以使用其他的方法,例如 nextNode, up, down, previousSibling 等等。
组件,容器,和布局
Ext JS 提供了一组丰富的组件和布局,这使在 Ext JS 中开发 UI 变得超级简单,甚至非专业 UI 开发人员也能够轻易的使用。
组件
从简单的组件说起,例如 button 和 label ,到复杂的组件,例如 Tree Panel,Grids 等等,Ext JS 有大量的内置组件。所有的组件都派生自Ext.Component 类,它提供支持创建,重绘,渲染和处理组件。
所有的组件都有一个属性叫做 xtype 。它是非常有用的,它用在当你不想马上实例化这个组件时,而是想让这个组件在实际被应用时才创建,就是我们俗称的懒加载。
容器
容器是一个特殊的组件类型,它能够持有其他组件。在 Ext JS 中 Ext.container.Container 类是所有的容器的基础类。
Ext.toolbar.Toolbar, Ext.panel.Panel, 和 Ext.Editor 是一些内置组件。这些组件都是可以包含其他组件。而像 Ext.button.Button 类就不是派生自Ext.container.Container ,所以它不能够包含其他组件。
一个典型的 Ext JS 应用包含一组嵌套的组件。看下面这个例子并思考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
Ext.create('Ext.panel.Panel', {
renderTo:Ext.getBody(),
width:700,
height:400,
items:[{
xtype: 'panel',
title: 'Panel 1',
},{
xtype: 'panel',
title: 'Panel 2',
height: 200,
items: [{
xtype: 'button',
text: 'Click Me'
}]
},{
xtype: 'panel',
title: 'Panel 3',
width: 150,
height: 100
}]
});
|
在前面的代码中,这是嵌套的组件,结构如下图所示:
上面的代码运行后将输出类似以下截图:
布局
布局定义了包含的组件是如何定位的以及设定组件的尺寸大小。每一个容器都有一个布局。默认布局是 auto 。这将不会为子组件指定任何关于位置和大小的规则。
在上面的图中,你可能已经注意到这些子组件只是一个接一个嵌套在父级容器中。这是在代码中因为我们还没有为这些组件制定任何布局,默认情况下使用的是 auto 布局。
现在,让我们在相同的代码里使用一些布局。下列示例中,我们将使用 column 布局和 center 布局。
当你使用 column 布局,你可以指定 columnWidth 。所有的列的 columnWidth 的值的总和必须等于 1 。你也可以为一些列指定固定宽度,如以下代码所示。这里,Panel3 取了一个 150 的固定宽度,然后剩下的两列按照 columnWidth 的值分配剩下的宽度:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
Ext.create('Ext.panel.Panel', {
renderTo:Ext.getBody(),
width:700,
height:400,
layout:'column',
items: [{
xtype: 'panel',
title: 'Panel 1',
columnWidth: 0.4,
height: 400,
},{
xtype: 'panel',
title: 'Panel 2',
columnWidth: 0.6,
layout: 'center',
height: 400,
items: [{
xtype: 'button',
text: 'Click Me'
}]
},{
xtype: 'panel',
title: 'Panel 3',
width: 150,
height: 400
}]
});
|
以上代码输出为:
updateLayout
updateLayout 是 Ext.container.Container 对象里的一个方法。这可以用来根据布局规则重新定位子组件。例如你修改了布局方式,需要动态的更新布局时。
suspendLayout
大多数时候你不会用到这个 updateLayout 方法,然而有些时候你必须调用它。
这个 updateLayout 方法是在你重绘和当你添加或删除了一个组件时自动调用。有时候你可能需要它暂停一下,不是马上就调用,特别是当你添加或删除多个子组件时。所以在这种情况下,你可以设置 suspendLayout 属性为 true ,一旦你完成添加或删除组件的操作,你可以设置 suspendLayout 为 false 并在你的代码中手动调用 updateLayout 方法。
同样的如果你想对整个框架停止更新布局,你可以调用 Ext.suspendLayouts() ,然后在你的操作完成后你可以通过调用 Ext.resumeLayouts(true) 恢复它。
以下是 Ext JS 中可用的布局:
- absolute
- accordion
- anchor
- border
- card
- center
- column
- fit
- hbox
- table
- vbox
absolute 绝对布局
这个布局使用 x 和 y 属性来指定组件的绝对定位:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
Ext.create('Ext.panel.Panel', {
renderTo:Ext.getBody(),
width:700,
height:400,
layout:'absolute',
items: [{
xtype: 'panel',
title: 'Panel 1',
x: 12,
y: 20,
height: 250
},{
xtype: 'panel',
title: 'Panel 2',
x: 200,
y: 150,
height: 200
},{
xtype: 'panel',
title: 'Panel 3',
x: 400,
y: 250,
width: 150,
height: 100
}]
});
|
这里所示的输出,你可以重叠组件因为他们用绝对位置定位的:
accordion 手风琴(可折叠)布局
这个布局展示了在一个时间里只有一个内置的可支持折叠和展开的子级 panel 。瞧一下以下示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 700,
height: 400,
layout: 'accordion',
items: [{
title: 'Item 1',
html: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum'
},{
title: 'Item 2',
html: 'some content here'
},{
title: 'Item 3',
html: 'empty'
}]
});
|
这里显示的输出,这个 Item 1 是展开的,而其他的 panel 是折叠的:
anchor 锚点布局
这个布局使你能够指定子级组件的大小,而这是相对于布局容器的。首先容器根据指定的锚点规则调整然后所有的子级组件再作调整:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 700,
height: 400,
layout: 'anchor',
items: [{
title: 'Item 1',
html: 'Item 1',
anchor: '50%'
},{
title: 'Item 2',
html: 'Item 2',
anchor: '-20 -200'
},{
title: 'Item 3',
html: 'Item 3',
anchor: '-200'
}]
});
|
输入如以下截图:
border 布局
这个布局允许你为子组件指定一个区域位置,例如 center,north,south,west 和 east。当你使用 border 布局时,在其内的组件必须有一个指定区域为 center,如下列代码所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 700,
height: 400,
layout: 'border',
items: [{
title: 'Item 1',
html: 'Item 1',
region: 'center'
},{
title: 'Item 2',
html: 'Item 2',
region: 'east',
width: 200
},{
title: 'Item 3',
html: 'Item 3',
region: 'south',
height: 100
}]
}) ;
|
以上代码输出类似下列视图:
card 卡片布局
在此布局中,只有一个子组件是可见的,这个组件基本上充满整个容器。卡片布局一般应用在向导或者 tabs:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 700,
height: 400,
layout: 'card',
defaultListenerScope: true,
bbar: ['->',{
itemId: 'btn-prev',
text: 'Previous',
handler: 'showPrevious',
disabled: true
},{
itemId: 'btn-next',
text: 'Next',
handler: 'showNext'
}],
items: [{
index: 0,
title: 'Item 1',
html: 'Item 1'
},{
index: 1,
title: 'Item 2',
html: 'Item 2'
},{
index:2,
title: 'Item 3',
html: 'Item 3'
}],
showNext: function () {
this.navigate(1);
},
showPrevious: function () {
this.navigate(-1);
},
navigate: function (incr) {
var layout = this.getLayout();
var index = layout.activeItem.index + incr;
layout.setActiveItem(index);
this.down('#btn-prev').setDisabled(index===0);
this.down('#btn-next').setDisabled(index===2);
}
});
|
卡片布局的输出。当你点击 next 按钮,将会显示 Item 2 面板:
center 中心布局
这种布局,容器的子组件在中间。在本章中开始介绍布局的部分,我们已经有一个例子了。
column 列布局
用此布局,你可以将容器划分为指定数量的列并指定每列所占的大小。这个例子也在本章开始介绍布局的部分中可以找到。
fit 适配布局
在此布局中,子组件将会自适应容器的尺寸。如下:
1
2
3
4
5
6
7
8
9
10
11
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 700,
height: 400,
layout: 'fit',
bodyPadding: 20,
items: [{
title: 'Item 1',
html: 'Fills the container',
}]
});
|
下列截图展示以上代码的输出。注意:Item 1 组件与父级容器之间的空隙是我们指定了 bodyPadding 属性:
hbox 布局
这种布局与 column 布局几乎是一样的,但是这种布局允许你拉伸列的高度。这里使用 flex 选项为子组件设置水平的相对值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 700,
height: 400,
layout:{
type: 'hbox',
pack: 'start',
align: 'stretch',
},
items: [{
title: 'Item 1',
html: 'Item 1',
flex: 1
},{
title: 'Item 2',
html: 'Item 2',
width: 100
},{
title: 'Item 3',
html: 'Item 3',
flex: 2
}]
});
|
上面代码输出:
table 表格布局
这个布局允许你渲染一个表格出来。你可以指定列数和行数,使用 rowspan 和 colspan 创建复杂布局:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 700,
height: 400,
layout:{
type: 'table',
columns: 3,
tableAttrs: {
style: {
width: '100%'
}
}
},
items: [{
rowspan: 3,
title: 'Item 1',
html: 'Item 1'
},{
title: 'Item 2',
html: 'Item 2'
},{
title: 'Item 3',
rowspan: 2,
html: 'Item 3'
},{
title: 'Item 4',
html: 'Item 4'
},{
title: 'Item 5',
html: 'Item 5'
},{
title: 'Item 6',
html: 'Item 6'
},{
title: 'Item 7',
html: 'Item 7'
}]
});
|
以下截图所示为前面 table 布局代码的输出结果:
VBox 布局
这个布局内,子组件是垂直向下一个接一个排列。看一下以下的示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 700,
height: 400,
layout:{
type: 'vbox',
pack: 'start',
align: 'stretch',
},
items: [{
title: 'Item 1',
html: 'Item 1',
flex: 1
},{
title: 'Item 2',
html: 'Item 2',
height: 100
},{
title: 'Item 3',
html: 'Item 3',
flex: 2
}]
});
|
这段代码所示的输出:
总结
在本章中,我们了解学习了在 Ext JS 中的基础类和这些类中常用的方法,你还学习了如何创建和扩展一个类。还有如何使用 事件 和 查询元素及组件的功能。
本人喜交朋友,欢迎扫描博客公告处个人二维码交流进步