Working with the DOM

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表示數組長度。

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章