zoukankan      html  css  js  c++  java
  • 读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

     

     

  • 相关阅读:
    事务处理语言(TCL)
    SQL,T-SQL简介
    centos 8 集群Linux环境搭建
    graphviz 的使用教程
    pyttsx3 的使用教程
    python 连接 SQL Server 数据库(使用 pymssql 库)
    python 连接 SQL Server 数据库(使用 pyodbc 库)
    C++注释规范
    IP分配及网段划分
    关于对象的浅度拷贝和深度拷贝
  • 原文地址:https://www.cnblogs.com/snandy/p/2504640.html
Copyright © 2011-2022 走看看