讀Ext之十五(操作批量元素)


前兩篇讀了Ext.Element,這篇介紹的Ext.CompositeElementLite類是對集合(Ext.Element)的操作。

Ext.select / Ext.element.select 依賴於Ext.CompositeElementLite。

 

類的大概結構如下(省略了掛在prototype上的很多方法),

Ext.CompositeElementLite = function(els, root){
    this.elements = [];
    this.add(els, root);
    this.el = new Ext.Element.Flyweight();
};
Ext.CompositeElementLite.prototype = {
    isComposite: true,    
    getElement : function(el){
        // Set the shared flyweight dom property to the current element
        var e = this.el;
        e.dom = el;
        e.id = el.id;
        return e;
    },
	...
};

構造器內定義了兩個個字段

this.elements 存放的是HTMLElement
this.el 是Ext.Element.Flyweight 對象

new 該類時

var cel = new Ext.Ext.CompositeElementLite(els,root); 

構造器調用了this.add,該方法如下:

add : function(els, root){
    var me = this,
        elements = me.elements;
    if(!els){
        return this;
    }
    if(Ext.isString(els)){
        els = Ext.Element.selectorFunction(els, root);
    }else if(els.isComposite){
        els = els.elements;
    }else if(!Ext.isIterable(els)){
        els = [els];
    }
    
    for(var i = 0, len = els.length; i < len; ++i){
        elements.push(me.transformElement(els[i]));
    }
    return me;
},

els有三種分支:

分支1,els為字符串(css選擇器如.cls)
調用Ext.Element.selectorFunction,返回數組。該函數是Ext.DomQuery.select的別名。Ext.DomQuery.select暫不提,只需了解調用后會返回一個數組,數組中存放的是HTMLElement。

分支2,els.isComposite為true
即els本身就是Ext.CompositeElementLite的實例對象,那么直接取該對象的elements賦值給els。


分支3,els不可迭代,即不是數組,也不是對象。
如傳一個div元素,那么將其包裝成數組。

 

for循環將數組中的元素一一添加到elements中。for中使用了transformElement方法,

// private
transformElement : function(el){
    return Ext.getDom(el);
},

這個方法用來將el轉成HTMLElement,下面依次看原型上的其它屬性,方法

isComposite: true,  

isComposite 用來表示對象是Ext.CompositeElementLite類的對象。僅在類內部使用。在上面提到的add方法中用到了。

 

接着是 getElement 方法,也僅在該類內部使用

getElement : function(el){
    // Set the shared flyweight dom property to the current element
    var e = this.el;
    e.dom = el;
    e.id = el.id;
    return e;
},

用來獲取構造器中定義的字段el(Ext.Element.Flyweight),Ext.Element.Flyweight基本上可以當成是Ext.Element。
這個方法設計很巧妙,它並沒有每次都new一個Ext.Element.Flyweight,然后賦值給this.el。而是繼續使用已有的this.el,只是更新了this.el.dom和this.el.id。

往下是 getCount方法,

getCount : function(){
    return this.elements.length;
}, 

該方法返回集合this.elements的長度。

 

接下來是 invoke 方法,

invoke : function(fn, args){
    var me = this,
        els = me.elements,
        len = els.length, 
        e, 
        i;
        
    for(i = 0; i < len; i++) {
        e = els[i];
        if(e){
            Ext.Element.prototype[fn].apply(me.getElement(e), args);
        }
    }
    return me;
},

簡單講就是將Ext.Element.prototype的函數fn在指定的上下文(me.getElement(e))上執行。

 

嗯,還是沒明白。實際上這個函數不是提供給客戶端程序員的,它是用來擴展Ext.CompositeElementLite類的。
即將Ext.Element原型上的所有方法都復制給Ext.CompositeElementLite的原型。以下代碼就是干這個事的

(function(){
var fnName,
    ElProto = Ext.Element.prototype,
    CelProto = Ext.CompositeElementLite.prototype;
    
for(fnName in ElProto){
    if(Ext.isFunction(ElProto[fnName])){
        (function(fnName){ 
            CelProto[fnName] = CelProto[fnName] || function(){
                return this.invoke(fnName, arguments);
            };
        }).call(CelProto, fnName);
       
    }
}
})();

這段代碼對於初學JS的程序員理解起來較困難。慢慢看吧..

接下來是 item 方法,

item : function(index){
    var me = this,
        el = me.elements[index],
        out = null;

    if(el){
        out = me.getElement(el);
    }
    return out;
},

它返回集合中指定的元素,如cel.item(1)返回集合中的第二個元素。

往下是 addListener 方法,

