Ext js 提供了一个简便的方法来处理DOM。我们可以创建节点, 修改样式,添加事件监听器,和创建漂亮的动画。而且可以不用管各浏览器的兼容性。
用来处理DOM节点的类为Ext.dom.Element类。这个类是包装了html原生节点,并且提供了许多的方法和实用工具来操作节点。
直接操作DOM被认为是一个非常差的实践,在index文件中,不应该有任何DOM 标记,我们在这里的举的例子,只是为了说明DOM操作的原理
获得元素
Ext.get
Ext.get方法,它封装在Ext.dom.Element类中, 用来根据ID查找DOM元素,并返回一个Ext.Element元素
// by id
var el = Ext.get("my-div");
// by DOM element reference
var el = Ext.get(myDivElement);
<!doctype html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title>Extjs - Loader</title>
<link rel="stylesheet" type="text/css" href="../ext-5.1.1/build/
packages/ext-theme-neptune/build/resources/ext-theme-neptune-all.css">
<script src="../ext-5.1.1/ext-all.js"></script>
<script src="../ext-5.1.1/build/packages/ext-theme-neptune/build/exttheme-
neptune.js"></script>
<script type="text/javascript">
Ext.onReady(function(){
var mymainDiv = Ext.get('main');
var mysecondDiv = Ext.dom.Element.get('second');
});
</script>
</head>
<body style="padding:10px">
<div id="main"></div>
<div id="second"></div>
</body>
</html>
通常我们获得一个元素是使用 Ext.get, 这是Ext.dom.Element.get的一个快捷方式
注意,我们不需要使用CSS选择器那样,传入#
返回的两个元素,都是Ext.dom.Element的实例,然后可以使用setStyle方法,设置它的样式
div.setStyle({
width: "100px",
height: "100px",
border: "2px solid #444",
margin: "80px auto",
backgroundColor: "#ccc"
});
//添加和删除样式
div.addCls("x-testing x-box-component");
div.removeCls("x-testing");
还有一些其它操作元素的方法,比如动画
div.fadeOut()
.fadeIn({
duration:3000
});
var el = Ext.get("my-div");
// no animation
el.setWidth(100);
// default animation
/*
Option Default Description
--------- -------- ---------------------------------------------
duration 350 The duration of the animation in milliseconds
easing easeOut The easing method
callback none A function to execute when the anim completes
scope this The scope (this) of the callback function
*/
el.setWidth(100, true);
//custom animate
// Element animation options object
var opt = {
duration: 1000,
easing: 'elasticIn',
callback: this.foo,
scope: this
};
// animation with some options set
el.setWidth(100, opt);
选择子元素
Ext.dom.Element的实例可以通过css选择器选择子孙节点, 这里有三个方法
* query
* selectNode
* select
这三个方法都可以接收有效的CSS选择器,应为它们的底层都是Javascript的querySelectorAll, 它们之前的不同在于,返回的类型
可以能过以下的代码,返回一个HTMLELement实例的数组
element.query('.foo');
也可以通过设置 asDom参数为false, 则返回的类型为Ext.dom.Element
element.query('.foo', false);
如果想得到第一个匹配的HTMLElement,则使用selectNode方法
element.selectNode('.foo');
同样,如果想返回的Ext.dom.Element, 设置asDom为false.
element.selectNode('.foo', false);
select方法用于返回类型为CompositeElementLite 或者CompositeElement. 它们都是元素的集合类型,可以将Ext.dom.Element的方法应用于组中。两者的不同在于CompositeElementLite是一个HTMLElement的实例,而CompositeElement是一个Ext.dom.Element类型集合。
//CompositeElementLite
element.select('.foo');
//CompositeElement
element.select('.foo', true);
对于query方法,也可以不用应用在Ext.dom.Element上,比如,查找在document下的,选择器为’.foo’的HTMLElements数组,可以简单的它document对像包装为Ext.dom.Element实例。
Ext.fly(document).query('.foo');
Ext.query
Ext JS允许我们查找某一类的DOM节点,查找引擎支持CSS3选择器,或者路径xpath选择器. 它返回找到的elements组成的数组(HTMLElement[] 或者 Ext.dom.Element[]),如果没有找到,则返回一个空的数组。
负责的这个类为Ext.dom.Query类。这个类包含了许多用于搜索的方法.
Ext.dom.Query 是一个单例类,所以我们不需要创建一个新的实例用来查找 DOM元素
在下面的代码中,myCustomComponent.getEl().dom作为上下文搜索的根节点。Ext.query将在这个根节点下查找,并且返回一个包含类为’oddRow’
var someNodes = Ext.query('.oddRow',
myCustomComponent.getEl().dom); //.dom表示获得HTMLElement
Ext.select
CSS/XPath选择器,返回单个的CompositeElement, CompositeElement表示一个elements的集合.
CompositeElement包含filter, iterate 以及集体类的方法
var rows = Ext.select('div.row'); ////Matches all divs with class row
rows.setWidth(100);
//也可以在单行中使用
Ext.select('div.row').setWidth(100);
通过逗号分隔,我们可以使用多个选择器
Ext.select('div.row, span.title'); //Matches all divs with class row and all spans with class title
默认情况下, select方法是查找整个DOM树。我们可以给它指定一个根元素,只查找这个元素下,符合条件的元素
//先查找ID为myEl的元素
Ext.get('myEl').select('div.row');
//也可以使用以下的方法
Ext.select('div.row', true, 'myEl');
查找一个class为.row, 并且属性中表含了title=bar的div, 并且返回找到的第一个子元素
Ext.select('div.row[title=bar]:first')
Ext.ComponentQuery
允许你通过ID, xtype, 和属性查找一个组件。你可以在全局(Ext.ComponentManager)或者指定的根组件(Ext.container.Container)中查找
http://docs.sencha.com/extjs/6.0.2-classic/Ext.ComponentQuery.html
以下的代码,是根据xtype,返回所有的button组件.
Ext.ComponentQuery.query('button');
根据ID查找
Ext.ComponentQuery.query('#foo');
以下的代码,返回xtype的类型为button, title为my button的元素
Ext.ComponentQuery.query("button[title='my button']");;
//or
parent.query('textfield[title=my button]');
也可以嵌套选择器
Ext.ComponentQuery.query('formpanel numberfield'); // form页板下的numberfield
以下的代码,返回匹配元素的第一个子直接子元素,如果没有找到,返回null
parent.child('button[itemId=save]');
同样,我们也可以使用nextNode, up, down, previousSibling等方法.
Ext.fly()
fly ( dom , named ) ,它包装一个dom元素为Ext.dom.Element,但不会保存这个元素的引用,适用于对一个元素的一次操作,后续不在使用,可以提高整个程序的效率.
<input type = 'text' id = 'studentName'>
Ext.fly('studentName').set({'value' : 'John'});
创建元素
var myDiv1 = Ext.get('div1');
myDiv1.createChild('Child from a string');
myDiv1.createChild('<div>Element from a string</div>');
以上都是通过字符串的作为参数,将字符串以innerHTML的方式,传递给myDiv1. 这种方式不简维护代码和管理,Extjs为我们提供了配置对像的方式
createChild ( config , [insertBefore] , [returnDom] ) : Ext.dom.Element / HTMLElement
通过传递的DomHelper创建一个元素,如果有传递insertBefore, 则将新创建的元素在它之前插入,否则为元素的末尾。
* config: Object
DomHelper元素配置对像,如果没有指定tag(e.g., {tag: ‘input’}), 则自动生成div.
* insertBefore: HTMLElement(optional)
指定插入元素在insertBefore这个元素之前
* returnDom: Boolean(optional)
如果为true, 则返回Dom节点,而不是Element. 默认为false;
通过代码说明
myDiv1.createChild({
tag : 'div',
html : 'Child from a config object'
});
如果想要插入嵌套标签,可以如下
myDiv1.createChild({
tag : 'div',
id : 'nestedDiv',
style : 'border: 1px dashed; padding: 5px;',
children : {
tag : 'div',
html : '...a nested div',
style : 'color: #EE0000; border: 1px solid'
}
});
如果想在第一行位置插入
//insertFirst ( el , [returnDom] ) : Ext.dom.Element / HTMLElement
myDiv1.insertFirst({
tag : 'div',
html : 'Child inserted as node 0 of myDiv1'
});
指定位置插入
myDiv1.createChild({
tag : 'div',
id : 'removeMeLater',
html : 'Child inserted as node 2 of myDiv1'
}, myDiv1.dom.childNodes[3]);
Removing child nodes
删除一个元素,要比添加一个元素简单,只需要先找到这个元素,在调用它的remove方法。为了说明,我们先创建段HTML:
<div id='div1' class="myDiv">
<div id='child1'>Child 1</div>
<div class='child2'>Child 2</div>
<div class='child3'>Child 3</div>
<div id='child4'>Child 4 </div>
<div>Child 5</div>
</div>
删除第一个元素
var myDiv1 = Ext.get('div1');
var firstChild = myDiv1.down('div:first-child');
firstChild.remove();
在上面的代码中 down ( selector , [returnDom] ) : HTMLElement / Ext.dom.Element 会根据css选择器(选择器不应该包含id), 会在父元素的子孙元素查找。
也可以删除最后一个元素
var myDiv1 = Ext.get('div1');
var lastChild = myDiv1.down('div:last-child');
lastChild.remove();
Using templates and XTemplates
Ext.Template类是一个非常强大的核心工具,允许你以占位符的方式创建一个多级的DOM。一旦创建完成,你可以多次重覆使用。传递给模板的数据通过占位符填充, 大部分 UI widget都使用了模板,比如grid panel, data view, and ComboBox
使用template
首先我们创建一个简单的template
var myTpl = Ext.create('Ext.Template' , "<div>Hello {0}.</div>");
myTpl.append(document.body, ['Marjan']); //target: document.body
myTpl.append(document.body, ['Michael']);
myTpl.append(document.body, ['Sebastian']);
在这个例子中,我们先创建了个 Ext.Template, 并且传递一个带有占位符({})的div字符串. 在这个例子中,我们的占位符为一个数字,并传递的值为一个数组。Template 也可以解构一个对像,如下所示
var myTpl = Ext.create('Ext.Template', [
'<div style="background-color: {color}; margin: 10px;">',
'<b> Name :</b> {name}<br />',
'<b> Age :</b> {age}<br />',
'<b> DOB :</b> {dob}<br />',
'</div>'
]);
myTpl.compile();
myTpl.append(document.body,{
color : "#E9E9FF",
name : 'John Smith',
age : 20,
dob : '10/20/89'
});
myTpl.append(document.body,{
color : "#FFE9E9",
name : 'Naomi White',
age : 25,
dob : '03/17/84'
});
在第一步,我们创建的模块不在是一个长字符串,而是一个数组,利用美观。在第二步的编译,可以消除正则表达式的开发,提高模块合并数据的速度。在这两段代码里,我们其实不用编译,因为只有针对大型的Application才能体现它的效果。
对于template,我们使用了两种不同的html结构。但如果你要填充的是一个对像数组? 比如,Ajax请求,返回了一个数据对像数组, 然后你需要为这个数组的每一个数据对像应用一个template,一种方法是使用 for loop或者Ext.each方法,在调用我们上面的template.
另一种是使用XTemplates代替,会使得代码更加清晰。
Looping with XTemplates
XTemplates可以被用于单个的数据对像,但它更易于处理数据对像数据。XTemplate 继承于Template, 并且提供了更多的方法。 如下所示
var tplData = [{
color : "#FFE9E9",
name : 'Naomi White',
age : 25,
dob : '03/17/84',
cars : ['Jetta', 'Camry', 'S2000']
},{
color : "#E9E9FF",
name : 'John Smith',
age : 20,
dob : '10/20/89',
cars : ['Civic', 'Accord', 'Camry']
}];
var myTpl = Ext.create('Ext.XTemplate', [
'<tpl for=".">',
'<div style="background-color: {color}; margin: 10px;">',
'<b> Name :</b> {name}<br />',
'<b> Age :</b> {age}<br />',
'<b> DOB :</b> {dob}<br />',
'</div>',
'</tpl>'
]);
myTpl.compile();
myTpl.append(document.body, tplData);
在XTemplate初始化时,我们使用了一个自定义的tpl标签, 并且设置了for属性, 值为”.”. tpl标签类似于逻辑或者行为标签,它有两个值,for and if, 它改变XTemplate生产html代码段的方式。 “.” 表示遍历传递给XTemplate的数组。
Advanced XTemplate usage
var myTpl = Ext.create('Ext.XTemplate', [
'<tpl for=".">',
'<div style="background-color: {color}; margin: 10px;">',
'<b> Name :</b> {name}<br />',
'<b> Age :</b> {age}<br />',
'<b> DOB :</b> {dob}<br />',
'<b> Cars : </b>',
'<tpl for="cars">',
'{.}',
'<tpl if="this.isCamry(values)">',
'<b> (same car)</b>',
'</tpl>',
'{[ (xindex < xcount) ? ", " : "" ]}',
'</tpl>',
'<br />',
'</div>',
'</tpl>',
{
isCamry : function(car) {
return car === 'Camry';
}
}
]);
myTpl.compile();
myTpl.append(document.body, tplData);
在遍历cars循环内,我们使用字符串 “{.}”, 它表示当前cars数组的当前值。在这里为car的名字。
this.isCamry定义在整个XTemplate的最后,它通过一个对像的方式,会传递给XTemplate的构造函数。这就是为什么我们可以在if条件语句中调用this.isCamery。
在XTemplate中的 {[…JS code …]}被解析为通用的Javascript代码。它可以访问XTemplate中的本地变量,在这里,xindex表示当前的循环值, xcount表示数组长度。