`
hideto
  • 浏览: 2650120 次
  • 性别: 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 伪类选择符 ...

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

    EXT核心API详解

    1、Ext类 ………………………………… 2 2、Array类 …………………………… 4 3、Number类 …………………………… 4 4、String类 …………………………… 4 5、Date类 ……………………………… 5 6、Function类 ...

    EXTJS 中文手册 电子书

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

    精通JS脚本之ExtJS框架.part1.rar

    16.7.2 商品信息的添加 16.7.3 商品信息的删除 16.7.4 商品信息的更新 第17章 ExtJS案例:企业任务管理系统 17.1 系统概述 17.2 需求分析 17.3 数据库设计 17.4 员工任务管理 17.4.1 个人任务处理 17.4.2 ...

    精通JS脚本之ExtJS框架.part2.rar

    16.7.2 商品信息的添加 16.7.3 商品信息的删除 16.7.4 商品信息的更新 第17章 ExtJS案例:企业任务管理系统 17.1 系统概述 17.2 需求分析 17.3 数据库设计 17.4 员工任务管理 17.4.1 个人任务处理 17.4.2 ...

    ExtJSWeb应用程序开发指南(第2版)

    6.13.2 废弃原有键盘绑定 6.13.3 将废弃的键盘绑定重新生效 6.14 Ext.KeyMap提供更灵活强大的对按键的处理方法 6.14.1 构造函数 6.14.2 给对象添加键盘绑定 6.14.3 废弃已绑定到KeyMap的配置 6.14.4 将KeyMap...

    ExtJS入门教程(超级详细)

    1、Ext类 ………………………………… 2 2、Array类 …………………………… 4 3、Number类 …………………………… 4 4、String类 …………………………… 4 5、Date类 ……………………………… 5 6、Function类 ...

    Ext 学习中文手册

    Ext官方网站+中文教程 无论你是Ext库的新手,抑或是想了解Ext的人,本篇文章的内容都适合你。本文将简单地介绍Ext的几个基本概念,和如何快速地做出一个动态的...Step 2: Ext结构的构建 96 Step 3: 创建Tab控制逻辑 97

    EXT简体中文参考手册(PDF&CHM电子档)

    目录 EXT 中文手册 1 EXT简介 3 目錄 3 下载Ext 4 开始! 4 Element:Ext的核心 4 获取多个DOM的节点 5 响应事件 5 使用Widgets 7 ...EXT源码概述 11 ...Step 2: Ext结构的构建 96 Step 3: 创建Tab控制逻辑 97

    EXT 中文帮助手册

    4 Element:Ext的核心 4 获取多个DOM的节点 5 响应事件 5 使用Widgets 7 使用Ajax 9 EXT源码概述 11 揭示源代码 11 发布Ext源码时的一些细节 12 我应该从哪里开始? 13 适配器...

    EXT 中文手册

    4 Element:Ext的核心 4 获取多个DOM的节点 5 响应事件 5 使用Widgets 7 使用Ajax 9 EXT源码概述 11 揭示源代码 11 发布Ext源码时的一些细节 12 我应该从哪里开始? 13 适配器...

    EXTjs组件解释文档

    包括从基础到深入的EXTjs组件解释,EXTjs实例,EXT核心API详解,Ext.DomQuery类

    幻影:无头基于Chromium的Web性能指标收集器和监视工具

    幻影 基于的模块化Web性能指标收集器。 为什么是幻影? 好吧,:)要求 12以上安装通过npm npm install phantomas这将安装puppeteer模块支持 。通过Docker 您可以使用: docker pull macbre/phantomas:latest支持 您...

    React-Flux-Pages-Boilerplate

    –React+助焊剂+通天塔– Gulp – domquery(用于dom操作) – TweenMax TimelineMax –十字路口+哈希器(用于路由) – lodash –大小元素(获取dom元素的宽度和高度) $ bower install $ npm install // For ...

Global site tag (gtag.js) - Google Analytics