一个ExtJS 应用程序是由一个或者更多个叫做组件的窗口小部件组成的。所有的组件都是Ext.Component类的子类,它允许它们参与到自动的生命周期管理中去,包括实例化、渲染、设置尺寸和位置、还有去实例化。ExtJS提供了大范围的实用组件,而且任何组件都可以很容易的被扩展,去创建一个定制的组件。
容器是一个可以包含其他组件的特殊组件。一个典型的应用程序是由许多内嵌成树状结构,可以用组件层次代表的组件构成的。容器负责管理组件和它们的子元素的生命周期,包括创建、渲染、尺寸和位置,还有销毁。一个典型的应用程序组件层级从顶部的Viewport开始,在它里面内嵌了其他的容器或者组件。
使用容器的items配置属性,子组件被添加到容器中。这个例子使用Ext.create去实例化了两个Panel,然后把那些Panel作为子组件添加到一个Viewport中:
var childPanel1 = Ext.create('Ext.panel.Panel', { title: 'Child Panel 1', html: 'A Panel' });
var childPanel2 = Ext.create('Ext.panel.Panel', { title: 'Child Panel 2', html: 'Another Panel' });
Ext.create('Ext.container.Viewport', { items: [ childPanel1, childPanel2 ] });
容器使用布局管理器(Layout Manager)去设置它们的子组件的尺寸和位置。要获得更多关于布局和容器的信息,请查阅布局和容器指南。
请看 Container Example 去了解这个工作的demo是如何使用items配置去向一个容器中添加组件的。
每一个组件都有一个象征性的名字,这种东西称作一个xtype。比如 Ext.panel.Panel 有一个称作’panel‘的xtype。所有组件的xtype都被列在组件的API文档中。上面的例子展示了如何去添加一个已经加载好的组件到一个容器中。但是在大型的应用程序中,这不是很理想的,因为不是所有的组件需要立刻被实例化,而且根据应用程序的使用,一些组件也许从来都不会被实例化。比如一个使用Tab Panel的应用程序仅需要每一个tab被用户点击的时候,才去渲染tab里面的内容。这就是xtype被应用的地方,先允许一个容器的子元素被配置好,但是在容器没有决定它是必须的之前,它是不会被实例化的。
下面这个示例代码使用一个Tab Panel展示了一个容器的子元素的懒加载和渲染。每一个tab有一个当tab被渲染时展示一个警告框的监听器。
Ext.create('Ext.tab.Panel', {
renderTo: Ext.getBody(),
height: 100,
width: 200,
items: [
{
// Explicitly define the xtype of this Component configuration.
// This tells the Container (the tab panel in this case)
// to instantiate a Ext.panel.Panel when it deems necessary
xtype: 'panel',
title: 'Tab One',
html: 'The first tab',
listeners: {
render: function() {
Ext.MessageBox.alert('Rendered One', 'Tab One was rendered.');
}
}
},
{
// this component configuration does not have an xtype since 'panel' is the default
// xtype for all Component configurations in a Container
title: 'Tab Two',
html: 'The second tab',
listeners: {
render: function() {
Ext.MessageBox.alert('Rendered One', 'Tab Two was rendered.');
}
}
}
]
});
这段代码运行的结果就是为第一个tab立即显示一个警告框。此现象发生的原因是第一个tab是默认活动的tab,因此它的容器Tab Panel立即初始化和渲染了它。
指导第二个tab被点击,它的警告框是不会得到显示的。这表明了在被需要以前,这个tab是不会被渲染的,因为直到这个tab被激活,render事件才被触发。
可以工作的demo见 Lazy Instantiation Example
所有的组件都内置了show和hide方法。方法隐藏组件使用的默认CSS是“display:none”,但是他可以使用hideMode配置项来修改:
var panel = Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
title: 'Test',
html: 'Test Panel',
hideMode: 'visibility' // use the CSS visibility property to show and hide this component
});
panel.hide(); // hide the component
panel.show(); // show the component
浮动组件置身于文档流之外,使用CSS的绝对定位,不参与它们容器的布局。一些组件,比如说窗口(Window),默认是浮动的,然而任何组件都可以使用floating配置项变成浮动的。
var panel = Ext.create('Ext.panel.Panel', {
width: 200,
height: 100,
floating: true, // make this panel an absolutely-positioned floating component
title: 'Test',
html: 'Test Panel'
});
上面的代码初始化了一个Panel,但是并没有渲染它。一般的一个组件要么有设置了一个renderTo配置,要么就作为一个容器的子组件,然而在浮动组件的情况下,两者都不是必须的。浮动组件在第第一次调用它们的show方法时自动被渲染到文档体系中。
panel.show(); // render and show the floating panel
这里有其他一些和浮动组件相关的配置和方法需要注意:
1 draggabble - 使得浮动组件可以在屏幕周围被拖动。
2 shaodow - 定制一个浮动组件的阴影。
3 alignTo() - 使浮动组件同一个特定的元素对其。
4 center() - 让浮动组件在它的容器中对其。
可以工作的浮动组件的demo见 Floating Panel Example。
当要创建一个新的用户界面(UI)类时,必须选择那个类是拥有一个组件的实体,还是扩展那个组件。
推荐做法是扩展跟所需功能最类似的基类。这是因为ExtJS提供的生命周期自动管理包含在需要时自动渲染,在被一个恰当的布局管理器自动设置组件的尺寸和位置,还有自动从容器中销毁和移除,这些功能。
创建一个组件的(继承了该组件的)新类并替换它在组件层级中的位置,比创建一个拥有一个ExtJS组件,还要在外部渲染和管理的新类,要容易。
子类
类系统(Class System)让扩展一个现有的组件变得容易。线面这个例子创建了一个Ext.Component 的子类,没有任何附加功能。
Ext.define('My.custom.Component', {
extend: 'Ext.Component'
});
ExtJS使用模板方法模式(Template method pattern)委派给子类,特定于那个子类的行为。
意思是继承链中的每一个类都也许会“贡献”针对组件的生命周期中某些方面的额外的逻辑块。每一个类都实现了它们自己的特殊行为,而且允许其它类在继承链中继续贡献它们自己的逻辑。
一个例子就是渲染(render)方法。render是Component的父类中定义的一个私有方法, AbstractComponent 负责组件生命周期中初始化和渲染方面的工作。render必须不能被重写,但是在处理过程中调用onRender允许子类的实现添加一个onRender方法去执行特定于类的处理。每一个onRender方法在“贡献”它额外的逻辑之前必须先调用它父类的onRender方法。
下面这个图描绘了onRender模板方法的功能。
render方法被调用了(这是由容器的布局管理器来完成的)。这个方法也许没有被重写,而是由Ext基类实现的。它调用了 this.onRender,this.onRender是现在的子类的实现(如果实现了的话)。调用父类的版本又调用父类的版本,等等。最后,每一个类都贡献了它的功能,并且控制流程又回到render方法。
下面的实例是一个实现onRender方法的组件的子类:
Ext.define('My.custom.Component', {
extend: 'Ext.Component',
onRender: function() {
this.callParent(arguments); // call the superclass onRender method
// perform additional rendering tasks here.
}
});
重点注意许多的模板方法也有一个对应的事件。例如render事件在组件被渲染之后被触发。然而在实现子类时,必须要使用模板方法去展现生命周期重要方法的类逻辑,而不是事件。事件也许会被延缓执行,或者被一个句柄所阻止。
下面是能够被组件的子类实现模板方法:
1 initComponent - 这个方法被构造器(constructor)调用。它被用来初始化数据,设定配置,还有附加事件处理句柄。
2 beforeShow - 这个方法在组件被显示出来之前被调用。
3 onShow - 允许显示操作有附加的行为。在调用了父类的onShow以后,组件将会是可见的。
4 afterShow - 这个方法在组件已经被显示了之后被调用。
5 onHide - 允许隐藏操作有附加的行为。在调用了父类的onHide方法之后,组件将会被隐藏。
6 afterHide - 这个方法会在组件已经隐藏之后被调用。
7 onRender - 允许渲染情形下有附加的行为。
8 afterRender - 允许渲染被完成之后又附加的行为。在这个阶段组件的元素已经根据配置定好了样式,将会添加任何配置的CSS类名的样式,同时配置了可见性和使用状态。
9 onEnable - 允许启动(enable)操作有附加的行为。在调用了父类的onEnable之后,组件将呈可用状态。
10 onDisable - 允许禁用(disable)操作有附加的行为。在调用了父类的onDisable之后,组件将呈不可用状态。
11 onAdded - 允许在一个组件被添加到容器中的时候有附加的行为。在这个阶段,组件在父容器的子条目集合之中。在调用了父类的onAdded之后,ownerCt引用将会被表现出来,而且如果配置了一个ref,refOwner将会被设置。
12 onRemoved - 允许在一个组件被从他的父容器中移除的时候有附加的行为。在这个阶段,组件将会从父容器的子条目集合中被移除,但是不会被销毁(如果父容器的autoDestroy被设置成了true,或者remove的调用调用传入了第二个肯定的参数,它将被销毁掉)。在调用了父类的onRemoved之后,ownerCt和refOwner将不会被表现出来。
13 onResize - 允许重新定义尺寸的操作有附加的行为。
14 onPosition - 允许定位的操作有附加的行为。
15 onDestroy - 允许销毁操作有附加的行为。
16 beforeDestroy - 这个方法在组件被销毁之前被调用。
17 afterSetPosition - 这个方法在组件的位置被设定之后被调用。
18 afterComponentLayout - 这个方法在组件在布局中被放置好以后被调用。
19 beforeComponentLayout - 这个方法在组件在布局中被放置好之前被调用。
选择最好的类去扩展,主要是要考虑效率的因素,还要考虑基类必须提供哪些能力。
不论何时,一旦任何用户界面组件需要被渲染和管理,常常倾向于扩展Ext.Panel。
Panel拥有许多的能力:
1 边框(Border)
2 头部(Header)
3 头部工具(Header tools)
4 尾部(Footer)
5 尾部按钮(Footer buttons)
6 顶部工具条(Top toolbar)
7 按钮工具条(Button toolbar)
8 包含和管理子组件
如果这些能力都不是必须的,那么使用一个Panel就是在浪费资源。
如果需要用户界面组件不需要包含任何其他的组件,即,如果它仅仅是封装了一些HTML形式的东西就满足了需求,那么扩展Ext.Component是合适的。比如,下面这个类就是一个包含了一个HTML图像元素,允许设置和获取图像的src属性的Component。它也会在图像被加载时触发一个load事件。
Ext.define('Ext.ux.Image', {
extend: 'Ext.Component', // subclass Ext.Component
alias: 'widget.managedimage', // this component will have an xtype of 'managedimage'
autoEl: {
tag: 'img',
src: Ext.BLANK_IMAGE_URL,
cls: 'my-managed-image'
},
// Add custom processing to the onRender phase.
// Add a ‘load’ listener to the element.
onRender: function() {
this.autoEl = Ext.apply({}, this.initialConfig, this.autoEl);
this.callParent(arguments);
this.el.on('load', this.onLoad, this);
},
onLoad: function() {
this.fireEvent('load', this);
},
setSrc: function(src) {
if (this.rendered) {
this.el.dom.src = src;
} else {
this.src = src;
}
},
getSrc: function(src) {
return this.el.dom.src || this.src;
}
});
用例:
var image = Ext.create('Ext.ux.Image');
Ext.create('Ext.panel.Panel', {
title: 'Image Panel',
height: 200,
renderTo: Ext.getBody(),
items: [ image ]
});
image.on('load', function() {
console.log('image loaded: ', image.getSrc());
});
image.setSrc('http://www.sencha.com/img/sencha-large.png');
见于 Managed Image Example 有一个可以工作的demo。这个例子仅用于展示的目的 - Ext.Img 类则可以被用于在真实应用程序中管理图片。
如果需要的用户界面组件会包含其他的组件,但是不需要前面提到的一个Panel的能力,那Ext.container.Container就是最适合被扩展的类了。在容器几倍,记住使用了那种局部(Layout)和管理子组件是很重要的。
容器拥有下面这些附加的模板方法。
1 onBeforeAdd - 这个方法在一个新的子组件加入时被调用。它被传入了新的组件,并且也许会被用来改变这个组件,或者用某些方式对容易做一些准备工作。如果返回false,就取消添加操作。
2 onAdd - 这个方法在一个新的子组件已经加入时调用。它被传入了已经被加入的组件。这个方法也许被用来更新任何依赖子条目的状态的内部结构。
3 onRemove - 这个方法在一个新组件已经被移除之后被调用。它被传入了已经被移除的组件。这个方法也许会被用来更新任何依赖子条目的状态的内部结构。
4 beforeLayout - 这个方法在容器已经布局(必要时还有渲染)好它的子组件之前被调用。
5 afterLayout - 这个方法在容器已经布局(必要时还有渲染)好它的子组件之后被调用。
如果需要的用户界面组件必须有一个头部,尾部和工具条,那么Ext.Panel就是最适合被扩展的类。
重要的是:一个Panel是一个容器。记住那个Layout被选择用来渲染和管理子组件是很重要的。
扩展了Ext.Panel的类常常是高度应用程序相关的,并且一般被用来在一个配置好的布局中聚集其他的用户界面组件(常常是容器和表单域),还提供使用在tbar和bbar中的控制结构的方式操作所包含的组件的方法。
Panel拥有下面这些附加的模板方法:
1 afterCollapse - 这个方法在面板被收起时被调用。
2 afterExpand - 这个方法在面板被展开时被调用。
3 onDockedAdd - 这个方法在一个对接条目被加入到面板时被调用。
4 onDockedRemove - 这个方法在一个对接条目被从面板中移除时被调用。
---------------
下面是文章来源:
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有