原文:http://docs.sencha.com/ext-js/4-0/#!/guide/component
翻译:frank/sp42 转载请保留本页信息
ExtJS 程序由不同的器件所组成,器件也称作“组件”。所有组件皆是 Ext.Component 其子类,目的在于能够参与生存周期的自动化管理,包括实例化、渲染、大小调整与定位、销毁的问题。ExtJS不但直接提供了一个广阔且实用的组件模型,而且使得任意组件都可以轻松地扩展出新的组件。
An Ext JS application's UI is made up of one or many widgets called Components. All Components are subclasses of the Ext.Component
class which allows them to participate in automated lifecycle management including instantiation, rendering, sizing and positioning, and destruction. Ext JS provides a wide range of useful Components out of the box, and any Component can easily be extended
to create a customized Component.
组件层次 The Component Hierarchy
容器是组件的一种特殊类型,用于承载其他组件之用。一个典型的应用程序是由若干嵌套的组件而成,这有点像树状的结构。容器负责管理子组件的生存周期,包括实例化、渲染、大小调整与定位、销毁的问题。一个典型的组件层次以“视口 Viewport ”为顶点,然后其他的容器或者组件嵌套于内:
A Container is a special type of Component that can contain other Components. A typical application is made up of many nested Components in a tree-like structure that is referred to as the Component hierarchy. Containers are responsible for managing the Component
lifecycle of their children, which includes creation, rendering, sizing and positioning, and destruction. A typical application's Component hierarchy starts with a Viewport
at the top, which has other Containers and/or Components nested within it:
可以通过容器的 items 配置项来添加容器的子组件。该例子通过 Ext.create 实例化了两个面板,这两个面板作为 Viewport 的子项出现:
Child Components are added to a Container using the Container's items configuration property. This example uses Ext.create to instantiate two Panels, then adds those Panels as child Components of a 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 ] });
容器使用布局管理器进行子组件的定位和大小的调节。更多有关的资讯请参与《布局与容器》的指南。
Containers use Layout Managers to size and position their child Components. For more information on Layouts and Containers please refer to theLayouts and Containers Guide.
通过参与容器的例子可以了解到如果通过 items 项为容器加入组件。
See the Container Example for a working demo showing how to add Components to a Container using the items configuration.
Xtype 和延时实例化XTypes and Lazy Instantiation
每一个组件都有一个 xtype 的标记。例如 Ext.panel.Panel 的 xtype 为 “panel”。可通过文档中心参阅全体的xtype对照表。下面的例子是如何把已经实例化的组件加入到容器中去。然而在大型的应用程序中,把所有组件马上都实例化的话,不是一个明智的选择,而且部分组件有些是根本不需要进行实例化的。例如,使用 TabPanel 控件,只是用户点击了的才会显示出来。这样的话,在进行配置的时候只是送入一个xtype,便不会实例化,而是内部需要显示的话才进行渲染。
Every Component has a symbolic name called an xtype
. For exampleExt.panel.Panel
has an xtype
of 'panel'. The xtype
s for all Components are listed in theAPI Docs for
Component. The above example showed how to add already instantiatedComponents to aContainer.
In a large application, however, this is not ideal since not all of the Components need to be instantiated right away, and some Components might never be instantiated depending on how the application is used. For example an application that uses aTab
Panel will only need the contents of each tab to be rendered if and when each tab is clicked on by the user. This is wherextype
s come in handy by allowing a Container's children to be configured up front, but not instantiated until the Container
determines it is necessary.
下面的例子演示了 TabPanel 的延时实例化过程。每张 Tab 有一个提示已经渲染好的事件触发。
The following example code demonstrates lazy instantiation and rendering of a Container's Child components using a Tab Panel. Each tab has an event listener that displays an alert when the tab is rendered.
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.'); } } } ] });
Floating Components (浮动组件)
浮动组件的意思是脱离 document 流的布局定位,与 CSS 的绝对定位相对相应,因此不参与其容器的布局。一些如 Windows 的组件默认便是浮动的。其实任何组件都可以改为浮动的布局,见 floatiing 配置项。
Floating Component are positioned outside of the document flow using CSS absolute positioning, and do not participate in their Containers' layout. Some Components such asWindows
are floating by default, but any Component can be made floating using thefloating
configuration.
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 却还没有渲染它。怎么指定 Component 渲染到哪?一般来说你可以在配置项 renderTo 那里指定渲染目的地,也可以在 Container 父容器中指定,不过在本例子中就是后者作为子组件的形式出现的。浮动组件一般第一时候自动渲染到 document body,然后调用 show() 方法就会显示:
The above code instantiates a Panel but does not render it. Normally a Component either has a renderTo
configuration specified, or is added as a child Component of a Container, but in the case of floating Components neither of these is needed. Floating Components are automatically rendered to the document body the first time theirshow
method is called:
panel.show(); // 渲染并显示浮动面板 render and show the floating panel
这里是一些与浮动组件相关的配置项和方法:
Here are a few other configurations and methods to make note of related to floating components:
draggable
- 使得浮动组件在屏幕中可作拖动。enables dragging of a floating Component
around the screen.shadow
- 自定义浮动组件其阴影的外观。customizes the look of a floating Component's
shadow.alignTo()
- 把浮动组件对齐到某个特定的元素。aligns a floating Component to
a specific element.center()
- 把浮动组件在其容器中居中。centers a floating Component in its Container.
可参阅一下浮动面板的在线例子。
For a working demo of floating Component features see the Floating Panel Example.
组合或扩展 Composition or Extension
当创建一个新类,往往要作出这么的一个选择:要么拥有某个工具类的实例来扮演首要的角色,要么扩展那个类。
When creating a new UI class, the decision must be made whether that class should own an instance of aComponent, or to extend
that Component.
使用 ExtJS 过程中,推荐从最靠近的基类开始扩展,实现所需的功能即可。这是因为 ExtJS 提供的自动生存周期引入了自动渲染的机制、自动大小调整和承担接受来自布局管理器的 UI 组件布局调控,还有在容器(Container)中自动销毁的功能。
It is recommended to extend the nearest base class to the functionality required. This is because of the automated lifecycle management Ext JS provides which includes automated rendering when needed, automatic sizing and positioning of Components when managed
by an appropriate layout manager, and automated destruction on removal from a Container.
组织一个新类,它就是 ExtJS 的类,实现起来是很方便的,这就会导致了 Container→Component层次的形成,相比较,新类拥有一个 ExtJS 类的话,必须从外围对其渲染和组织。
It is easier to write a new class which is a Component and can take its place in the Component hierarchy rather than a new class which has an Ext JS Component, and then has to render and manage it from outside.
模板方法模式 The Template method Pattern
ExtJS 组件大量采用Template Method pattern(模板方法模式)来实现继承层次,交由子类来负责其特定的行为。
Ext JS uses the Template method pattern to delegate to subclasses, behavior which is specific only to that subclass.
其意义在于,继承链中的每个子类得以于组件生存周期的某个阶段内“提交(contribute)”额外的逻辑功能。于是每一个类便拥有属于其自身的行为,当其他类加入自己的行为时也不会造成相互间的影响。
The meaning of this is that each class in the inheritance chain may "contribute" an extra piece of logic to certain phases in the Component's lifecycle. Each class implements its own special behavior while allowing the other classes in the inheritance chain
to continue to contribute their own logic.
其中一个例子是render(渲染)函数。render 函数不能够被覆盖,应该是一层一层地在各子类的实现中加入 onRender 方法,那么 render 函数就会在执行的时候把各onRender方法访问调用。每一个onRender方法必须调用其父类的onRender方法继而再埋头处理(contribute)自己(子类)的逻辑部分。
下面的图例演示了模板方法onRender的机能过程。
The diagram below illustrates the functioning of the onRender
template method.
render是由容器的布局管理器(Container’s layout manager)负责调用。该方法的实现不能被“覆盖而冲掉(overridden)”,它是由 ExtJS 基类提供的。this.onRender表示当前子类所写的实现(如有提供的话)。它会访问父类的版本、父类的版本又会调用父、父类的版本……最终,每个类完成了其功能,render 函数的返回值对生存周期进行控制。
The render
method is called (This is done by a Container’s layout manager). This method may not be overridden and is implemented by the Ext base class. It callsthis.onRender
which is the implementation within the current subclass
(if implemented). This calls the superclass version which calls its superclass version etc. Eventually, each class has contributed its functionality, and control returns to therender
function.
这里是一个组件的子类,它实现了 onRender 方法:
Here is an example of a Component subclass that implements the onRender
method:
Ext.define('My.custom.Component', { extend: 'Ext.Component', onRender: function() { this.callParent(arguments); // call the superclass onRender method // perform additional rendering tasks here. } });
强调:编写子类时,模板方法应在实例化的过程中调用,属于生存周期内的一部分的动作,而不应是事件的一部分。事件有可能会由 handler 挂起,或中止。
It is important to note that many of the template methods also have a corresponding event. For example therender
event is fired after the Component is rendered. When subclassing, however, it is it is essential to use template methods to perform class logic at important phases in the lifecycle andnot events. Events may be programmatically suspended, or may be
stopped by a handler.
以下是 Component 子类皆可享有的模板方法:
Below are the template methods that can be implemented by subclasses of Component:
initComponent
构造器调用的方法。用于初始化数据、设置配置项,登记事件的相关任务。This method is invoked by the constructor. It is used to initialize data, set up configurations, and attach event handlers.beforeShow
组件显示之前执行的方法。This method is invoked before the Component is shown.onShow
允许在显示组件的同时加入特定的行为。父类的 onShow 执行过后,Componenet 将会显示。Allows addition of behavior to the show operation. After calling the superclass’s onShow, the Component will be visible.afterShow
组件显示后执行的方法。This method is invoked after the Component is shown.onShowComplete
当 afterShow 方法完成后执行该方法。This method is invoked after theafterShow
method is completeonHide
允许在隐藏组件的同时加入特定的行为。父类的onHide执行过后,Componenet 将会隐藏。Allows addition of behavior to the hide operation. After calling the superclass’s onHide, the Component will be hidden.afterHide
This method is invoked after the Component has been hiddenonRender
允许渲染期间加入特定的行为。父类的 onRender 被调用后,可以确定组件的 Element 元素。可以在此阶段中执行剩余 DOM任务以完成结构上的控制(HTML结构)。Allows addition of behavior to the rendering phase.After calling the superclass’s onRender, the Component's Element willexist. Extra DOM processing
may be performed at this stage to completethe desired structure of the Component.afterRender
允许渲染完成后加入特定的行为。此阶段的组件元素会根据配置的要求(configuartion)设置样式,会引入已配置的CSS样式名称所指定的样式名称,并会配置可见性(visibility)和配置可激活(enable)情况。Allows addition of behavior after rendering is complete. At this stage the Component’s Element will have been styled according
to the configuration, will have had any configured CSS class names added, and will be in the configured visibility and the configured enable state.onEnable
允许在激活组件的同时加入特定的行为。父类的onEnable执行过后,Componenet将会激活启用。Allows addition of behavior to the enable operation. After calling the superclass’s onEnable, the Component will be enabled.onDisable
允许在禁用组件的同时加入特定的行为。父类的onDisable执行过后,Componenet将会禁用。Allows addition of behavior to the disable operation. After calling the superclass’s onDisable, the Component will be disabled.onAdded
当组件被加入到容器中时允许添加新的行为。此阶段中,该组件就是容器集合中的一员。调用父类的 onAdded 之后会出现 ownerCt 的一个引用,如果你配置了 ref,则会设置 refOwner。Allows addition of behavior when a Component is added to a Container. At this stage, the Component is in the parent Container's collection
of child items. After calling the superclass's onAdded, the ownerCt reference will be present, and if configured with a ref, the refOwner will be set.onRemoved
当组件从容器中被移除时允许添加新的行为。此阶段中,该组件已经不是容器集合中的一员了,但尚未销毁(如父容器的 autoDestory 为 true,又或者传入了第二个参数为 true 的话,组件都会自动销毁)。当父类的 onRemoved 调用之后,不会出现 owenerCt 和 refOwner。Allows addition of behavior when a Component is removed from its parent Container.
At this stage, the Component has been removed from its parent Container's collection of child items, but has not been destroyed (It will be destroyed if the parent Container's autoDestroy is true, or if the remove call was passed a truthy second parameter).
After calling the superclass's onRemoved, the ownerCt and the refOwner will not be present.onResize
当调整大小尺寸时加入的行为。Allows addition of behavior to the resize operation.onPosition
当进行定位时加入的行为。Allows addition of behavior to the position operation.onDestroy
允许在销毁组件的同时加入特定的行为。父类的onDestroy执行过后,Componenet将会被销毁。Allows addition of behavior to the destroy operation. After calling the superclass’s onDestroy, the Component will be destroyed.beforeDestroy
当组件被销毁之前执行的方法。This method is invoked before the Component is destroyed.afterSetPosition
当组件进行定位之前执行的方法。This method is invoked after the Components position has been set.afterComponentLayout
当组件执行布局之前调用的方法。This method is invoked after the Component is laid out.beforeComponentLayout
当组件执行布局之后调用的方法。This method is invoked before the Component is laid out.
ExtJS 组件类的各层次中的均有其自身的模板方法,我们可以打开来看看,这些都是根据自身不同的需求而作出的设计。
提示: 当调用父类的模板方法时,最简洁的方法就是使用Function.apply,保证所有的参数都可以接受得到,传送给那个模板方法:
Ext.ux.Subclass.superclass.onRender.apply(this, arguments);
要扩展哪个类 Which Class To Extend
选择适合的类来扩展不但要考虑基类提供哪些功能,而且对性能方面也要着重考虑。无论有多少个 UI 控件被渲染或调控, Ext.Panel 常常就是被衍生(extend)的对象。
Panel 类拥有许多的能力:
Choosing the best class to extend is mainly a matter of efficiency, and which capabilities the base class must provide. There has been a tendency to always extendExt.Panel
whenever any set of UI Components needs to be rendered and managed.
The Panel class has many capabilities:
- Border(躯干)
- Header(头部)
- Header工具条
- Footer(底部)
- Footer按钮
- Top toolbar(顶部工具条)
- Bottom toolbar(底部工具条)
- 承托和管理子组件
如果这些派不上用场,那使用 Panel 便是资源浪费。
If these are not needed, then using a Panel is a waste of resources.
Component(组件类)
如果要求的 UI 控件不需要其他的细节的控件,也就是,仅仅是封装某部分的 HTML 元素的话,那么可取的扩展对象就是 Ext.BoxComponent或Ext.Component。如果再缩窄一步,我不需要听凭父容器提供的大小调控功能,那么使用Ext.Component就可以了。
强调:Component 类并不会内省而得知哪一种元素作为 holder。因此为了创建所需的元素(Element),应设定autoEl
的配置项。
例如,要把一张图片封装为 Component,我们于是乎这样定义:
If the required UI Component does not need to contain any other Components, that is, if it just to encapsulate some form of HTML which performs the requirements, then extendingExt.Component
is appropriate. For example, the following class is a Component that wraps an HTML image element, and allows setting and getting of the image'ssrc
attribute. It also fires aload
event when the image is loaded:
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');
这是一个可封装图片的 Ext Component 类,可参与非箱子方寸模型(non box-sizing)的布局。这里看看演示。
See the Managed Image Example for a working demo. This example is for demonstration purposes only - theExt.Img class should be used for managing
images in a real world application.
Container(容器类)
如果 UI 组件只是用于承载(Contain)其他 UI 元素在其身上,并不需要前文提及到的 Ext.Panel 那么多的功能,那么为避免臃肿,应采用 Ext.Container 容器类来继承。同样地,autoEl指定元素的配置项亦必不可少,将用于容器在某个元素之上进行渲染。同样,在视觉控制方面,滚动条是否显示方面(即
overflow属性),用户都可以使用 Style 配置项,或容器元素的 class 属性的两种方式进行 CSS 样式制定。
If the required UI Component is to contain other Components, but does not need any of the previously mentioned additional capabilities of aPanel,
then Ext.container.Container is the appropriate class to extend. At the Container level, it is important to remember whichLayout
is to be used to render and manage child Components.
注意: 对于 Container 层次,不要忘记哪种布局类是被用于渲染和调控子组件的。
位于该层次的对象还提供了特别的模板方法: Containers have the following additional template methods:
onBeforeAdd
当添加新的子组件的时候,就会调用该方法。这时会有新组件作为参数传入,或者可修改它,或者以特别的方式准备好 Container。返回 false 表示终止添加的操作。This method is invoked before adding a new child Component. It is passed the new Component, and may be used to modify the Component, or prepare the
Container in some way. Returning false aborts the add operation.onAdd
当加入新的组件后执行该方法。送入的组件将会被添加。该方法可用于根据子项状态而采取的内部结构更新。This method is invoked after a new Component has been added. It is passed the Component which has been added. This method may be used to update any internal structure which may depend upon
the state of the child items.onRemove
当新的组件被移除之后执行该方法。送入的组件将会被移除。该方法可用于根据子项状态而采取的内部结构更新。This method is invoked after a new Component has been removed. It is passed the Component which has been removed. This method may be used to update any internal structure which may
depend upon the state of the child items.beforeLayout
当容器执行布局(若需要的话会进行渲染)之后前调用该方法This method is invoked before the Container has laid out (and rendered if necessary) its child Components.afterLayout
当容器执行布局(若需要的话会进行渲染)之后调用该方法。This method is invoked after the Container has laid out (and rendered if necessary) its child Components.
此类管理了其包含的输入字段,可以精确的布局-大小调整,外补丁等等——都是通过 CSS 样式分配到元素身上这样来起作用的。
Panel (面板类)
如果组件需要头部(header)、底部(footer)、工具条(toolbar)之类的 UI 元素,那么 Ext.Panel 便是一个很不错的基类了。
If the required UI Component must have a header, footer, or toolbars, then Ext.Panel is the appropriate class to extend.
注意:Panel 也是容器的一种,因此不要忘记 Panel 使用哪种布局类来渲染和调控那些子组件的。
Important: A Panel is a Container. It is important to remember which Layout is to be used to render and manage child Components.
通常 Ext.Panel 所实现的类不但有很高的程序可制定性,而且与其他 UI 组件一起有很高的内聚性(通常作为容器使用,或表单字段使用),表现在布局配置方面,针对子组件诸如tbar(顶部工具栏),bbar(底部工具栏)这些控件的命令操作。
Classes which extend Ext.Panel are usually highly application-specific and are generally used to aggregate other UI Components (Usually Containers, or form Fields) in a configured layout, and provide means to operate on the contained Components by means of controls in thetbar
and the bbar.
Panel 有下列面板方法:
Panels have the following additional template methods:
afterCollapse
当 Panel 闭合时调用的方法。This method is invoked after the Panel is Collapsed.afterExpand
当 Panel 展开时调用的方法。This method is invoked after the Panel is expandedonDockedAdd
当 Panel 的槽位加入内容时调用的方法。This method is invoked after a docked item is added to the PanelonDockedRemove
当 Panel 的槽位移除内容时调用的方法。This method is invoked after a docked item is removed from the Panel