ExtJS 4 组件详解
ExtJS 4 的应用界面是由很多小部件组合而成的,这些小部件被称作“组件(Component
)”,所有组件都是Ext.Component
的子类,Ext.Component
提供了生命周期管理包括初始化、渲染、大小和尺寸管理、销毁等功能,这使得所有Ext.Component
的子类都自动分享了这些能力。ExtJS提供了各式各样丰富的组件,每一个组件都很容易被扩展创建成自定义组件。
The Component Hierarchy 组件层级
容器(Container
)是个可以容纳其他组件的特殊组件。通常的应用都是由很多嵌套的组件构成,这些组件有一个类似树状的结构,这就是组件的层级。容器负责管理子组件的生命周期包括始化、渲染、大小和尺寸管理、销毁。通常的应用最顶层的组件都是Viewport
然后有其他容器或者组件嵌套在其中:
子组件通过容器的items
加入到容器中,下面这个例子通过Ext.create
方法创建了两个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
)”管理子组件的尺寸和位置。关于布局和容器的详细内容可以查看《ExtJS 4 布局和容器》
XTypes and Lazy Instantiation xtype和延迟加载
每个组件都有一个代称叫做xtype
,例如Ext.panel.Panel
的xtype
是panel
。所有组件的xtype
在API Docs for Component 中有列出。上面那个例子说明了如何添加已经初始化的组件到一个容器中。在大的应用中,这种方式是不可行的,因为这种方法需要每个组件都是初始化过的,但是大的应用中,由于使用的方式有些组件可能根本没有被用到(比如有100个页面的应用,一个用户登录进来只操作了两个页面,这时把其他98个页面的组件全部初始化是不合理的),例如一个用到TabPanel
的应用,TabPanel
的每个tab只当用户点击它的时候再渲染即可。这就是引入xtype
机制的原因,有了xtype
可以让一个容器的子组件事先定义好,到真正需要的时候再初始化。
下面的示例代码通过TabPanel
展示了延迟加载和延迟渲染,每个tab都有个响应函数监听tab的渲染render
事件,渲染的时候会弹出一个对话框告知当前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,所以它的父容器TabPanel
立即初始化和渲染了它
不点击第二个tab,它的对话跨就一直不会弹出,这说明tab不会被渲染直到被用到,tab的render
事件不会触发直到tab被激活
Showing and Hiding 显示和隐藏
所有组件都有内置的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
Floating Components 浮动组件
浮动组件定位于文档流之外,使用的是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
属性配置渲染到什么位置,要么就作为容器的一个子组件由容器负责渲染,但是这个例子的浮动组件即不需要renderTo
也不需要作为子组件。浮动组件第一次调用show
方法时,会被自动渲染到DOM的document.body中:
1
panel.show(); // render and show the floating panel
有几个属性是使用浮动组件时值得注意的:
draggable
- 让浮动组件可以拖拽shadow
- 定制浮动组件的阴影效果alignTo()
- 让浮动组件对齐到一个特定元素center()
- 让浮动组件相对于容器居中
Creating Custom Components 自定义组件
Composition or Extension 组合还是继承
当创建一个新的UI类时,必须决定这个类是引用其他组件的实例还是扩展这个组件。
推荐扩展最接近的组件添加自己需要的功能,这是因为使用继承的方式可以自动获得组件原有的自动生命周期管理能力,包括按须渲染、布局管理器提供的尺寸位置管理、从容器中删除的自动析构等。
扩展一个原有组件会让扩展出的组件隶属于组件层级中,这样比一个外部类引用并掌管ExtJS组件的实例要容易的多。
Subclassing 子类化
ExtJS的类系统使得扩展一个现有组件变的很简单。接下来的代码演示了创建一个Ext.Component
的子类,不添加任何功能:
1
2
3
Ext.define('My.custom.Component', {
extend: 'Ext.Component'
});
Template Methods 模板方法
ExtJS使用了模板方法模式把特殊行为委托给子类。
这意味着每一个继承链上的类都可以“贡献”一段包含特定逻辑的片段到组件的生命周期中。每一个类实现自己特殊行为的同时,还允许其他在继承链上的类继续贡献它们自己的逻辑。
一个例子就是render
方法。render
是个私有方法,是在Component
的父类AbstractComponent
中定义的,render
在组件生命周期中负责渲染阶段的初始化。render
不能被重写,但是render
过程中会调用onRender
,这个onRender
方法是允许子类去实现的,子类可以在这里增加专属于子类的逻辑,每一个onRender
方法必须在自己的额外逻辑之前调用父类的onRender
。
下图指示了onRender
模板方法是如何工作的。render
方法首先被调用(这是布局管理器完成的),render
方法不能被覆盖,它是ExtJS中的相关基类实现的,它会调用当前子类的this.onRender
(如果当前子类有实现onRender
),这会使得继续调用父类的onRender
,父类的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
完成之后会触发render
事件。创建子类的时候最好是使用模板方法,而不是使用事件,因为模板方法一定会被执行,事件是可以被中断的(这里是我的补充:什么时候用事件,什么时候用模板方法?模板方法是面向你创建的子类的所有实例的,如果你需要增加的功能片段确实被所有实例需要,那一定要放在模板方法中,如果是某一个实例特殊需要的功能,请用事件实现,事件是可以对单独某个对象实现的)
下面列举的是Component
的子类中可以实现的模板方法:
initComponent
这个方法被构造器调用,它被用来初始化数据,设置配置,添加事件beforeShow
这个方法在组件显示前调用onShow
允许组件显示的时候附加行为,调用父类的onShow
之后,组件变为可见afterShow
这个方法在组件显示完成后调用onShowComplete
这个方法在afterShow
执行完毕的时候调用onHide
允许组件隐藏的时候附加行为,调用父类的onHide
之后,组件变为不可见afterHide
这个放在组件隐藏完成后调用onRender
允许在渲染阶段附加行为afterRender
允许在渲染完毕时附加行为,在这个阶段,组件的Element
已经赋予了样式,该加的css类都已经加上,显示和启用与否的状态都标记完成onEnable
允许启用操作时附加行为,调用父类的onEnable
之后,组件变为启用onDisable
允许禁用操作时附加行为,调用父类的onDisable
之后,组件变为禁用onAdded
允许一个组件被添加到一个容器的时候附加行为,在这个阶段,组件已经在父容器的items中,调用父类的onAdded
之后,ownerCt引用被设置,如果配置了ref,refOwner这时也被设置onRemoved
允许一个组件从父容器中删除的时候附加行为,在这个阶段,组件已经从父容器的items中移除,但是还没有被销毁(如果父容器的autoDestroy设置为true,或者如果删除操作remove函数的第二个参数设置为true,组件就会被销毁),调用父类的onRemoved
之后,ownerCt和refOwner就会移除onResize
允许改变大小的时候附加行为onPosition
允许设置位置的时候附加行为onDestroy
允许销毁时附加行为,调用父类的onDestroy
之后,组件被销毁beforeDestroy
组件销毁前调用afterSetPosition
组件位置设置之后调用afterComponentLayout
组件布局完成时调用beforeComponentLayout
组件布局之前调用
Which Class To Extend 扩展那个类
选择最合适的类继承是个影响效率的问题,基类能提供的功能也是个问题。现在有种倾向是无论什么样的UI组件都从Ext.Panel
继承
Panel类有很多能力:
- Border
- Header
- Header tools
- Footer
- Footer buttons
- Top toolbar
- Bottom toolbar
- Containing and managing child Components
如果不需要这些功能,继承Ext.Panel
是浪费资源。
Component 组件
如果创建的UI组件不需要包含任何其他组件,就比如只是对HTML片段的封装就可以满足需求的组件,推荐扩展Ext.Component
,例如下面的例子封装了HTML image元素,允许设置image的src,并且图片加载完成会触发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');
这个例子仅作为例子,Ext.Img
可以在真实应用中使用。
Container 容器
如果UI组件需要包含其他组件的能力,但是又不需要Panel
那么多功能Ext.container.Container
是个很好的选择。使用它有一点需要注意,记得使用Layout
管理子组件。Ext.container.Container
有如下模板方法:
onBeforeAdd
这个方法在添加一个子组件之前调用,方法会被传入添加进来的子组件,你可能会对子组件进行一些修改,或者对容器自身做一些准备工作,返回false会中断添加操作。onAdd
这个方法在新组件被添加完成时调用,方法会传入新添加的组件,这个方法可以用来更新依赖子组件状态的内部结构onRemove
子组件被删除之后调用,用处跟onAdd
类似beforeLayout
组件布局它的子组件之前调用的方法afterLayout
组件布局它的子组件之后调用的方法
Panel 面板
如果需求的UI组件必须有header,footer或者toolbar,Ext.panel.Panel
比较适合
注意Panel
也是个容器,也需要Layout
管理子组件
从Panel
扩展出的组件一般都是跟具体应用相关的,通常都聚合了其他组件在其中,一般都提供了操作内部组件的方法,比如在toolbar上有操作内部组件的按钮等Panel
有如下附加的模板方法:
afterCollapse
组件折叠起来之后调用afterExpand
组件展开之后调用,与afterCollapse相对应onDockedAdd
工具条上有子组件添加之后调用onDockedRemove
工具条上有子组件被移除后调用
ExtJS 4 组件详解的更多相关文章
- Angular6 学习笔记——组件详解之组件通讯
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- Extjs Window用法详解
今天我们来介绍一下Extjs中一个常用的控件Window.Window的作用是在页面中创建一个窗口,这个窗口作为容器,可以在它里面加入grid.form等控件,从而来实现更加复杂的界面逻辑. 本文的示 ...
- Extjs Form用法详解(适用于Extjs5)
Extjs Form是一个比较常用的控件,主要用来显示和编辑数据的,今天这篇文章将介绍Extjs Form控件的详细用法,包括创建Form.添加子项.加载和更新数据.验证等. 本文的示例代码适用于Ex ...
- Android中Intent组件详解
Intent是不同组件之间相互通讯的纽带,封装了不同组件之间通讯的条件.Intent本身是定义为一个类别(Class),一个Intent对象表达一个目的(Goal)或期望(Expectation),叙 ...
- Android笔记——四大组件详解与总结
android四大组件分别为activity.service.content provider.broadcast receiver. ------------------------------- ...
- Extjs combox的详解
Extjs combox的详解 写了哈extjs当中的combox,第一次写,照着网上的例子抄.在上次的例子中,是实现了,可是有一个重大的错误.也就是自己根本没有理解combox从远程服务器获取数据, ...
- vue.js基础知识篇(6):组件详解
第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 V ...
- Echars 6大公共组件详解
Echars 六大组件详解 : title tooltip toolbox legend dataZoom visualMap 一.title标题详解 myTitleStyle = { color ...
- Extjs Window用法详解 3 打印具体应用,是否关掉打印预览的界面
Extjs Window用法详解 3 打印具体应用,是否关掉打印预览的界面 Extjs 中的按钮元素 {xtype: 'buttongroup',title: '打印',items: [me.ts ...
随机推荐
- E - 食物链 poj1182
题目告诉有 3 种动物,互相吃与被吃,现在告诉你 m 句话,其中有真有假,叫你判断假的个数 ( 如果前面没有与当前话冲突的,即认为其为真话 ).每句话开始都有三个数 D A B,当D = ...
- @property中有哪些属性关键字?/ @property 后面可以有哪些修饰符?
出题者简介: 孙源(sunnyxx),目前就职于百度 整理者简介:陈奕龙(子循),目前就职于滴滴出行. 转载者:豆电雨(starain)微信:doudianyu 属性可以拥有的特质分为四类: 原子性- ...
- Android应用开发学习之画廊视图
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 画廊视图Gallery能按水平方向显示一组图片,并可以拖动图片.下面我们来看一个使用画廊视图的例子,其运行效果如下: ...
- JSP写入MySQL数据库中出现乱码问题笔记
1.在数据库链接字符串上要形如:jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=UTF-8(注意要加chara ...
- C#快速剔除字符串中不合法的文件名或者文件路径字符
C#快速剔除字符串中不合法的文件名 string strFileName= "文件名称"; StringBuilder rBuilder = new StringBuilder( ...
- hdu 1882 Strange Billboard(位运算+枚举)
http://acm.hdu.edu.cn/showproblem.php?pid=1882 感觉非常不错的一道题. 给一个n*m(1<=n,m<=16)的矩阵,每一个格子都有黑白两面,当 ...
- 《Android开发艺术探索》读书笔记 (7) 第7章 Android动画深入分析
本节和<Android群英传>中的第七章Android动画机制与使用技巧有关系,建议先阅读该章的总结 第7章 Android动画深入分析 7.1 View动画 (1)android动画分为 ...
- Java基础知识强化之集合框架笔记07:Collection集合的遍历之迭代器遍历
1. Collection的迭代器: Iterator iterator():迭代器,集合的专用遍历方式 2. 代码示例: package cn.itcast_03; import java.util ...
- yii2 and short_open_tag
在看yii2的时候, 在main文件里看到了这样一段代码 <?= Yii::$app->language ?> 而我查看了php.ini里的配置, short_open_tag=Of ...
- 堆和栈 内存分配 heap stack
Java中的堆和栈 在[函数]中定义的一些[基本类型的变量]和[对象的引用变量]都是在函数的[栈内存]中分配的.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间, ...