Ext Core是一款具有多項功能的輕型JavaScript庫,基于MIT許可為大家服務(wù)。在Ext Core中有許多激賞的功能,在倡導快速Web開(kāi)發(fā)的同時(shí)也本著(zhù)高質(zhì)量、可伸縮性的代碼的指導思想進(jìn)行著(zhù)。Core庫對DOM操作、Ajax、事件、動(dòng)畫(huà)、模板、00機制等的任務(wù)都有相應的支持。Core庫基于MIT方式發(fā)布,無(wú)論是一般的動(dòng)態(tài)頁(yè)面和簡(jiǎn)單的應用程序都可選擇使用。
可在本頁(yè)面下載,也可以到Ext Core主頁(yè)面查找最新的版本來(lái)下載。
送到手上的Ext Core有調試的版本和供發(fā)布時(shí)的產(chǎn)品版本。產(chǎn)品版本已經(jīng)作壓縮(就是消除空白符、硬回車(chē)和注釋?zhuān)┖突煜奶幚恚ㄋ芯植孔兞恐孛麨槎痰拿Q(chēng),使用YUI Compressor)。在開(kāi)發(fā)階段,你應使用的是-debug版本,這樣才會(huì )看到未混淆過(guò)的錯誤信息。
要引入Ext Core的開(kāi)發(fā)版本,這樣引入JavaScript文件就可以了:
<script src="ext-core-debug.js"></script>要引入產(chǎn)品版本(壓縮并且gzipped后25kb),只需要省略掉“-debug”:
<script src="ext-core.js"></script>完事!Ext Core沒(méi)有相關(guān)的CSS文件。
完成Ext Core的加載之后,拿下面的代碼測試一下是否正確加載了:
Ext.onReady(function() { Ext.DomHelper.append(document.body, {tag: 'p', cls: 'some-class'}); Ext.select('p.some-class').update('Ext Core successfully injected');});本手冊的作者是Tommy Maintz、Aaron Conran、James Donaghue、Jamie Avins與Evan Trimboli。譯者根據基于GNU Free Documentation License許可的原版于2009.4.5初次釋放版本來(lái)翻譯,分設有簡(jiǎn)體中文和繁體中文(正體中文,格式是PDF)兩種版本。維護以上兩種中文的翻譯版本的是Ext中文站(ajaxjs.com),譯者主要是frank。文中許多部分取材于《Ext 3.x中文文檔》。鑒于《文檔》是frank與南宮小駿、善祥等諸多Ext愛(ài)好者之合力,特此說(shuō)明。
一份HTML文檔通常由大量的裝飾元素(markup)所組成。每當瀏覽器加載當前的html文檔,html文檔其中的每一個(gè)標簽都被翻譯為HTMLElement以構建裝飾樹(shù)的文件對象模型(Document Object Model,DOM)。你可以在瀏覽器的全局空間中找到一個(gè)稱(chēng)為document的變量,那個(gè)document就是DOM樹(shù)的對象。document記憶了當頁(yè)面加載完畢后而形成的每一份裝飾元素引用。
document對象有一個(gè)重要的方法getElementById,允許在每個(gè)瀏覽中獲取其中的HTMLElement對象。然而,直接操縱DOM來(lái)說(shuō)還有許多要注意的問(wèn)題。Ext Core實(shí)現了Ext.Element類(lèi)來(lái)封裝(Wrap around)各瀏覽器不同HTMLElement的對象。
Ext.Element占Ext Core庫的篇幅很大,其中方法就占據了大部份。因此我們將這些方法可分為下面幾類(lèi):
你可以使用Ext.get方法創(chuàng )建Ext.Element的實(shí)例,達到封裝普通的HTMLElement之目的。例如你有已一個(gè)id名為“myElementId”的元素,便可以這樣獲?。?/p>
var el = Ext.get('myElementId');用Firebug執行以下代碼后,觀(guān)察Ext.Element身上的方法有哪些。有一點(diǎn)要注意的就是,你正在觀(guān)察的是普通JavaScript對象,我意思是說(shuō)無(wú)所謂的public與private的方法,它們均有在此列出,若有疑問(wèn)可參考API文檔。
var el = Ext.get('myElementId');console.dir(el);
console.dir命令由Firebug提供,執行該可方便地列出某個(gè)對象身上有什么成員,這都是例于開(kāi)發(fā)者閱讀的形式顯示的。你換可以通過(guò)折疊某個(gè)子對象以了解其牽連的屬性。如圖,屬性顯示是黑色的,方法/函數是綠色的,構造器(constructors)或類(lèi)(class)就是紅色的?,F在我對id為myElementId的段落元素進(jìn)行操作:
var el = Ext.get('myElementId');el.addClass('error');這段代碼作用后段落的字體顏色就變?yōu)榧t色,頁(yè)面的CSS規則有error的樣式類(lèi),屬于error類(lèi)的元素就會(huì )有紅色效果:
.error { color: red;}下一小節(CSS類(lèi)與樣式)會(huì )簡(jiǎn)介關(guān)于處理元素的不同方式。
享元模式(Flyweight Design Pattern)是一種節省內存的模式,該模式的大概原理是建立單個(gè)全體對象然后不斷反復使用它。
Ext在啟動(dòng)的時(shí)候就創(chuàng )建了一個(gè)全局的Ext.Element對象專(zhuān)為Flyweight的設計服務(wù)。這個(gè)全局的Flyweight實(shí)例可以為Dom里面任何一個(gè)節點(diǎn)保存引用。要訪(fǎng)問(wèn)這種Flyweight的對象請使用Ext.fly方法。Ext新手可能會(huì )因Ext.get()與Ext.fly()兩者之間的用法而犯湖涂。
如果感覺(jué)這個(gè)Ext.Element元素是一直下去多次引用的,那么可以使用Ext.get方法;如果在一段時(shí)間內不需要存儲元素的引用,那么就使整個(gè)庫部共享的對象Flyweight的Ext.Element對象。通過(guò)Flyweight訪(fǎng)問(wèn)元素,用Ext.fly(/*元素id*/)的方法。
再如上面那段落,我們撤銷(xiāo)樣式。
Ext.fly('myElementId').removeClass('error');當執行這代碼,Ext就復用現有的享元對象,不一定要建立一個(gè)全新Ext.Element對象。fly方法較適合單行的、一次性的原子操作(atomic operation),就算你想將某個(gè)元素存儲起來(lái)也是無(wú)效的,因為其它代碼很有機會(huì )改變對象。例如,我們看看下面的代碼:
var el = Ext.fly('foo');Ext.fly('bar').frame();el.addClass('error');frame()是Ext.Element包中的動(dòng)畫(huà)方法,產(chǎn)生高亮的效果,你可以估計一下,有什么現象出現?
答案是id為bar的那個(gè)元素會(huì )產(chǎn)生frame效果隨后立即應用上error的CSS樣式效果,那foo id的元素可什么事情都沒(méi)有發(fā)生,這是由于指向Flyweight對象的el引用已經(jīng)被產(chǎn)生過(guò)frame效果的所使用。
el就是bar元素,這是關(guān)于Flyweight享元用法的重要內容,如果你想搞清楚Ext.fly方法的用途適宜再看看這部份的內容。
Ext.getExt.get()可接收這幾種類(lèi)型的參數,如HTMLElement,Ext.Element、字符型,返回的新實(shí)例。以下三種類(lèi)型如下例:
var el1 = Ext.get('elId'); // 接收元素idvar el2 = Ext.get(el1); // 接受Ext.Elementvar el3 = Ext.get(el1.dom); //接受HTMLElementExt.flyExt.fly在參數方面與Ext.get的完全相同,但其內置控制返回Ext.Element的方法就完全不同,Ext.fly從不保存享元對象的引用,每次調用方法都返回獨立的享元對象。其實(shí)區別在于“緩存”中,因為緩存的緣故,Ext.get需要為每個(gè)元素保存其引用,就形成了緩存,如果有相同的調用就返回,但Ext.fly沒(méi)有所謂的緩存機制,得到什么就返回什么,不是多次使用的情況下“一次性地”使用該元素就應該使用Ext.fly(例如執行單項的任務(wù))。
使用Ext.fly的例子:
// 引用該元素一次即可,搞掂了就完工Ext.fly('elId').hide();Ext.getDom送入String (id)、dom節點(diǎn)和Ext.Element的參數,Ext.getDom只會(huì )返回一個(gè)普通的dom節點(diǎn)。如下例:
// 依據id來(lái)查dom節點(diǎn)var elDom = Ext.getDom('elId'); // 依據dom節點(diǎn)來(lái)查dom節點(diǎn)var elDom1 = Ext.getDom(elDom); // 如果我們不了解Ext.Element是什么直接用Ext.getDom返回舊的dom節點(diǎn)好了function(el){ var dom = Ext.getDom(el); // 接下來(lái)干些事情……}通過(guò)學(xué)習markup裝飾部分,我們已經(jīng)曉得,裝飾與document的緊密聯(lián)系下如何透過(guò)Ext Core較簡(jiǎn)便地取得數據。但進(jìn)行document的布局又如何編排呢?是不是有一種方法可以控制布局也可以控制document的樣式呢?答案便是用Cascading Style Sheets (CSS)處理。CSS正是用來(lái)頁(yè)面可視化信息和布局的語(yǔ)言。Ext Core在方面真的是讓我們用戶(hù)感覺(jué)好使好用,易如反掌,——直接修改它就行了。
<style type="text/css">myCls { color: #F00;}</style>...<div type="myCls">您好!</div>
上一例中我們賦予div元素“您好”的文本和讓其顏色為紅色(#F00)。
我們已經(jīng)曉得Firebug,可以為我們帶來(lái)頁(yè)面開(kāi)發(fā)上的種種便利。凡頁(yè)面中的任意一元素上面右擊,選擇“Inspect Element”(檢測元素),彈出Firebug可以觀(guān)察到dom樹(shù)中真實(shí)情況,該元素是定義在哪里的。Dom樹(shù)右邊的面板就是對應該元素身上的樣式。

如果你未曾熟悉Firebug的話(huà),暫時(shí)放下這塊建議先學(xué)習一下它。它仿佛就是Web開(kāi)發(fā)的高級示波器!心血來(lái)潮地修改站點(diǎn)的樣式抑或是調試站點(diǎn)的樣式,“Inspect Element”功能都貢獻殊大?;氐紼xt中,我們看看Ext Core中有哪些方法是為修改CSS所服務(wù)的。
Ext.fly('elId').addClass('myCls'); // 加入元素的'myCls'的樣式
//為元素添加'myCls'在所有側邊元素上刪除'myCls'樣式// all sibilings.Ext.fly('elId').radioClass('myCls');
Ext.fly('elId').removeClass('myCls'); // 移除元素的樣式
Ext.fly('elId').toggleClass('myCls'); // 加入樣式Ext.fly('elId').toggleClass('myCls'); // 移除樣式Ext.fly('elId').toggleClass('myCls'); // 再加入樣式
if (Ext.fly('elId').hasClass('myCls')) { // 是有樣式的……}
Ext.fly('elId').replaceClass('myClsA', 'myClsB');
var color = Ext.fly('elId').getStyle('color');var zIndx = Ext.fly('elId').getStyle('z-index');var fntFmly = Ext.fly('elId').getStyle('font-family');// ... 等等
Ext.fly('elId').setStyle('color', '#FFFFFF');Ext.fly('elId').setStyle('z-index', 10);Ext.fly('elId').setStyle({ display : 'block', overflow : 'hidden', cursor : 'pointer'});// 帶有動(dòng)畫(huà)的變換過(guò)程Ext.fly('elId').setStyle('color', '#FFFFFF', true);// 帶有0.75秒動(dòng)畫(huà)的變換過(guò)程Ext.fly('elId').setStyle('color', '#FFFFFF', {duration: .75}); // ... 等等
Ext.fly('elId').getColor('background-color');Ext.fly('elId').getColor('color');Ext.fly('elId').getColor('border-color');// ... 等等
Ext.fly('elId').setOpacity(.5);Ext.fly('elId').setOpacity(.45, true); // 動(dòng)畫(huà)// 附有半秒的動(dòng)畫(huà)過(guò)程Ext.fly('elId').setOpacity(.45, {duration: .5});
Ext.fly('elId').clearOpacity();已知某個(gè)位置,我們要其附近位置的dom樹(shù)中游歷,是一件經(jīng)常性的任務(wù)。Ext Core里面就有這樣跨瀏覽器的方法,允許我們在dom之中穿梭自如。再一次,CSS進(jìn)入了我們的視野,使得干起復雜的任務(wù)時(shí)沒(méi)那么痛苦?;贑SS3的選擇符(選擇器)在方面也尤其地干練!
拿以下的裝飾做示范:
<style type="text/css"> .red { color: #F00; }</style> ...<div id='elId'> <ul> <li>a-one</li> <li>a-two</li> <li>a-three</li> <li>a-four</li> </ul> <ul> <li>b-one</li> <li>b-two</li> <li>b-three</li> </ul></div>
這是一堆列表元素,要讓其中的偶數行變紅色。要如此優(yōu)雅地實(shí)現該功能,Ext不是沒(méi)有,鍵入命令如下:
Ext.fly('elId').select('li:nth-child(2n)').addClass('red');
結果如下:

我們已見(jiàn)識過(guò)游歷DOM方面,依靠Ext Core所帶來(lái)的強大威力,——類(lèi)似還有更多的,看看:
var el = Ext.get('elId');if (el.is('p.myCls')) { // 條件成立}
Ext.fly('elId').findParent('div'); // 返回dom節點(diǎn)Ext.fly('elId').findParent('div', 4); // 查找4個(gè)節點(diǎn)Ext.fly('elId').findParent('div', null, true); // 返回Ext.Element
Ext.fly('elId').findParentNode('div');
Ext.fly('elId').up('div');Ext.fly('elId').up('div', 5); // 限5層的內查找
// 返回結果的CompositeElementExt.fly('elId').select('div:nth-child(2)');// 返回數組Ext.fly('elId').select('div:nth-child(2)', true);// 整個(gè)document都會(huì )搜索Ext.select('div:nth-child(2)');
// 返回dom節點(diǎn)組成的數組Ext.query('div:nth-child(2)'); Ext.fly('elId').child('p.highlight'); // 返回的類(lèi)型是Ext.ElementExt.fly('elId').child('p.highlight', true); // 返回dom節點(diǎn)
Ext.fly('elId').down('span'); // 返回的類(lèi)型是Ext.ElementExt.fly('elId').down('span', true); // 返回dom節點(diǎn)
// 返回父節點(diǎn),類(lèi)型是Ext.ElementExt.fly('elId').parent(); // 返回父節點(diǎn),類(lèi)型是html domExt.fly('elId').parent("", true);// 返回父級節點(diǎn),但一定要是div的,找到就返回,類(lèi)型是Ext.ElementExt.fly('elId').parent("div");
// 返回下一個(gè)側邊節點(diǎn),類(lèi)型是Ext.ElementExt.fly('elId').next();// 返回下一個(gè)側邊節點(diǎn),類(lèi)型是html domExt.fly('elId').next("", true);// 返回下一個(gè)側邊節點(diǎn),但一定要是div的,找到就返回,類(lèi)型是Ext.ElementExt.fly('elId').next("div");
// 返回上一個(gè)側邊節點(diǎn),類(lèi)型是Ext.ElementExt.fly('elId').prev();// 返回上一個(gè)側邊節點(diǎn),類(lèi)型是html domExt.fly('elId').prev("", true);// 返回上一個(gè)側邊節點(diǎn),但一定要是div的,找到就返回,類(lèi)型是Ext.ElementExt.fly('elId').prev("div");
// 返回第一個(gè)側邊節點(diǎn),類(lèi)型是Ext.ElementExt.fly('elId').first();// 返回第一個(gè)側邊節點(diǎn),類(lèi)型是html domExt.fly('elId').first("", true);// 返回第一個(gè)側邊節點(diǎn),但一定要是div的,找到就返回,類(lèi)型是Ext.ElementExt.fly('elId').first("div");
// 返回最后一個(gè)側邊節點(diǎn),類(lèi)型是Ext.ElementExt.fly('elId').last();// 返回最后一個(gè)側邊節點(diǎn),類(lèi)型是html domExt.fly('elId').last("", true);// 返回最后一個(gè)側邊節點(diǎn),但一定要是div的,找到就返回,類(lèi)型是Ext.ElementExt.fly('elId').last("div");
DHTML常見(jiàn)的一項任務(wù)就是DOM元素的增、刪、改、查。鑒于不同瀏覽器的差別很大,搞起來(lái)會(huì )很麻煩,ExtCore就設計了一個(gè)抽離不同瀏覽器之間差異的API,并考慮了執行速度方面的優(yōu)化。我們可以輕松地圍繞DOM樹(shù)做增、刪、改、查的任務(wù)。先觀(guān)察一下這裝飾元素:
<div id='elId'> <p>paragraph one</p> <p>paragraph two</p> <p>paragraph three</p></div>
渲染出來(lái)這樣:

這時(shí)我們?yōu)槠浼尤胍粋€(gè)子節點(diǎn)“elId”:
Ext.fly('elId').insertFirst({ tag: 'p', html: 'Hi! I am the new first child.'});
插入后是這樣:

小菜一碟吧???我們再操練一下Ext Core強大的API功能:
var el = Ext.get('elId1');// 用id指定Ext.fly('elId').appendChild('elId2');// Ext.Element添加Ext.fly('elId').appendChild(el);// 選擇符組合地添加Ext.fly('elId').appendChild(['elId2','elId3']);// 直接添加dom節點(diǎn)Ext.fly('elId').appendChild(el.dom);// 添加CompositeElement,一組的divExt.fly('elId').appendChild(Ext.select('div'));
var el = Ext.get('elId1'); // 'elId'添加到'elId2'里面Ext.fly('elId').appendTo('elId2'); Ext.fly('elId').appendTo(el); // 添加到Ext.Element el
var el = Ext.get('elId1'); // dom節點(diǎn)在前面插入Ext.fly('elId').insertBefore('elId2');//Ext.Element el在前面插入Ext.fly('elId').insertBefore(el);
var el = Ext.get('elId1'); // dom節點(diǎn)在后面插入Ext.fly('elId').insertAfter('elId2');// Ext.Element el在后面插入Ext.fly('elId').insertAfter(el);
var el = Ext.get('elId1'); // 插入的dom節點(diǎn)作為第一個(gè)元素Ext.fly('elId').insertFirst('elId2'); // 插入的Ext.Element作為第一個(gè)元素Ext.fly('elId').insertFirst(el); // 用DomHelper配置項創(chuàng )建新節點(diǎn),新節點(diǎn)會(huì )作為第一個(gè)子元素被插入。Ext.fly('elId').insertFirst({ tag: 'p', cls: 'myCls', html: 'Hi I am the new first child'});
var el = Ext.get('elId1'); // 'elId'去替換'elId2'Ext.fly('elId').replace('elId2'); // 'elId'去替換'elId1'Ext.fly('elId').replace(el);
var el = Ext.get('elId1'); Ext.fly('elId').replaceWith('elId2'); // 'elId2'替換掉'elId'.Ext.fly('elId').replaceWith(el); // 'elId1'替換掉'elId' // 用DomHelper配置項創(chuàng )建新節點(diǎn),并用該節點(diǎn)換掉‘elId’。Ext.fly('elId').replaceWith({ tag: 'p', cls: 'myCls', html: 'Hi I have replaced elId'});
在上面的例子中,大家可能就注意到這樣的語(yǔ)法:
.insertFirst({ tag: 'p', html: 'Hi I am the new first child'});insertFirst方法的那個(gè)參數作用是什么呢?參數就是要創(chuàng )建的裝飾元素在DomHelper中是怎么表示的,也就是DomHelper的配置選項,其配置項支持很多的屬性,html片斷也行,至于html屬性就可以是Dom節點(diǎn)的很多屬性了(css class、url、src、id等)。這里是Ext.Element一些的API,直接用來(lái)與Ext.DomHelper相交互:
var el = Ext.get('elId');var dhConfig = { tag: 'p', cls: 'myCls', html: 'Hi I have replaced elId'};// 創(chuàng )建新的節點(diǎn),放到'elId'里面el.createChild(dhConfig); // 創(chuàng )建新的節點(diǎn),居el第一個(gè)子元素之前el.createChild(dhConfig, el.first());
Ext.fly('elId').wrap(); // div包著(zhù)elId // 用新建的一個(gè)元素來(lái)包著(zhù)elIdExt.fly('elId').wrap({ tag: 'p', cls: 'myCls', html: 'Hi I have replaced elId'});
Html片斷,顧名思義,系html裝飾中的某一部分。Exr Core就是以html片斷的形式修改控制dom,換言之,我們關(guān)心裝飾片斷即可修改該部分的dom,無(wú)須為瀏覽器的實(shí)現和性能而煩惱。Ext Core已經(jīng)做足涵蓋這方面的功夫,閣下所做的只是提供好相關(guān)裝飾元素,如:
<div id='elId'> <li>one</li> <li>two</li> <li>three</li> <li>four</li> </div>
你猜Ext Core會(huì )怎樣做?
Ext.fly('elId').insertHtml('beforeBegin', '<p>Hi</p>')
形成裝飾元素如下:
<p>Hi</p> <div id='elId'> <li>one</li> <li>two</li> <li>three</li> <li>four</li> </div>
不意外吧?這是因為我們可以自由定位插入的順序。我們指定“beforeBegin”,就是這樣:
Ext.fly('elId').insertHtml('afterBegin', '<p>Hi</p>')
看一看:
<div id='elId'> <p>Hi</p> <li>one</li> <li>two</li> <li>three</li> <li>four</li> </div>
現在我們使用“beforeEnd”。
Ext.fly('elId').insertHtml('beforeEnd', '<p>Hi</p>')
來(lái)看看:
<div id='elId'> <li>one</li> <li>two</li> <li>three</li> <li>four</li> <p>Hi</p> </div>
最后試試“afterEnd”。
Ext.fly('elId').insertHtml('beforeEnd', '<p>Hi</p>')
看看:
<div id='elId'> <li>one</li> <li>two</li> <li>three</li> <li>four</li> </div><p>Hi</p>
處理HTML片斷時(shí)下列方法也是有幫助的:
Ext.fly('elId').insertHtml( 'beforeBegin', '<p><a href="anotherpage.html'>點(diǎn)擊我</a></p>'); // 返回dom節點(diǎn)Ext.fly('elId').insertHtml( 'beforeBegin', '<p><a href="anotherpage.html'>點(diǎn)擊我</a></p>', true); // 返回Ext.Element
Ext.fly('elId').remove(); // elId在緩存和dom里面都沒(méi)有
Ext.removeNode(node); // 從dom里面移除(HTMLElement)Ext Core具備完整的Ajax API。關(guān)于本部分的詳細內容會(huì )在文章尾部交待清楚不過(guò)這里先介紹API中的概貌:
Ext.fly('elId').load({url: 'serverSide.php'})
var updr = Ext.fly('elId').getUpdater();updr.update({ url: 'http://myserver.com/index.php', params: { param1: "foo", param2: "bar" }});
事件控制為解決跨瀏覽器的工作帶來(lái)便利。
正如Ext.Element封裝了原生的Dom類(lèi)型節點(diǎn),Ext.EventObject也是封裝了瀏覽器的原生事件對象。Ext.EventObject的實(shí)例解決了各瀏覽器之間的差異。例如鼠標按鈕被點(diǎn)擊了、有按鍵被按下了、或者要停止事件的推進(jìn)等的任務(wù)都有相應的方法參與。
要將事件處理器和頁(yè)面中的元素綁定在一起可以使用Ext.Element的on方法。它是addListener方法的簡(jiǎn)寫(xiě)形式。第一個(gè)參數是要訂閱的事件類(lèi)型和第二個(gè)參數是準備觸發(fā)的事件函數。
Ext.fly('myEl').on('click', function(e, t) { // myEl有點(diǎn)擊的動(dòng)作 // e是這次產(chǎn)生的事件對象,Ext.EventObject // t是HTMLElement目標});Ext Core常規化了所有DOM事件的參數。事件處理器總會(huì )被送入一個(gè)常規化的事件對象(Ext.EventObject)和目標元素,HTMLElement。
這些是用于事件處理方面的API:
var el = Ext.get('elId');el.on('click', function(e,t) { // e是一個(gè)標準化的事件對象(Ext.EventObject) // t就是點(diǎn)擊的目標元素,這是個(gè)Ext.Element. // 對象指針this也指向t });
var el = Ext.get('elId');el.un('click', this.handlerFn);// 或el.removeListener('click', this.handlerFn);
// e它不是一個(gè)標準的事件對象,而是Ext.EventObject。function handleClick(e){ e.preventDefault(); var target = e.getTarget(); ...}var myDiv = Ext.get('myDiv');myDiv.on("click", handleClick);// 或Ext.EventManager.on('myDiv', 'click', handleClick);Ext.EventManager.addListener('myDiv', 'click', handleClick);
事件委托、事件緩沖、事件延遲等的這些功能都是屬于高級事件的控制內容,Ext Core在此方面提供了一系列的配置選項。
這不是說(shuō)要求我們在body元素掛上一個(gè)全局的事件,這會(huì )導致頁(yè)面內的任何動(dòng)作都會(huì )觸發(fā)那個(gè)事件,無(wú)疑很有可能會(huì )帶來(lái)反效果的,我們想提升效能卻會(huì )更慢……因此,我們說(shuō),適用的場(chǎng)景應該像是下拉列表、日歷等等這樣擁有一群元素的控件,直接或間接地體現在一個(gè)容器身上的那么一個(gè)控件。下面一個(gè)大的ul元素為例子:并不是集合內的每一個(gè)元素都要登記上事件處理器,而是在集合其容器上登記一次便可,這樣產(chǎn)生了中央化的一個(gè)事件處理器,然后就有不斷循環(huán)該事件周期,使得逐層上報機制付諸實(shí)現,只要在容器層面定義就可以。
<ul id='actions'> <li id='btn-edit'></li> <li id='btn-delete'></li> <li id='btn-cancel'></li></ul>不是登記一個(gè)處理器而是為逐個(gè)列表項(list item)都登記:
Ext.fly('btn-edit').on('click, function(e,t) { // 執行事件具體過(guò)程});Ext.fly('btn-delete').on('click, function(e,t) { // 執行事件具體過(guò)程});Ext.fly('btn-cancel').on('click, function(e,t) { // 執行事件具體過(guò)程});要使用事件委托的方式代替,在容器身上登記一個(gè)事件處理器,按照依附的邏輯選擇:
Ext.fly('actions').on('click, function(e,t) { switch(t.id) { case ''btn-edit': // 處理特定元素的事件具體過(guò)程 break; case 'btn-delete': // 處理特定元素的事件具體過(guò)程 break; case 'btn-cancel': // 處理特定元素的事件具體過(guò)程 break; }});基于dom各層經(jīng)過(guò)逐層上報的原因,可以說(shuō),我們登記了的“actions”的div一定會(huì )被訪(fǎng)問(wèn)得到。這時(shí)就是執行我們所指定的switch指令,跳到對應匹配的元素那部分代碼。這樣方法具備可伸縮性,因為我們只要維護一個(gè)函數就可以控制那么多的元素的事件。
el.on('click', function(e,t) { // 執行事件具體過(guò)程}, this, { // 對子孫'clickable'有效 delegate: '.clickable' });
// handles when the mouse enters the element function enter(e,t){ t.toggleClass('red');}// handles when the mouse leaves the elementfunction leave(e,t){ t.toggleClass('red');}// subscribe to the hoverel.hover(over, out);
el.removeAllListeners();
el.on('click', function(e,t) { // 執行事件具體過(guò)程}, this, { single: true // 觸發(fā)一次后不會(huì )再執行事件了});
el.on('click', function(e,t) { // 執行事件具體過(guò)程}, this, { buffer: 1000 // 重復響應事件以一秒為時(shí)間間隔});
el.on('click', function(e,t) { // 執行事件具體過(guò)程}, this, { // 延遲事件,響應事件后開(kāi)始計時(shí)(這里一秒) delay: 1000 });
el.on('click', function(e,t) { // 執行事件具體過(guò)程}, this, { // 遇到里頭的第一個(gè)'div'才會(huì )觸發(fā)事件 target: el.up('div') });
某個(gè)元素在頁(yè)面上,我們就想獲得到其尺寸大小或改變它的尺寸大小。毫無(wú)意外下,Ext Core也把這些任務(wù)抽象為清晰的API供大家使用。這些都是setter的方法,可傳入動(dòng)畫(huà)的配置參數,或即就是以個(gè)布爾型的true,表示這是默認的動(dòng)畫(huà)。我們來(lái)看一看:
// 設置高度為200px以默認配置進(jìn)行動(dòng)畫(huà)Ext.fly('elId').setHeight(200, true);// 設置高度為150px以自定義的配置進(jìn)行動(dòng)畫(huà)Ext.fly('elId').setHeight(150, { duration : .5, // 動(dòng)畫(huà)將會(huì )持續半秒 // 動(dòng)畫(huà)過(guò)后改變其內容為“結束” callback: function(){ this.update("結束"); } });
拉出Firebug,檢測一下元素(右擊后選擇元素“Inspect Element”),觀(guān)察右方的面板并點(diǎn)擊“l(fā)ayout”,您應會(huì )看到這樣:

這塊地方提供的信息足夠清楚顯示有關(guān)該元素的所有尺寸。從中得知,當前元素寬895px、高1669px、0px的內邊距、0px的邊框和0px的外邊距。不過(guò)這些信息亦可從Ext Core的Ext.Element的API查詢(xún)得知!
var dimSz = Ext.get('dim-sizing');var padding = dimSz.getPadding('lrtb'); // 返回0px的值var border = dimSz.getBorderWidth('lrtb'); // 返回0px的值var height = dimSz.getHeight(); // 返回1691px的值var width = dimSz.getWidth(); // 返回895px的值
把代碼弄進(jìn)Firebug調試看看,有否這樣的結果?實(shí)際上用這些set的方法改變高度或寬度后就可立即在firebug的layout面板看到的。(注意:if如果對圖片設置其不同大小的高度或寬度,那就是瀏覽器的尺寸。如果你在瀏覽器中瀏覽圖片元素的實(shí)際情況那就是實(shí)際的輸出大小。)
剩下的API是哪些?我們看看:
var ht = Ext.fly('elId').getHeight();
var wd = Ext.fly('elId').getWidth();
Ext.fly('elId').setHeight();Ext.fly('elId').setWidth();var bdr_wd = Ext.fly('elId').getBorderWidth('lr');
var padding = Ext.fly('elId').getPadding('lr');
Ext.fly('elId').clip();Ext.fly('elId').unclip();if (Ext.isBorderBox) { // }通過(guò)Ext Core定義的API能快速地采集元素位置的各方面數據,歸納為get的或set的方法,全部瀏覽器都可通用。類(lèi)似于上一節的尺寸大小的API,多數的setter方法支持動(dòng)畫(huà)效果??稍诘诙抵袀魅雱?dòng)畫(huà)的配置參數(object-literal configuration object),或即就是以個(gè)布爾型的true,表示這是默認的動(dòng)畫(huà)。我們來(lái)看一看例子是怎樣子的:
// 改變x-coord為75px,附有自定義的動(dòng)畫(huà)配置Ext.fly('elId').setX(75, { duration : .5, // 動(dòng)畫(huà)將會(huì )持續半秒 // 動(dòng)畫(huà)過(guò)后改變其內容為“結束” callback: function(){ this.update("結束"); }});
var elX = Ext.fly('elId').getX()
var elY = Ext.fly('elId').getY()
var elXY = Ext.fly('elId').getXY() // elXY是數組
Ext.fly('elId').setX(10)Ext.fly('elId').setY(10)Ext.fly('elId').setXY([20,10])var elOffsets = Ext.fly('elId').getOffsetsTo(anotherEl);
var elLeft = Ext.fly('elId').getLeft();
var elRight = Ext.fly('elId').getRight();
var elTop = Ext.fly('elId').getTop();
var elBottom = Ext.fly('elId').getBottom();
Ext.fly('elId').setLeft(25)Ext.fly('elId').setRight(15)Ext.fly('elId').setTop(12)Ext.fly('elId').setBottom(15)Ext.fly('elId').setLocation(15,32)Ext.fly('elId').moveTo(12,17)Ext.fly('elId').position("relative")
Ext.fly('elId').clearPositioning() Ext.fly('elId').clearPositioning("top")
var pos = Ext.fly('elId').getPositioning()
Ext.fly('elId').setPositioning({ left: 'static', right: 'auto'})
// {left:translX, top: translY}var points = Ext.fly('elId').translatePoints(15,18);
Ext Core已經(jīng)齊備了若干的動(dòng)畫(huà)的插件,附加在Ext.Element的身上,讓你進(jìn)一步地發(fā)揮這一組組預配置的動(dòng)畫(huà),作出更“酷”的東東來(lái)。
放在Firebug里面運行這段代碼看看,你將發(fā)現Ext就內建了一組完整的動(dòng)畫(huà)。每一組動(dòng)畫(huà)就是使用這些配置字面對象(configuration object literal),去制定這些動(dòng)畫(huà)如何產(chǎn)生。不一定要默認的配置,或者你也可以在動(dòng)畫(huà)執行完畢后接著(zhù)執行一個(gè)回調函數:
Ext.fly('slideEl').slideOut('r');
Ext.fly('slideEl').slideOut('r', { callback : function(){ alert('元素已滑出'); }});
可以看出這樣子做動(dòng)畫(huà)著(zhù)實(shí)強大!
動(dòng)畫(huà)支持八方位的定向,所以你可以選擇八個(gè)不同的定位點(diǎn)來(lái)啟動(dòng)您的動(dòng)畫(huà)效果。
| Valuer | |
|---|---|
| tl | The top left corner左上角 |
| t | The center of the top edge頂部中央 |
| tr | The top right corner右上角 |
| l | The center of the left edge左邊中央 |
| r | The center of the right edge右邊中央 |
| bl | The bottom left corner左下角 |
| b | The center of the bottom edge底部中央 |
| br | The bottom right corner右下角 |
進(jìn)一步瀏覽里面的API:
// 默認情況:將元素從頂部滑入el.slideIn();// 自定義:在2秒鐘內將元素從右邊滑入el.slideOut();// 常見(jiàn)的配置選項及默認值el.slideIn('t', { easing: 'easeOut', duration: .5});el.slideOut('t', { easing: 'easeOut', duration: .5, remove: false, useDisplay: false});
// 默認el.puff();// 常見(jiàn)的配置選項及默認值el.puff({ easing: 'easeOut', duration: .5, remove: false, useDisplay: false});
// 默認el.switchOff();// 所有的配置選項及默認值el.switchOff({ easing: 'easeIn', duration: .3, remove: false, useDisplay: false});
// 默認情況:高亮顯示的背景顏色為黃色el.highlight();// 自定義:高亮顯示前景字符顏色為藍色并持續2秒el.highlight("ffff9c", { // 可以任何有效的CSS屬性表示顏色 attr: "background-color", endColor: (current color) or "ffffff", easing: 'easeIn', duration: 1});
// 默認情況:一個(gè)淡藍色的波紋el.frame();// 自定義:三個(gè)紅色的波紋并持續3秒el.frame("C3DAF9", 1, { duration: 1 //每個(gè)波紋持續的時(shí)間 // 注意:這里不能使用 Easing 選項在,即使被包含了也會(huì )被忽略});
el.pause(1);
// 默認情況:將可見(jiàn)度由 0 漸變到 100%el.fadeIn();el.fadeOut();// 自定義:在2秒鐘之內將可見(jiàn)度由 0 漸變到 75%el.fadeIn({ endOpacity: 1, // 可以是 0 到 1 之前的任意值(例如:.5) easing: 'easeOut', duration: .5});el.fadeOut({ endOpacity: 0, // 可以是 0 到 1 之前的任意值(例如:.5) easing: 'easeOut', duration: .5, remove: false, useDisplay: false});
// 將寬度和高度設置為 100x100 象素el.scale(100, 100);// 常見(jiàn)的配置選項及默認值。
// 如果給定值為 null,則高度和寬度默認被設置為元素已有的值。el.scale( [element's width], [element's height], { easing: 'easeOut', duration: .35 });
// 將元素水平地滑動(dòng)到X坐標值為200的位置,同時(shí)還伴隨著(zhù)高度和透明度的改變el.shift({ x: 200, height: 50, opacity: .8 });// 常見(jiàn)的配置選項及默認值。el.shift({ width: [element's width], height: [element's height], x: [element's x position], y: [element's y position], opacity: [element's opacity], easing: 'easeOut', duration: .35});
// 默認情況:將元素向下方滑出并漸隱el.ghost();// 自定義:在2秒鐘內將元素向右邊滑出并漸隱el.ghost('b', { easing: 'easeOut', duration: .5, remove: false, useDisplay: false});
我們也可以用ExtCore的動(dòng)畫(huà)系統來(lái)建立我們制定的動(dòng)畫(huà),在Firebug里面測試一下下面的代碼:
var el = Ext.get('complexEl')el.animate({ borderWidth: {to: 3, from: 0}, opacity: {to: .3, from: 1}, height: {to: 50, from: el.getHeight()}, width: {to: 300, from: el.getWidth()} });
以上未能分類(lèi)的就這里列出,都是Ext.Element方法。
el.focus();
el.blur();
el.getValue();el.getValue(true); // 輸出值為數字型
if (Ext.isBorderBox) { }在DOM節點(diǎn)中的某個(gè)元素,返回其一個(gè)命名空間屬性的值。
el.getAttributeNS("","name");CompositeElement能夠把一組元素視作一個(gè)元素來(lái)處理(依據維基百科全書(shū)),這組元素的數量可以零個(gè)到多個(gè)。CompositeElement采用與Ext.Element相同的接口,以簡(jiǎn)化程序員的工作,也可以減少處理集合上的那些一般內核檢查(指要寫(xiě)“循環(huán)”的代碼)。通常CompositeElement由執行靜態(tài)方法Ext.select來(lái)獲取得到。Ext.select()基于DomQuery來(lái)搜索整個(gè)文檔,匹配符合特定選擇符(Selecetor)的元素。
例如下列的裝飾元素:
<html> <body> <div id="first" class="title">Sample A</div> <div id="second" class="doesNotMatch">Lorem Ipsum</div> <div id="third" class="title secondCSSCls">Some additional content</div> </body></html>
我們根據選擇符“.title”查詢(xún)整張頁(yè)面得到一個(gè)CompositeElement類(lèi)型的對象,其包含了兩個(gè)div的引用,分別是第一個(gè)div和第二個(gè)div。
var els = Ext.select('.title');注意:第三個(gè)元素同時(shí)還附有secondCSSCls的樣式。HtmlElement元素可允許有多個(gè)CSS樣式類(lèi),就用空格分割開(kāi)。這里的選擇符不是說(shuō)只要title樣式的,那么“first”與“thrid”都能返回得到。
獲取CompositeElement對象后即可像單個(gè)元素那段操作一群Elements。例如,我們對集合中的每個(gè)元素加入CSS的.error樣式。
var els = Ext.select('.title');els.addClass('error');如果要獲取的某一些元素是處于另處一元素的附近的,這兩者之間相對的關(guān)系是已知的,那么就可以從那個(gè)元素為起點(diǎn)進(jìn)行搜索查詢(xún)。這樣查詢(xún)效率會(huì )更來(lái)得快,原因是你是在文檔中的某一部分內局部地查詢(xún),自然比全體查詢(xún)的快。下面HTML中,“accordion”的div標簽是包含著(zhù)first、second 和third元素:
<html> <body> <div id="accordion"> <div id="first" class="title">Sample A</div> <div id="second" class="doesNotMatch">Lorem Ipsum</div> <div id="third" class="title secondCSSCls"> Some additional content </div> </div> </body></html>
由于我們得知這三元素都在accordion元素里面的,因此我們將搜索范圍僅限定在accordion元素內。如果清楚元素的相對位置,應該盡量使用這種縮小范圍的方式來(lái)查詢(xún),以利于性能提升。
其它有用的CompositeElement方法如下面代碼所列:
var accordion = Ext.get('accordion');accordion.select('title');// firstItem是第一個(gè)的div,類(lèi)型是Ext.Elementvar firstItem = accordion.item(0); // 提示1或居二的位置alert(accordion.indexOf('third'));// 提示2alert(accordion.getCount()); // 集合里和DOM里面都沒(méi)有這個(gè)元素了accordion.removeElement('one', true); 注意:Ext JS用戶(hù)所熟悉的一些方法,如each、first、last、fill、contains、filter這些都在CompositeElement里都沒(méi)有。
“異步JavaScript與XML(Ajax)”與是幾種開(kāi)發(fā)技術(shù)匯總的名稱(chēng),用于開(kāi)發(fā)Web交互程序或富介面的互聯(lián)網(wǎng)程序。利用Ajax,可不在影響現有頁(yè)面之交互的情況下,達到與服務(wù)端異步式的數據獲取,當前頁(yè)面無(wú)須一定的變化。負責數據交互的是XHR對象,基于各瀏覽器其實(shí)現XHR方式的不同,Ajax框架都提供一個(gè)抽象接口,處理了這些差并異集中在一個(gè)可復用的編程基建中,而在Ext中,負責這些任務(wù)的正是Ext.Ajax對象。
Ext.Ajax對象繼承自Ext.data.Connection,定義為單例提供了一個(gè)既統一又高度靈活的Ajax通迅服務(wù)。利用這個(gè)單例對象,就可以處理全體Ajax請求,并執行相關(guān)的方法、事件和參數。
每次請求都觸發(fā)事件,這是全局規定的。
// 例子:凡是Ajax通迅都會(huì )通過(guò)spinner告知狀態(tài)如何。Ext.Ajax.on('beforerequest', this.showSpinner, this);Ext.Ajax.on('requestcomplete', this.hideSpinner, this);Ext.Ajax.on('requestexception', this.hideSpinner, this);由于Ext.Ajax是單例,所以你可以在發(fā)起請求的時(shí)候才覆蓋Ext.Ajax屬性。這些是最常見(jiàn)的屬性:
// 每次請求都將這字段與信息注入到頭部中去。Ext.Ajax.defaultHeaders = { 'Powered-By': 'Ext Core'};Ext.Ajax.request就是發(fā)送與接收服務(wù)端函數的函數。服務(wù)端返用response以決定執行success或failure函數。注意這種success/failure函數是異步的,即就是服務(wù)端有響應后客戶(hù)端這邊回頭調用(回調函數),期用客戶(hù)端的Web頁(yè)面還可以進(jìn)行其它任務(wù)的操作。
Ext.Ajax.request({ url: 'ajax_demo/sample.json', success: function(response, opts) { var obj = Ext.decode(response.responseText); console.dir(obj); }, failure: function(response, opts) { console.log('服務(wù)端失效的狀態(tài)代碼:' + response.status); }});Ajax另外一個(gè)常見(jiàn)用法是動(dòng)態(tài)更新頁(yè)面中的原素不需要刷新頁(yè)面。response方法暴露了el配置項,在請求之后根據內容設置到元素的innerHTML。
用Ext.Ajax.request 的配置項提交表單:
Ext.Ajax.request({ url: 'ajax_demo/sample.json', form: 'myForm', success: function(response, opts) { var obj = Ext.decode(response.responseText); console.dir(obj); }, failure: function(response, opts) { console.log('服務(wù)端失效的狀態(tài)代碼:' + response.status); }});DomQuery的作用在于提供選擇符(Selector)、XPath的快速元素定位,對HTML與XML的文檔都有效。DomQuery支持到CSS3規范的選擇符,還有一些自定義的選擇符與較簡(jiǎn)單的,一份完整的CSS3規范在這里。
你可以輸入多個(gè)查詢(xún)條件,然后在一個(gè)對象上面返回。
// 匹配所有的帶foo class的div和帶bar class的spanExt.select('div.foo, span.bar');使用選擇符,它可以支持一個(gè)根節點(diǎn)的概念。根節點(diǎn)的意思是如果有指定選擇符的根節點(diǎn)表示從該節點(diǎn)上開(kāi)始進(jìn)行搜索。這樣可以助于提升性能,因為若不存在根節點(diǎn)表示從document body開(kāi)始進(jìn)行搜索,速度自然比較慢。
Ext.get('myEl').select('div.foo');// 這是等價(jià)的Ext.select('div.foo', true, 'myEl');// 這是等價(jià)的對于構成復雜的查詢(xún)情況,可以由多個(gè)查詢(xún)條件組成查詢(xún)鏈。依次按順序進(jìn)行屬性鏈的查詢(xún)。
// 匹配class為foo的div,要求是有title屬性為bar的div,而且還是這個(gè)div下面最前頭的子元素Ext.select('div.foo[title=bar]:first');// Matches all div elementsExt.select('div'); // Matches all span elements contained inside a div at any levelExt.select('div span');// Matches all li elements with a ul as their immediate parentExt.select('ul > li');
// Matches all div elements with the class newsExt.select('div.news'); // Matches all a elements with an href that is http://extjs.comExt.select('a[href=http://extjs.com]'); // Matches all img elements that have an alt tagExt.select('img[alt]');
// Matches the first div with a class of codeExt.select('div.code:first'); // Matches spans that fall on an even index.Ext.select('span:even'); // Matches all divs whos next sibling is a span with class header.Ext.select('div:next(span.header));
DomHelper(下簡(jiǎn)稱(chēng)DH)是專(zhuān)用于動(dòng)態(tài)生成裝飾元素的實(shí)用工具,已解決大多數瀏覽器之間差別的問(wèn)題,避免了原始操作DOM腳本的麻煩。對于HTML片斷與innerHTML的操作,DH經(jīng)充分考慮并在性能上有足夠的優(yōu)化。
Ext.DomHelper是一個(gè)單例,因此無(wú)須實(shí)例化即可調用其靜態(tài)方法。
var myEl = document.createElement('a');myEl.;myEl.innerHTML = 'My Link';myEl.setAttribute('target', '_blank');var myDiv = document.createElement('div');myDiv.id = 'my-div';myDiv.appendChild(myEl);document.body.appendChild(myDiv);Ext.DomHelper:Ext.DomHelper.append(document.body, { id: 'my-div', cn: [{ tag: 'a', href: 'http://www.yahoo.com/', html: 'My Link', target: '_blank' }]});DomHelper是根據DomHelper 配置項未決定生成在頁(yè)面上的HTML,這DomHelper配置可視作任何HTML元素的等價(jià)物。
Markup:<a href="http://www.extjs.com">Ext JS</a>DomHelper配置項:{ tag: 'a', href: 'http://www.extjs.com', html: 'Ext JS'}Tpl模板、格式化函數,from的靜態(tài)方法(對textarea有用)。
添加和執行成員格式化函數。
Javascript是一門(mén)靈活的語(yǔ)言。以它靈活性,其中一項表現為,JavaScript基礎對象可以讓程序員自由地綁定函數在其身上。為什么會(huì )這樣做?基礎對象是與這些所屬的方法(函數)有密切聯(lián)系的,開(kāi)放給大家定義其關(guān)系的。不過(guò)這樣的方法有許多,不大有可能一一實(shí)作出來(lái),有些瀏覽器有,有些沒(méi)有,但就開(kāi)放出來(lái)這種修改的權利給程序員。當同時(shí)使用多個(gè)JavaScript庫時(shí),他們可能有各自的實(shí)現,但如果同名的方法、屬性就犯大忌了,這種重疊將引入庫與庫之間的沖突……基于這種狀況,Ext謹慎處理加入到基礎對象的方法數量。這里是一份有關(guān)于各框架、庫“入侵/污染”問(wèn)題的調查報告:Framework Scanner。
下列函數已經(jīng)加入了Function的prototoype對象中。(請注意createSequence與createInterceptor沒(méi)有被加入。):
var sayHello = function(firstName, lastName){ alert('Hello ' + firstName + ' ' + lastName);};Ext.get('myButton').on('click', sayHello.createCallback('John', 'Smith');var sayHello = function(firstName, lastName, e){ alert('Hello ' + firstName + ' ' + lastName);};Ext.get('myButton').on( 'click', sayHello.createDelegate(this, ['John', 'Smith'], //0這里說(shuō)明我們打算把我們參數插入到最前的位置 0); var whatsTheTime = function(){ alert(new Date());};whatsTheTime.defer(3000); //執行之前等待三秒
下面的這些方法加入到Array的prototype對象中,瀏覽器有實(shí)現的話(huà)就不用加:
var idx = [1, 2, 3, 4, 5].indexOf(3); // 返回2。var arr = [1, 2, 3, 4];arr.remove(2);var len = arr.length; // len是3了。
String類(lèi)只有一個(gè)format的方法加入,注意這或者會(huì )與Ajax.NET相沖突。
var s = String.format( 'Hey {0} {1}',您好嗎?', '張', '三');//{0}替換為 張,{1}替換為 三
Ext提供了增強Javascript與JSON若干方面的函數,功能上各自不一樣但目的都是為了更方便地程序員使用好前端設施。
var person = { name: 'John Smith', age: 30};Ext.apply(person, { hobby: 'Coding', city: 'London'}); // person對象也有hobby與cityvar person = { name: 'John Smith', age: 30, hobby: 'Rock Band'};Ext.applyIf(person, { hobby: 'Coding', city: 'London'}); // 不復制hobby
這些方法用于JSON數據的轉換,在GET的http通訊中經(jīng)常被轉換為字符通訊等等的場(chǎng)景。
var params = { foo: 'value1', bar: 100};var s = Ext.encode(params); // s形如foo=value1&bar=100var s = 'foo=value1&bar=100';var o = Ext.decode(s); // o現在有兩個(gè)屬性,foo和bar。alert(o.bar);
Ext core有為JavaScript數組和其他類(lèi)型的collections提供方法。
Ext.each([1, 2, 3, 4, 5], function(num){ alert(num);});var arr1 = Ext.toArray(1); // arr1 = [1];// arr2 = Ext elements []var arr2 = Ext.toArray(Ext.select('div));
JSON表示Javascript Object Notation,常用于數據交換格式。類(lèi)似于JavaScript的字面對象(object literals)。當與服務(wù)器交換數據的時(shí)候,就要轉換為原生的JavaScript形式。有以下兩種輔助方法。更多的資訊可參見(jiàn)json.org。
var s = Ext.encode({ foo: 1, bar: 2}); //s是'{foo=1,bar=2}'這樣。var s = '{foo=1,bar=2}';var o = Ext.decode(s); // o現在有兩個(gè)屬性,foo和bar。
Ext帶有一系列的瀏覽器判定的功能,以解決主流瀏覽器之間有差異的問(wèn)題,在JavaScript與CSS方面都有判定技術(shù),也適應復雜的情境。
對瀏覽器的判定情況:
if(Ext.isIE){ // 執行該瀏覽器的專(zhuān)用代碼}CSS也有類(lèi)似的判定,不同的樣式會(huì )根據不同的操作環(huán)境適當添加到根元素和body上,目的是更方便地解決好瀏覽器怪辟問(wèn)題。在strict模式環(huán)境中,樣式ext-strict就會(huì )加入到root,其余這些可適當地加入到body中去。
/* 當這是strict mode模式而且是safari的環(huán)境中,字體便有變化。*/.ext-strict .ext-safari .sample-item{ font-size: 20px; }JavaScript是一門(mén)弱類(lèi)型語(yǔ)言,要搞清楚變量是什么類(lèi)型自然很有必要。這方面,Ext有若干如下的方法:
如果傳入的值是null、undefined或空字符串,則返回true。
alert(Ext.isEmpty(''));返回true表名送入的對象是JavaScript的array類(lèi)型對象,否則為false。
alert(Ext.isArray([1, 2, 3]));
檢查傳入的值是否為對象。
alert(Ext.isObject({}));檢查傳入的值是否為函數。
alert(Ext.isFunction(function(){}));返回一個(gè)獨一無(wú)二的標點(diǎn)符號,對Ext.id()的調用就是生成從未使用的新id,第一個(gè)參數是可選的,是對哪個(gè)元素去分配id,第二個(gè)參數是id的前綴。
var s = Ext.id(null, 'prefix'); // 不指定元素var s = Ext.id(Ext.get(document.body)); // 對元素分配id
Task Runner是一個(gè)以特定時(shí)間為間隔然后執行函數的類(lèi)。這對進(jìn)行“拉(pull)”的操作是比較有用的,例如每30秒的間隔刷新內容(Ajax)。TaskMgr對象是TaslRunner的單例,這樣使用起這個(gè)Task Runner便很快了。
var stop = false;var task = { run: function(){ if(!stop){ alert(new Date()); }else{ runner.stop(task); // 有需要的話(huà)這里我們也能停止任務(wù) } }, interval: 30000 // 每30秒一周期};var runner = new Ext.util.TaskRunner();runner.start(task);//使用TaskMgrExt.TaskMgr.start({ run: function(){ }, interval: 1000});DelayedTask就是提供一個(gè)快捷的方式達到“緩沖”某個(gè)函數執行的目的。調用它之后,那個(gè)函數就會(huì )等待某段時(shí)間過(guò)去以后才會(huì )被執行。在此等待的期間中,如果task方法再被調用,原來(lái)的調用計時(shí)就會(huì )被取消。因此每一周期內最好只調用task方法一次。譬如在用戶(hù)是否完成輸入的情景,這方法可適用:
var task = new Ext.util.DelayedTask(function(){ alert(Ext.getDom('myInputField').value.length); }); // 調用函數之前等待500ms,如果用戶(hù)在500ms內按下其他的鍵,這就會(huì )等于作廢,重新開(kāi)始500ms的計算。 Ext.get('myInputField').on('keypress', function(){ task.delay(500); });注意我們這里是為了指出DelayedTask的用途。登記事件的同時(shí)也能對addListener/on的配置項設置DelayedTask其參數的。
JavaScript本身是基于原型的,這與普通基于類(lèi)的編程語(yǔ)言相比,在實(shí)現繼承的機制上有較大的出入。JavaScript中創(chuàng )建一個(gè)新類(lèi)那便是修改了某個(gè)對象原型(prototype)的結果。Ext提供了許多簡(jiǎn)化這方面工作的函數。有關(guān)不同繼承方案的討論可參考這里。
Ext支持以下類(lèi)風(fēng)格的編程行為:繼承擴展(extend),重寫(xiě)(overrride)/直接覆蓋。這意味著(zhù)開(kāi)發(fā)者可以根據需求加入自己的行為,創(chuàng )建自己的類(lèi),或者修改某些函數讓其更加合適。
extend
Ext.extend方法創(chuàng )建新一個(gè)類(lèi)之定義。第一個(gè)參數是父類(lèi),第二個(gè)參數是屬性/函數的列表。第二個(gè)參數加入到對象的prototype中extend過(guò)后,Ext.extend還會(huì )產(chǎn)生一個(gè)superclass的引用,在第二個(gè)例子中有演示。
Person = Ext.extend(Object, { constructor: function(first, last){ this.firstName = first; this.lastName = last; } getName: function(){ return this.firstName + ' ' + this.lastName; }});Developer = Ext.extend(Person, { getName: function(){ if(this.isCoding){ return 'Go Away!'; }else{ // 訪(fǎng)問(wèn)父類(lèi)的方法 return Developer.superclass.getName.call(this); } }});var p = new Person('John', 'Smith');alert(p.getName());override
override方法也編輯、修改類(lèi)的其中一種途徑,不過(guò)本方法不會(huì )創(chuàng )建一個(gè)新類(lèi),而是對現有類(lèi)予以修改其行為,第一個(gè)參數是要覆蓋的類(lèi),第二個(gè)參數就是覆蓋列表。override方法實(shí)際是修改類(lèi)prototype的屬性。
// 我們已聲明的Person類(lèi)Ext.override(Person, { getName: function(){ // 覆蓋了舊行為,這次last name排頭 return this.lastName + ' ' + this.firstName; }});當在類(lèi)原型中的prototype放置某項成員時(shí),即表示所有該類(lèi)的實(shí)例都會(huì )使用該共享的prototype。除非您有特效的要求,否則不要在prototype的定義中放入非原始類(lèi)型的成員("primitive" types,像{}、[]數組,就屬非屬原始類(lèi)型成員。**翻譯疑問(wèn):字符型,布字型,數值型不屬于"primitive"??**)。
MyClass = Ext.extend(Object, { // 所有MyClass的實(shí)例都使用這{},不會(huì )“按引用”復雜新一份出來(lái)。 baseParams: {}, foo: function(){ this.baseParams.bar = 'baz'; }});Ext.onReady(function(){ var a = new MyClass(); var b = new MyClass(); a.foo(); // a已影響b的baseParams console.log(b.baseParams); });單例另一種較常見(jiàn)的說(shuō)法是“模塊設計模式”,如果某一個(gè)類(lèi)靜態(tài)方法較多,或者該類(lèi)只須要實(shí)例化一次,那么采用單例的模式就很不錯了。JavaScript的單例模式中,我們常常會(huì )創(chuàng )建私有JavaScript變量或通過(guò)高明的閉包手法建立私有的方法,以一段程序入口的范例代碼就能說(shuō)明多少問(wèn)題。
MyApp = function(){ var data; //外部無(wú)法訪(fǎng)問(wèn)data,這是的私有成員 return { init: function(){ // 初始化程序 }, getData: function(){ return data; } };}();Ext.onReady(MyApp.init, MyApp);觀(guān)察者(Observable,或訂閱者subscriber)模式常用于對象間的解藕,方便清楚了解其它對象的狀態(tài)。觀(guān)察者使用事件的概念,當主題的狀態(tài)有所改變,那么主題就會(huì )是觸發(fā)事件。換言之,狀態(tài)一改變,主題轄下的訂閱者就會(huì )接收到通知。為達到如此的靈活性,實(shí)現解藕編的程模型,很多Ext類(lèi)就從Observable繼承。創(chuàng )建一個(gè)自定義事件的類(lèi)定很簡(jiǎn)單:
var MyClass = Ext.extend(Ext.util.Observable, { constructor: function(config){ this.addEvents('datachanged'); // 聲明打算觸發(fā)的事件 MyClass.constructor.call(this, config); }, update: function(){ // 執行數據更新 // 對訂閱者送入我們指定的參數 // passed to the subscribers. this.fireEvent('datachanged', this, this.data.length); }});// 進(jìn)行事件的訂閱var c = new MyClass();c.on('datachanged', function(obj, num){ // 數據變化事件的反應});命名空間對組織代碼很方便,可在兩方面體現其益處:其一是用了命名空間,很大程度避免了全局空間被污染的問(wèn)題,污染全局的成員終究不是一個(gè)好習慣,例如Ext對象本身就是在全局空間的一個(gè)對象。要養成一個(gè)良好的習慣,就要把寫(xiě)好的類(lèi)放進(jìn)一個(gè)命名空間中,可以用你公司的名字或程序的名字決定命名;其二是有助規范好你的代碼,把相類(lèi)似的或相依賴(lài)的類(lèi)都放在同一個(gè)名命空間中,也方便向其它開(kāi)發(fā)者指明代碼其意圖。
// 兩種方式都是一樣的,后者的為佳。Ext.namespace( 'MyCompany', 'MyCompany.Application', 'MyCompany.Application.Reports');Ext.namespace('MyCompany.Application.Reports');聯(lián)系客服