`
hideto
  • 浏览: 2678820 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Ext源码解析:2, DomQuery.js

阅读更多
fromhttp://www.beyondrails.com/blogs/19/edit

Extjs Introduction中提到:
引用

DomQuery is 2~3 times faster than jQuery/dojo/Mootools, Prototype is the most slowest one!

Speed Test测试页面: http://extjs.com/playpen/slickspeed/

Ext的DomQuery为啥这么快呢?
一是因为DomQuery的byId/byTag/byClassName/byAttribute/byPseudo等基本查询方法实现的比较好
二是因为DomQuery良好的结构和模块设计
三是因为DomQuery有一个查询缓存

DomQuery的Dom查询器分四种类型:
1,Element Selector
2,Attribute Selector
3,Pseudo Class Selector
4,CSS Value Selector

Ext的查询方法是Ext.query(String selector, [Node root]) : Array
Ext.query = Ext.DomQuery.select;

select方法的实现:
select : function(path, root, type){
    if(!root || root == document){
        root = document;
    }
    if(typeof root == "string"){
        root = document.getElementById(root);
    }
    var paths = path.split(",");
    var results = [];
    for(var i = 0, len = paths.length; i < len; i++){
        var p = paths[i].replace(trimRe, "");
        if(!cache[p]){
            cache[p] = Ext.DomQuery.compile(p);
            if(!cache[p]){
                throw p + " is not a valid selector";
            }
        }
        var result = cache[p](root);
        if(result && result != document){
            results = results.concat(result);
        }
    }
    if(paths.length > 1){
        return nodup(results);
    }
    return results;
}

可以看到,Ext对于selector做了一个cache,缓存结果为Ext.DomQuery.compile方法返回的一个function
返回的function接收一个参数root来指示从那个Dom元素开始查询
compile : function(path, type){
    type = type || "select";

    var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
    var q = path, mode, lq;
    var tk = Ext.DomQuery.matchers;
    var tklen = tk.length;
    var mm;

    // accept leading mode switch
    var lmode = q.match(modeRe);
    if(lmode && lmode[1]){
        fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
        q = q.replace(lmode[1], "");
    }
    // strip leading slashes
    while(path.substr(0, 1)=="/"){
        path = path.substr(1);
    }

    while(q && lq != q){
        lq = q;
        var tm = q.match(tagTokenRe);
        if(type == "select"){
            if(tm){
                if(tm[1] == "#"){
                    fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
                }else{
                    fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
                }
                q = q.replace(tm[0], "");
            }else if(q.substr(0, 1) != '@'){
                fn[fn.length] = 'n = getNodes(n, mode, "*");';
            }
        }else{
            if(tm){
                if(tm[1] == "#"){
                    fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
                }else{
                    fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
                }
                q = q.replace(tm[0], "");
            }
        }
        while(!(mm = q.match(modeRe))){
            var matched = false;
            for(var j = 0; j < tklen; j++){
                var t = tk[j];
                var m = q.match(t.re);
                if(m){
                    fn[fn.length] = t.select.replace(tplRe, function(x, i){
                                            return m[i];
                                        });
                    q = q.replace(m[0], "");
                    matched = true;
                    break;
                }
            }
            // prevent infinite loop on bad selector
            if(!matched){
                throw 'Error parsing selector, parsing failed at "' + q + '"';
            }
        }
        if(mm[1]){
            fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
            q = q.replace(mm[1], "");
        }
    }
    fn[fn.length] = "return nodup(n);\n}";
    eval(fn.join(""));
    return f;
}

而compile方法会使用正则表达式匹配selector,然后分别去选择调用quickId/getNodes/byId/byTag/byClassName等特定查询模式的实现function
正则表达式匹配selector:
matchers : [{
        re: /^\.([\w-]+)/,
        select: 'n = byClassName(n, null, " {1} ");'
    }, {
        re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
        select: 'n = byPseudo(n, "{1}", "{2}");'
    },{
        re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
        select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
    }, {
        re: /^#([\w-]+)/,
        select: 'n = byId(n, null, "{1}");'
    },{
        re: /^@([\w-]+)/,
        select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
    }
]

看看quickId/byId的实现:
function quickId(ns, mode, root, id){
    if(ns == root){
       var d = root.ownerDocument || root;
       return d.getElementById(id);
    }
    ns = getNodes(ns, mode, "*");
    return byId(ns, null, id);
}
function byId(cs, attr, id){
    if(cs.tagName || cs == document){
        cs = [cs];
    }
    if(!id){
        return cs;
    }
    var r = [], ri = -1;
    for(var i = 0,ci; ci = cs[i]; i++){
        if(ci && ci.id == id){
            r[++ri] = ci;
            return r;
        }
    }
    return r;
};

如果是在默认的document下查找一个指定id的元素,则直接调用document.getElementById
否则用getNodes得到所有的子Dom元素,再用byId来匹配Id,第一个匹配上的返回

操作符匹配:
operators : {
    "=" : function(a, v){
        return a == v;
    },
    "!=" : function(a, v){
        return a != v;
    },
    "^=" : function(a, v){
        return a && a.substr(0, v.length) == v;
    },
    "$=" : function(a, v){
        return a && a.substr(a.length-v.length) == v;
    },
    "*=" : function(a, v){
        return a && a.indexOf(v) !== -1;
    },
    "%=" : function(a, v){
        return (a % v) == 0;
    },
    "|=" : function(a, v){
        return a && (a == v || a.substr(0, v.length+1) == v+'-');
    },
    "~=" : function(a, v){
        return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
    }
}

pseudo class匹配:
first-child
last-child
nth-child
only-child
empty
contains
nodeValue
checked
not
any
odd
even
nth
first
last
has
next
prev
分享到:
评论

相关推荐

    Ext Js权威指南(.zip.001

    6.1 ext js的选择器:ext.domquery / 215 6.1.1 选择器的作用 / 215 6.1.2 使用ext.query选择页面元素 / 215 6.1.3 基本选择符 / 223 6.1.4 属性选择符 / 229 6.1.5 css属性值选择符 / 234 6.1.6 伪类选择符 ...

    extjs帮助文档

    - **概述**:Ext.DomQuery类提供了一个类似于jQuery的选择器引擎,用于查询DOM元素。 - **常用方法**: - `Ext.DomQuery.select(selector)`:选择符合指定CSS选择器的所有元素。 - `Ext.DomQuery.selectNode...

    extjs帮助文档pdf版

    Ext 类 (P.2) - **概述**:`Ext` 是 ExtJS 的核心命名空间,包含了全局的方法和属性。 - **用途**:提供了一个统一的入口来访问 ExtJS 库的功能,如创建组件、管理事件等。 - **常用方法**: - `Ext.create()`: ...

    extjs学习资源

    - **DOM查询**: `Ext.DomQuery`提供了类似jQuery的语法来选择DOM元素。 - **模板引擎**: `Ext.Template`允许开发者使用模板字符串创建HTML,并可以方便地插入数据。 ```javascript // 示例: 使用DomQuery选择元素...

    Ext深入浅出 数据传输

    11.17.2 扩展String......................... 306 11.17.3 扩展Function.................... 306 11.17.4 扩展Number......................... 308 11.17.5 扩展Array........................... 308 11.18 Ext....

    Ext+JS高级程序设计.rar

    第1章 Ext Core重要概念 2 1.1 Ext.Element 2 1.1.1 获取HTMLElement节点的Ext.Element实例 2 1.1.2 CSS样式操作 3 1.1.3 DOM查询与遍历 4 1.1.4 DOM操作 6 1.1.5 事件处理 9 1.1.6 尺寸大小 13 1.1.7 定位功能 14 ...

    ext自学宝典

    ### ext自学宝典知识点解析 #### 一、EXT简介与入门 **EXT**,全称为Extensible Tools,但在本文档中特指**Ext JS**,一个用于构建交互式Web应用程序的开源JavaScript框架。该框架提供了丰富的UI组件和数据管理...

    ExtJS 3.2的中文参考手册

    **EXT源码概述** - **源代码结构**: ExtJS的源代码组织清晰,易于理解和扩展。 - **发布细节**: 在发布源码时,会包含必要的文档和示例代码,方便开发者快速上手。 #### 9. **EXT程序规划入门** - **准备工作**:...

    Ext官方中文教程(可打包下载)

    Ext源码概述 Ext与RESTful Web Services 程序设计: 如何合理地规划一个应用程序 如何本地化ext的教程 xtype的含义 扩展Ext中的组件 扩展与插件之间的区别 扩展Ext的新手教程 Ext的类继承 从源码生成Ext 基础用法...

    EXT中文手册.pdf

    5. **DOM查询和Ext DomQuery**:Ext框架的DomQuery提供了一种基于CSS选择器的方式来查询DOM节点,这在处理动态生成的DOM结构时非常有用。例如,`Ext.select('p').highlight()`可以选中所有段落元素,并给它们添加...

    ext核心api详解(2)

    本文将深入探讨EXT JS的核心API,特别是关于Ext.DomQuery、Ext.DomHelper和Ext.Template这三个关键模块。 **Ext.DomQuery** Ext.DomQuery类提供了类似CSS的选择器功能,用于在DOM树中查找匹配的元素。其核心方法...

    EXT核心API详解.doc

    1. **Ext类**:EXT库的基础类,提供了许多实用的方法,如创建元素、事件处理等。 2. **Array类**:扩展了JavaScript原生的数组对象,提供了如each、indexOf、remove等功能,增强了数组操作能力。 3. **Number类**...

    Ext API详解--笔记

    Ext Js 是一个强大的JavaScript库,主要用于构建富客户端应用程序。它提供了丰富的组件模型、数据绑定机制以及一套完整的API,使得开发者可以高效地创建交互式的Web应用。这篇笔记将深入探讨Ext Js的核心API,涵盖多...

    EXTJS 中文手册 电子书

    Element:Ext的核心 .......................................................................................... 6 获取多个DOM的节点 .........................................................................

    EXT核心API详解(第一部分)

    3. **基本数据类型扩展**:EXT JS扩展了JavaScript的基本数据类型,如Array、Date、Function和Number。例如,`Array`增加了一些便利的方法,如`Array.each`进行数组遍历,`Array.indexOf`查找元素索引,`Array....

    ext培训第四讲.doc 4/4

    #### 一、Element:Ext 的核心组件 ##### 1.1 Element 概念介绍 Element 是 Ext 库的核心组成部分,它简化了对 DOM 元素的操作并提供了丰富的功能,使得开发者能够更加高效地进行前端开发工作。与传统 JavaScript ...

    ext-word文档

    #### EXT源码概述 深入了解ExtJS的源码可以帮助开发者更好地掌握其工作原理。ExtJS的源码组织结构清晰,分为多个模块,如`core`(核心)、`adapter`(适配器)等。通过研究源码,可以学习到如何扩展和自定义组件。 ...

Global site tag (gtag.js) - Google Analytics