addListener : function(eventName, handler, scope, opt){
    var els = this.elements,
        len = els.length,
        i, e;
    
    for(i = 0; i<len; i++) {
        e = els[i];
        if(e) {
            Ext.EventManager.on(e, eventName, handler, scope || e, opt);
        }
    }
    return this;
},

用來給集合中的所有元素添加事件,內部使用前面提到的 Ext.EventManager.on方法。

 

接下來是 each 方法,

each : function(fn, scope){       
    var me = this,
        els = me.elements,
        len = els.length,
        i, e;
    
    for(i = 0; i<len; i++) {
        e = els[i];
        if(e){
            e = this.getElement(e);
            if(fn.call(scope || e, e, me, i)){
                break;
            }
        }
    }
    return me;
},

用來迭代集合中的元素,使用fn來調用,scope指定fn的上下文。與JQuery的 $().each 類似。

接着是 fill 方法,

fill : function(els){
    var me = this;
    me.elements = [];
    me.add(els);
    return me;
},

該方法會用新的元素集合填充elements。會清空之前的elements。

接下來是 filter 方法,

filter : function(selector){
    var els = [],
        me = this,
        elements = me.elements,
        fn = Ext.isFunction(selector) ? selector
            : function(el){
                return el.is(selector);
            };
            
    
    me.each(function(el, self, i){
        if(fn(el, i) !== false){
            els[els.length] = me.transformElement(el);
        }
    });
    me.elements = els;
    return me;
},

該方法用來過濾集合元素,條件selector可以是函數,也可以是css選擇器。把符合條件的存放到字段elements中。
內部使用了is方法,該方法在上一篇已經提到。

再往下是  indexof 方法,

indexOf : function(el){
    return this.elements.indexOf(this.transformElement(el));
},

很熟悉吧,和String和Array的indexOf類似,如果存在返回其索引,否則返回-1。內部實際使用的就是數組的indexOf方法。
indexOf是ECMAScript 5中數組新加的。IE6等老瀏覽器不支持,Ext給Array的原型添加了該方法,見 讀Ext之三(原型擴展) 。

接着看 replaceElement 方法,

replaceElement : function(el, replacement, domReplace){
    var index = !isNaN(el) ? el : this.indexOf(el),
        d;
    if(index > -1){
        replacement = Ext.getDom(replacement);
        if(domReplace){
            d = this.elements[index];
            d.parentNode.insertBefore(replacement, d);
            Ext.removeNode(d);
        }
        this.elements.splice(index, 1, replacement);
    }
    return this;
},

該方法會把集合中指定的元素(el)用新的元素(replacement)替換。domReplace為true則將文檔中的也替換,否則只替換集合elements中的。

最后一個方法是 clear,

clear : function(){
    this.elements = [];
}

顧名思義,用來 清空數組 。與 Prototype庫   不同的Ext是重新給數組this.elements賦值為空數組。
Prototype庫則是將數組的length賦值為0以實現清空。注意JS中數組的length是可寫的。其它語言如Java則是只讀的。

在篇頭我提到了Ext.select / Ext.Element.select,且說過該方法的實現依賴於Ext.CompositeElementLite。下面揭開面紗看看該方法源碼,

Ext.Element.select = function(selector, root){
    var els;
    if(typeof selector == "string"){
        els = Ext.Element.selectorFunction(selector, root);
    }else if(selector.length !== undefined){
        els = selector;
    }else{
        throw "Invalid selector";
    }
    return new Ext.CompositeElementLite(els);
};
Ext.select = Ext.Element.select;

可以看到Ext.select是Ext.Element.select的別名,它更簡短。Ext.select 在日常開發中經常使用到。
它相當於JQuery的選擇器,即往往是先定位到某(或某些)元素(或元素集合)后再進行一系列操作(方法調用)。不知注意到沒有,Ext.CompositeElementLite的方法中都會返回自身(this)。
因此可以實現 鏈式調用 的語法效果。如

Ext.select('p')
   .addClass('.cls')
   .on('click',function(){alert(this)});

選擇頁面中的段落p元素,為其添加類cls,再為其添加點擊事件。只要願意你可以一直點操作下去。

好了,介紹了怎么使用。看看它是如何實現的,

參數selector可以是css選擇器(字符串),可以是HTMLELement集合。將其作為參數傳給new Ext.CompositeElementLite。返回的是Ext.CompositeElementLite的實例對象。

 

很簡單,其實內部僅僅是new了個Ext.CompositeElementLite,了解了該類。其實就了解了Ext.select。

 

 

CompositeElementLite.js

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM