当你要创建一个网页时, 经常会发现,你知道怎样用原生的html来创建,却不知道如何使用浩如烟海的ext组件来实现。本文将介绍一些使用ext组件创建html的一些技巧。
简介
组件的渲染
首先让我们用一个简单的例子了解一下组件是如何渲染的:
/** The renderTo config option specifies a parent DOM element for
* rendering the component.
* For brevity it is not shown in the remaining examples.
*/
new Ext.Component({renderTo: 'component-demo' });
这个例子太简单了,我们甚至在页面上无法看到它:
但是它的确生成了下面的dom元素:
<div id="component-1001" class="x-component x-component-default" role="presentation"></div>
我们先暂停一下
- 一个ext组件使用一个<div>进行渲染,复杂的html元素也许会使用很多的html元素进行渲染,但有且只有一个外部元素作为组件的基本元素,组件渲染完成后你可以通过组件对象的el属性来访问这个元素。
- 基本元素的ID即是组件的id;
- 这里有两个css, 分别来自baseCls和ui两个配置项,这两个配置项提供有默认值,我们在创建ext组件时很少用到。稍后我们会看一个使用baseCls的例子。
-
基于你使用的ext版本,你会看到其他不同的配置属性,如ARIA。
现在让我们简化一下上面的html元素, 以方便描述:
<div id="component-1001" ...></div>
让我们给ext组件添加一些样式苏醒,以方便我们看到这个组件:
new Ext.Component({ cls: 'green-box',height: 60, width: 300 });
.green-box {
background-color: #fec;
border: 2px solid #5a7;
border-radius: 5px;
box-shadow: 2px 2px 2px #bbb;
padding: 5px;
}
我们在ext组件中添加的这些属性会生成如下的html元素样式:
<div id="component-1001" class="green-box ..." style="height: 60px; width: 300px;" ...></div>
现在以这个组件为本例子的基础,让我们开始添加自己的html:
html属性配置
简单粗暴, 我们可以通过配置html字符串来将我们的html注入到ext组件:
new Ext.Component({html: 'Some <b>HTML</b> content', ... });
生成的html如下:
<div id="..." class="green-box x-component x-component-default" ...>
Some <b>HTML</b> content
</div>
现在静态注入的html已经很好的执行了,我们还可以通过组件的update方法来替换html的内容:
var summary = new Ext.Component({html: 'Some <b>content</b>', ... });
new Ext.button.Button({
...
handler: function() {
summary.update('Some slightly different <b>content</b>');
} });
点击按钮, summary中的html会改变:
<div id="..." class="green-box x-component x-component-default" ...>
Some slightly different <b>content</b>
</div>
可是,使用html配置项我们只能改变组件里面的内容,如果我们想要改变组件外部的el本身,就得通过别的途径来实现了。
autoEl属性
我们可以通过配置autoEl属性来改变组件外部的el元素:
new Ext.Component({ autoEl: 'form', ... });
它看起来和刚才的例子很相像,但是生成的html却改变了(原来是个div,现在是个form):
<form id="..." class="green-box x-component x-component-default" ...></form>
通过给autoEl配置object对象,我们还可以改变组件el的其他结构。比如,我们可以添加一些简单属性给这个html:
new Ext.Component({
autoEl: {
href: 'javascript:alert(%22Clicked!%22)',
html: 'Click Me!',
tag: 'a'
}
});
这时,生成的html如下:
<a href="javascript:alert(%22Clicked!%22)" ...>Click Me!</a>
autoEl实质上是作为一个DomHelper来渲染的,因此它能接受所有DomHelper的配置项;比如通过cn来创建子元素:
new Ext.Component({
...
autoEl: {
cn: [
'Some ',
{tag: 'b', cn: 'HTML'},
' content'
]
}
});
<div ...> Some <b>HTML</b> content </div>
虽然autoEl很好很强大,但是它也有缺陷:它很难通过参数配置,并且代码可读性很差。如果你需要添加一个内容生动的ext组件,使用模板将是更好的选择。
tpl 和 data 属性
这两个属性需要同时使用。tpl提供一个html模板(XTemplate 语法),data为模板提供渲染数据。
通俗地讲, tpl就像声明了一个类,而data就如同类的实例。下面我们通过一个简单的例子来演示这两个属性的使用:
new Ext.Component({
...
tpl: '{name} is {age} years old and lives in {location}',
data: {
age: 26,
location: 'Italy',
name: 'Mario'
}
});
<div ...> Mario is 26 years old and lives in Italy </div>
和html属性一样,我们可以通过ext组件的update方法来改变组件的内容,所不同的是,这次传递的参数是data对象而不是html字符串:
var summary = new Ext.Component({
...
tpl: '{name} is {age} years old and lives in {location}',
data: {
age: 26,
location: 'Italy',
name: 'Mario'
}
});
new Ext.button.Button({
...
handler: function() {
summary.update({
age: 7,
location: 'Japan',
name: 'Aimee'
});
}
});
XTemplates 拥有丰富而强大的语法,它比精确的数据有更好的表现。完整的template描述超出了本文的范畴,但下面的例子可以让人领会到template的功能,它颜色了如何通过数组数据来生成html列表:
new Ext.Component({
...
data: ['London', 'Paris', 'Moscow', 'New York', 'Tokyo'],
tpl: [
'<ul>',
'<tpl for=".">',
'<li>{.}</li>',
'</tpl>',
'</ul>'
]
});
生成的html如下:
<div ...>
<ul>
<li>London</li>
<li>Paris</li>
<li>Moscow</li>
<li>New York</li>
<li>Tokyo</li>
</ul>
</div>
注意:现在<ul>依然包含在Ext组件的主元素<div>中, 如果我们想去掉<div>可以用前面提到的autoEl配置项将Ext组件的主元素转换为<ul>,并去掉模板中的<ul>元素:
new Ext.Component({
...
autoEl: 'ul',
data: ['London', 'Paris', 'Moscow', 'New York', 'Tokyo'],
tpl: [
'<tpl for=".">',
'<li>{.}</li>',
'</tpl>'
]
});
转码 (HTML Encoding)
默认情况下,XTemplates不会对html的值进行转码(类似直接将值拼接到html中--译者注);但是我们在XTemplates中使用Ext.util.Format.htmlEncode就可以轻易将值进行转码:
new Ext.Component({
...
tpl: '<b>Email:</b> {email:htmlEncode}',
data: {
email: 'John <john@example.com>'
}
});
在这个例子中,如果不对email进行转码,那么email值中的<...>将不会正确显示。
targetEl 属性
Ext的大部分复杂组件如panels和windows, 通过html属性和tpl属性配置的html内容并没有直接注入到Ext组件的el中,这样做是为了防止它们的header和toolbar等元素被body元素替换掉:
new Ext.panel.Panel({
...
bodyPadding: 10,
title: 'Title',
tpl: 'Some <b>{lang}</b> content',
data: {
lang: 'HTML'
}
});
这里渲染的html元素就被称做targetEl。稍后我们将看到如何在自定义组件中改变targetEl。
需要说明的是autoEl依然承担着配置组件外部el的功能,它不受targetEl的影响。
小结
现在我们已经了解了如何使用Ext组件创建简单的html页面:
- 使用autoEl属性配置最外层的html元素;
- 使用html属性配置简单的html内容;
- 使用tpl + data来生成动态html内容。
但是,创建html页面只是工作的第一步,下面三节我们将讲解Ext组件之间交互常用的技术。
事件 Events
让我们给组件添加一个click事件。下面这个例子是添加事件的基本方式,很容易理解:
var clickCmp = new Ext.Component({
...
count: 0,
html: 'Click Me',
listeners: {
// 给组件的主元素el添加一个事件监听
el: {
click: function() {
clickCmp.count++;
clickCmp.update('Click count: ' + clickCmp.count);
}
}
}
});
例子中关键的一点是:listener被注册到了Ext组件对象的el上而不是组件对象本身。组件没有绑定click监听事件所以上面的例子还不能正常工作。例子中有一个关键问题是,这个click事件只是映射到了Ext组件对象上,但在这个闭包证并没有真正被使用。
注册监听事件的规范方式是重写initEvents来注册事件。下面这个例子中我们自定义了一个Ext组件,这个组件支持用handler属性注册click事件(类似button的handler--译者注):
Ext.define('ClickComponent', {
extend: 'Ext.Component',
initEvents: function() {
this.callParent();
// Listen for click events on the component's el
this.el.on('click', this.onClick, this);
},
onClick: function() {
// Fire a click event on the component
this.fireEvent('click', this);
// Call the handler function if it exists
Ext.callback(this.handler, this);
}
});
我们可以像下面的方式来使用事件:
new ClickComponent({
...
count: 0,
html: 'Click Me',
handler: function() {
this.count++;
this.update('Click count: ' + this.count);
}
});
我们在自定义组件的onClick方法中还触发了click事件,这是Ext组件的click事件反作用到了el上, 我们在例子中没有用到;理解这两种事件的区别很重要。
事件委派 Event Delegation
使用事件委派和一些css, 我们就很容易为一个列表添加一些交互动作。下面这个例子有一些Ext组件的高级应用,我们要一点点消化:
new Ext.Component({
...
autoEl: 'ul',
data: ['London', 'Paris', 'Moscow', 'New York', 'Tokyo'],
listeners: {
// Add the listener to the component's main el
el: {
// Use a CSS class to filter the propagated clicks
delegate: '.list-row',
click: function(ev, li) {
// Toggle a CSS class on the li when it is clicked
Ext.fly(li).toggleCls('list-row-selected');
}
}
},
tpl: [
'<tpl for=".">',
'<li class="list-row">{.}</li>',
'</tpl>'
]
});
.list-row {
border: 1px solid #f90;
border-radius: 5px;
cursor: pointer;
list-style: none outside;
padding: 5px;
}
.list-row-selected {
background-color: #f90;
}
显示效果如下:
生成的html如下:
<ul id="..." ...>
<li class="list-row">London</li>
<li class="list-row">Paris</li>
<li class="list-row">Moscow</li>
<li class="list-row">New York</li>
<li class="list-row">Tokyo</li>
</ul>
当点击<li>时,样式list-row-selected就会添加到点击的<li>上。这就类似于在Ext组件的el上(在本例中即<ul>)添加了一个click事件,但是我们不想监听<ul>的事件,于是我们使用事件冒泡的特性将click事件作用到<li>上,为了实现这个目的,在Ext中我们使用delegate 配置项来实现。理论上我们可以用标签名字“li”作为delegate的选择器,但是css class名称是一种更好的实践。例子中的<li>都有一个名为“list-row” 的css class,我们可以使用它。
配置delegate: '.list-row' 有两方面作用:
如果click事件不是发生在 <li class="list-row">节点或<li class="list-row">的子孙节点,事件会被忽略。
传递给监听函数的参数将会是<li class="list-row">节点,哪怕是<li>还包含子节点,传递给监听函数的参数节点也是由<li>环绕。
和前面提到的例子一样,自定义组件的delegate事件可以通过重写initEvents函数来实现。
数据视图 DataView
如果我们想更深入地演化前面的list的例子,我们可以使用DataView来实现。Ext.view.View类常被称作DataView,它可以自动绑定到store。有关DataView的更详细介绍不在本文讨论的范围, 下面的例子演示了如何通过DataView实现列表:
new Ext.view.View({
...
autoEl: 'ul',
itemSelector: '.list-row',
overItemCls: 'list-row-over',
selectedItemCls: 'list-row-selected',
simpleSelect: true,
// An ExtJS store or store config
store: {
data: [{city: 'London'}, ...],
fields: ['city']
},
tpl: [
'<tpl for=".">',
'<li class="list-row">{city}</li>',
'</tpl>'
]
});
这里有一个非常重要的设置项即itemSelector, 它的功能非常类似于我们前面提到的delegate; 它将DOM元素与store的数据记录对应起来,这样可以通过点击列表元素来选择数据。
renderTpl and renderData
renderTpl & renderData两个配置项功能类似 tpl & data,唯一不同的是renderTpl & renderData只在渲染组件时执行一次。renderTpl 和 tpl两个模板都能创建组件的html元素,通常用renderTpl创建的html元素被认为是组件内部标记(用来定义组件的框架或结构--译者注)而不是组件内容标记(组件显示的动态内容----译者注)。比如前面我们了解了panel组件中tpl的使用,tpl渲染的panel的动态内容部分;panel组件的类定义其实还有个 renderTpl, renderTpl定义了panel组件的框架,包括header、toolbars、body等等。tpl的定义既可以在Ext组件类中定义,也可以在组件实例中定义,但 renderTpl只能在组件类中定义。
baseCls属性
baseCls是Ext组件样式的基础,它既是添加在Ext组件外部el上的样式名称(class)又是Ext组件主要html元素上样式名称的前导符。创建组件主要html元素和他们的css class的工作通常由 renderTpl来完成。
有些Ext组件定义了他们特有的baseCls样式, 比如button组件 使用x-btn, panel组件使用x-panel, window组件使用x-window等。这些样式在Ext组件库中被广泛使用,它们很难在应用程序代码中被恰当使用。如果需要自定义组件的样式,你可以设置 baseCls来防止样式冲突。比如如果你想完全清除button组件的默认样式,你可以设置button的 baseCls。
设置baseCls一定要谨慎再谨慎。Ext组件的正常运行有可能依赖某些样式属性的特定值,如果这些值被改变有可能会带来麻烦,特别是你想升级Ext版本的时候。如果你只期望改变组件的一小部分样式,应该考虑别的方式。
childEls
Ext组件对象存储了一些自身子html元素引用,这就意味着你不用遍历html节点就可以直接使用这些html对象。组件渲染完成后el属性存储了组件对象的外部html节点的引用, childEls用来配置需要存储引用的子节点。比如panel组件对象就有两个这样的属性:el和body; button对象有btnIconEl和btnInnerEl分别用来修改button的图标和显示文本。配置了引用的组件对象不能随意的修改,因为被存储了引用的html元素不能被删除。因此在childEls配置引用的html元素通常由renderTpl创建而不是tpl创建(ext5中在tpl中创建会报错--译者注)。
如果组件的html元素需要存储引用,在renderTpl中定义html元素的时候通常会给这些html元素指定id, id的值通常是 组件id + html元素名称, 这样做是方便组件渲染完成后能够快速遍历来创建对象属性。
下面的组件对象将会创建一个名为body的对象属性。
Ext.define('TestChildEls', {
extend: 'Ext.container.Container',
childEls: [
'body'
],
renderTpl: [
'<div id="{id}-body" data-ref="body" ...>{bodyCls}</tpl>',
...,
'</div>'
]
});
Putting It All Together
下面这个例子有点复杂。我们将继续上面提到的面板的例子,继续完善,将看到如下效果:
我们将Ext组件实现类定义分两部分:首先定义一个简单直观的基类,包含header和body两个区域和适当的样式定义,现在这个组件中还没有具体的人物简介信息。
// Note: This is correct for ExtJS 4.1 and 4.2. This page
// uses 4.0 so requires a slightly modified version.
Ext.define('TitledComponent', {
extend: 'Ext.Component',
baseCls: 'titled-component',
childEls: ['body', 'headerEl'],
renderTpl: [
'<h4 id="{id}-headerEl" class="{baseCls}-header">{header:htmlEncode}</h4>',
'<div id="{id}-body" class="{baseCls}-body">{% this.renderContent(out, values) %}</div>'
],
getTargetEl: function() {
return this.body;
},
// Override the default implementation to add in the header text
initRenderData: function() {
var data = this.callParent();
// Add the header property to the renderData
data.header = this.header;
return data;
},
setHeader: function(header) {
this.header = header;
// The headerEl will only exist after rendering
if (this.headerEl) {
this.headerEl.update(Ext.util.Format.htmlEncode(header));
}
}
});
然后再定义一个子类,在子类中定制一个人物简介的模板:
Ext.define('BiographyComponent', {
extend: 'TitledComponent',
xtype: 'biography',
header: 'Biography',
tpl: '{name} is {age:plural("year")} old and lives in {location}',
// Override update to automatically set the date in the header
update: function(data) {
this.callParent(arguments);
this.setHeader('Biography updated at ' + ...);
}
});
下面我们创建组件实例时,只需要传递数据:
var summary = new BiographyComponent({
data: {
age: 26,
location: 'Italy',
name: 'Mario'
}
});
添加一个按钮来更新人物简介信息:
new Ext.button.Button({
...
handler: function() {
// Update the body content via the tpl
summary.update({
age: ...,
location: ...,
name: ...
});
}
});
生成的html非常简单:
<div id="biography-1035" class="titled-component ..." ...>
<h4 id="biography-1035-headerEl" class="titled-component-header">Biography</h4>
<div id="biography-1035-body" class="titled-component-body">Mario is ...</div>
</div>
虽然样式不太令人满意,但组件的确是显示出来了。现在我们将样式绑定到在TitledComponent中定义的baseCls上:
.titled-component {
background-color: #fec;
border: 2px solid #5a7;
border-radius: 5px;
box-shadow: 2px 2px 2px #bbb;
display: inline-block;
}
.titled-component-body {
margin: 10px;
}
.titled-component-header {
background-color: #5a7;
color: #fff;
font-weight: 700;
margin: 0;
padding: 5px 10px;
text-align: center;
}
现在我们完成了自定义组件的大部分工作,现在我们快速回顾一下:
-
xtype:'biography' xtype会作为组件实例的id(“biography-1035”)的前导符,这个组件的Id同时也会作为组件外部元素el的id,我们在renderTpl中也用了两次。
- baseCls: 'titled-component' 这个样式被加在了组件外部的el上,注意一下这个样式是如何作为组件内部html元素的样式的前导符使用的。
-
childEls: ['body', 'headerEl'] chidlEls配置的两个引用在组件渲染后被创建, 对应的dom元素通过id查找。body元素在 getTargetEl方法中使用,headerEl元素在方法setHeader中被使用。
-
renderTpl的数据由initRenderData方法提供。initRenderData的默认实现(在Ext.util.Renderable中--译者注)已经包含了id和baseCls,我们只需要将 header属性追加上去。
- 在renderTpl中有个奇怪的标记“{% this.renderContent(out, values) %}”,这个标记内容应该显示在targetEl中用来注入组件内容。在 ExtJS 4.0中targetEl可能会在模板(template)中留下空白,组件内容部分会被插入到已经渲染到dom的targetEl后面。这样会有严重的性能问题,从ExtJS 4.1开始组件内容部分完全交给模板(template)渲染。如果你继承自容器(container)那么就将这部分内容替换为“{% this.renderContainer(out, values) %}”。
- getTargetEl 返回body元素的引用, 这个引用由 childEls 配置生成。只有有了这个方法,组件的update方法才可以更新到正确的dom元素。注意这个update方法不能与setHeader方法中调用的update方法混淆,后者是headerEl元素的方法而不是我们定义的组件的方法。
- setHeader方法更新header的内容,这种重写方式即可以在组件渲染前调用也可以在组件渲染后调用。
也许你不需要写这种底层的Ext组件,了解Ext组件的机制将有助于你更好的阅读ext源码。TitledComponent类的定义使用了Ext组件定义的典型风格,而BiographyComponent可以看做是应用程序类的典型。
原文地址: http://skirtlesden.com/articles/html-and-extjs-components
- 大小: 656 Bytes
- 大小: 2.4 KB
分享到:
相关推荐
### ExtJs组件类的对应表解析 #### 引言 ExtJs是一款强大的JavaScript框架,用于构建复杂的、数据密集型的应用程序。它提供了大量的组件和工具,使得开发者能够快速地创建美观且功能丰富的用户界面。本文将详细...
通过以上步骤,你不仅能够成功导入并运行ExtJS组件的示例,还能在Eclipse这个熟悉的开发环境中进行学习和实践。了解每个组件的用法和配置,是掌握ExtJS的关键。记住,实践是检验知识的最好方式,动手尝试并不断试验...
- 对于ExtJS,Spket可以识别和理解ExtJS组件和API,提供实时的代码提示,帮助开发者快速编写代码。 - 还包括模板、调试工具和集成版本控制系统等其他特性,为ExtJS开发提供了一个全面的工作环境。 3. **Ext包管理...
开发者可以根据实际需求,通过调整配置、编写事件处理器以及利用EXTJS的其他组件和工具,打造出满足各种需求的文件上传功能。同时,要确保在使用过程中充分考虑安全性,确保应用的稳定性和用户数据的安全。
1. **Portlets**:Portlets是Portal中的基本单元,它们是可配置的、可拖动的、可调整大小的组件,可以包含任何EXTJS组件,如表格、面板、按钮等。Portlets之间可以通过拖放操作进行重新排列。 2. **Portal Column**...
1. **EXTJS组件化编程**:理解EXTJS的组件模型,如何创建自定义组件,以及如何在应用中嵌入和配置这些组件。 2. **SWFUpload使用**:学习SWFUpload的基本用法,如设置参数、监听事件、处理回调函数等。 3. **Flash...
EXTJS 是一个强大的JavaScript前端框架,它主要用于构建富客户端应用,提供丰富的用户界面组件和灵活的可定制性。EXTJS 的核心在于其组件化的架构,允许开发者构建复杂的UI布局和功能丰富的应用程序。以下是对EXTJS...
3. 自定义组件和插件的开发,提升代码的复用性和可维护性。 4. 布局管理器的运用,确保组件在页面上的正确展示。 5. 将外部API(如YouTube API)集成到ExtJS组件中的技巧。 通过深入研究这个示例,开发者可以进一步...
它强调了JavaScript面向对象编程(OOP)在Extjs框架中的应用,并通过实例演示了如何使用各种组件和布局来创建复杂的用户界面。本教程通过递进式的结构,使读者从基础知识起步,逐步掌握Extjs的高级应用,最终能够...
ExtJS4是一款强大的JavaScript框架,用于构建富客户端的Web应用程序。在ExtJS4中实现多附件上传功能,我们可以利用其...通过理解这些知识点,你不仅可以构建一个功能完备的上传功能,还能提升对ExtJS组件化开发的理解。
开发者可以通过这个示例了解如何在ExtJS组件中嵌入KindEditor,设置编辑器的属性,如高度、宽度、样式,以及如何处理编辑器的事件,如文本改变、提交等。 集成步骤大致如下: 1. 引入ExtJS和KindEditor的库文件:在...
1. **嵌入ECharts图表到ExtJS组件**:在ExtJS的Panel或其他容器组件中,通过内联HTML或使用`Ext.util.CSS`来引入ECharts的JavaScript和CSS资源。然后,在组件的`rendered`事件中初始化ECharts实例,设置相应的配置项...
3. **ExtJS 插件**:ExtJS是一个用于创建富客户端Web应用的JavaScript框架,提供了大量的组件和布局管理。`tk.eclipse.plugin.htmleditor_2.2.0.jar`可能是专门为Eclipse定制的ExtJS插件,它扩展了基本的HTML编辑器...
它提供了大量的组件和功能,包括表格、树形视图、图表、菜单、窗口等,以及一个强大的数据绑定系统,使得开发复杂的交互式用户界面变得更加便捷。在本案例中,我们将讨论的是ExtJS中的一个特定组件——上传组件,它...
它们展示了如何使用EXTJS组件和API创建实际的Web应用,涵盖了各种功能和场景,如数据绑定、异步请求、图表绘制等。开发者可以通过运行和修改这些示例,来加深对EXTJS的理解。 在EXTJS 3.0.0的压缩包中,可能包含...
6. **表单处理**:强大的表单组件和表单处理能力,支持各种输入类型,以及验证和提交功能。 7. **拖放功能**:内置的拖放API允许用户轻松创建可拖放的元素,增强了用户体验。 8. **国际化**:支持多语言,包括中文...
ExtJS的UploadDialog组件通常基于Ext.window.Window创建,包含一个或多个文件输入字段,以及上传按钮和取消按钮。用户可以选择文件后,点击上传按钮将数据发送到服务器。它还可能具有进度条,用于显示上传进度。 2...