Ruby's Louvre

每天学习一点点算法

导航

dom Framework query模块

我自行开发、引以为豪的CSS3选择器,jQuery能支持的选择器基本都支持了,除了那个:has伪类外。由于选择器种类繁多,也不太好演示,因此请下载文档回来看吧。

用法基本与jQuery一样,下面是一个简单示例:

    dom.ready(function(){
        dom(".sample :hidden").each(function(){
          if(this.type){
            dom.console.log(this.tagName+"  "+this.type)
          }else{
            dom.console.log(this.tagName)
          }
        });
    });

源码:

 
/*dom Framework version 1.0
Copyright 2010
Dual licensed under the MIT or GPL Version 2 licenses.
author: <ruby> <rb>司徒正美<rp>(zhongqincheng)</rp></rb><rt>しとぅなさみ</rt></ruby>
http://www.cnblogs.com/rubylouvre/
*/
//=========================================
// 选择器模块
//==========================================
;;;(function(dom,window,undefined){
    dom.provide("query");
    dom.lib.quickTag = false;
    dom.lib.isNot = false;
    dom.lib.pageOrder = ("sourceIndex" in document.documentElement) ?  function (a, b) {
        return (a.sourceIndex - b.sourceIndex);
    }:function (a, b) {
        return (3 - (a.compareDocumentPosition(b) & 6));
    };
    var getUIDXML = function(node){
        var uid = node.getAttribute(dom.expando);
        if (!uid){
            uid = dom.uuid++
            node.setAttribute(dom.expando, uid);
        }
        return uid;
    };
    var getUIDHTML = function(node){
        return node.uniqueNumber || (node.uniqueNumber = dom.uuid++);
    };
    //用于获取选择器的类型
    var types_ = {
        "#":"id",        //ID选择器
        ".":"class",     //类选择器
        /*"tag";         //标签选择器*/
        "[":"attribute", //属性选择器
        " ":"descendant",//关系选择器(后代选择器)
        ">":"child",     //关系选择器(亲子选择器)
        "+":"adjacent",  //关系选择器(相邻选择器)
        "~":"general",   //关系选择器(兄长选择器)
        ":":"pseudo",    //伪类选择器
        ",":"combine",   //联合选择器
        "*":"wildcard"   //通配符选择器
    }
    //用于移除相应的选择器
    var regexes_ = {
        id: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,      //ID选择器
        tag: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,   //标签选择器
        attribute: /\[((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)(['"]*)(.*?)\3|)\]/, //属性选择器
        "class": /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,//类选择器
        pseudo: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/, //伪类选择器
        combine: /,/,                               //联合选择器
        child:/^(\>)\s*(\w*|\*)/,                    //亲子选择器
        adjacent:/^(\+)\s*(\w*|\*)/,                 //相邻选择器
        general:/^(\~)\s*(\w*|\*)/,                  //兄长选择器
        descendant: /\s+(\.((?:[\w\u00c0-\uFFFF_-]|\\.)+))?/,            //后代选择器
        wildcard :/\*/                               //通配符选择器
    };
    var queryPseudoHasExp = function(start_,next_,noCheck_){
        return {
            curry :function(lastResult,flag,a ,b){
                //将外围变量变成本地变量
                var start = start_,next = next_, isAll = noCheck_,
                result = [],ri = 0, uniqResult = {},
                i = 0, n = lastResult.length, el, uid, find;
                while (i < n) {
                    el = lastResult[i++];
                    uid = flag.uuid(el),
                    find = uniqResult[uid];
                    if (find === void 0) {
                        for (var c = 0, node = el.parentNode[start], nodeName = el.nodeName;node; node = node[next])
                            if (node.nodeType === 1 && (isAll || nodeName === node.nodeName)) {
                                ++c;
                                uniqResult[flag.uuid(node)] = a === 0 ? c === b : (c - b) % a === 0 && (c - b) / a >= 0;
                            }
                        find = uniqResult[uid];
                    }
                    if (find ^ dom.lib.isNot)
                        result[ri++] = el;
                }
                return result;
            }
        }
    }

    var queryPseudoNoExp = function(_direction,_noCheck){
        return {
            curry : function(lastResult){
                var result = [],ri = 0,els = lastResult,direction = _direction,isAll = _noCheck;
                for (var i = 0, el; el = els[i]; i++) {
                    var tagName = isAll || el.nodeName, find = null
                    if (find === null && direction <= 0){
                        for (var node = el.previousSibling; node; node = node.previousSibling)
                            if (node.nodeType === 1 && (isAll || node.nodeName === tagName)) {
                                find = false;
                                break;
                            }
                    }
                    if (find === null && direction >= 0)
                        for (var node = el.nextSibling; node; node = node.nextSibling)
                            if (node.nodeType === 1 && (isAll || node.nodeName === tagName)) {
                                find = false;
                                break;
                            }
                    if (find === null)//如果本身就是first-child或last-child
                        find = true;
                    if (find ^ dom.lib.isNot)//参与运算的两个值,如果两个相应bit位相同,则结果为0,否则为1。
                        result[ri++] = el;
                }
                return result;
            }
        }
    }

    var filters = { //伪类选择器的过滤器
        enabled: function(el){//标准
            return el.disabled === false && el.type !== "hidden";
        },
        disabled: function(el){//标准
            return el.disabled === true;
        },
        checked: function(el){//标准
            return el.checked === true;
        },
        indeterminate:function(el){//标准
            return el.indeterminate = true && el.type === "checkbox"
        },
        selected: function(el){
            el.parentNode.selectedIndex;
            return el.selected === true;
        },
        empty: function (el) {//标准
            return !el.firstChild;
        },
        lang: function (el, value) {//标准
            var reg = new RegExp("^" + value, "i")
            while (el && !el.getAttribute("lang"))
                el = el.parentNode;
            return  !!(el && reg.test(el.getAttribute("lang")));
        },
        header: function(el){
            return /h\d/i.test( el.nodeName );
        },
        button: function(el){
            return "button" === el.type || el.nodeName === "BUTTON";
        },
        input: function(el){
            return /input|select|textarea|button/i.test(el.nodeName);
        },
        hidden : function( el ) {
            dom.require("node");
            return el.type === "hidden" || dom.getStyle(el,"display") === "none"
        },
        visible : function( el ) {
            dom.require("node");
            return el.type !== "hidden" && dom.getStyle(el,"display") !== "none"
        },
        link:function(el){
            return el.nodeName.toLowerCase() === "a";
        },
        root:function(el,exp,context){//标准
            return el ===  context.documentElement;
        },
        target:function(el,exp,context){//标准
            var id = context.location.hash.slice(1);
            return (el.id || el.name) === id;
        },
        parent : function( el ) {
            return !!el.firstChild;
        },
        contains: function(el, exp) {
            return (el.textContent||el.innerText||'').indexOf(exp) !== -1
        },
        "first-child":      queryPseudoNoExp(-1, true),//标准
        "last-child":       queryPseudoNoExp( 1, true),//标准
        "only-child":       queryPseudoNoExp( 0, true),//标准
        "first-of-type":    queryPseudoNoExp(-1, false),//标准
        "last-of-type":     queryPseudoNoExp( 1, false),//标准
        "only-of-type":     queryPseudoNoExp( 0 ,false),//标准
        "nth-child":        queryPseudoHasExp("firstChild", "nextSibling",     true),//标准
        "nth-last-child":   queryPseudoHasExp("lastChild",  "previousSibling", true),//标准
        "nth-of-type":      queryPseudoHasExp("firstChild", "nextSibling",     false),//标准
        "nth-last-of-type": queryPseudoHasExp("lastChild",  "previousSibling", false),//标准
        //与位置相关的过滤器
        first: function(index){
            return index === 0;
        },
        last: function(index, num){
            return index === num;
        },
        even: function(index){
            return index % 2 === 0;
        },
        odd: function(index){
            return index % 2 === 1;
        },
        lt: function(index, num){
            return index < num;
        },
        gt: function(index, num){
            return index > num;
        },
        eq: function(index, num){
            return index ===  num;
        }
    };
    dom.each(String("text radio checkbox file password submit image reset").match(/\w+/g),
        function(name){
            filters[name] = function(el){
                return el.type === name
            }
        });

    var parseNth = function (exp) {
        var match = /(-?)(\d*)n([-+]?\d*)/.exec(exp === "even" && "2n" || exp === "odd" && "2n+1" || !/\D/.test(exp) && "0n+" + exp || exp);
        return {
            a: (match[1] + (match[2] || 1)) - 0,
            b: match[3] - 0
        };
    };

    var _position = dom.oneObject(String("eq gt lt first last even odd").match(/\w+/g));

    //http://www.cnblogs.com/rubylouvre/archive/2009/11/25/1610044.html
    dom.queryId = function (id, context) {
        var el = (context || document).getElementById(id);
        return el && [el] || []
    };
    if(dom.env.mixupsName){
        //如果浏览器的getElementById不能区分name与id
        dom.queryId = function(id,root){
            root = root || document;
            var el = root.getElementById(id);
            if (el && el.attributes['id'].value === id) {
                return [el]
            } else {
                var all = root.all[id];
                for(var i=0;el=all[i++];){
                    if(el.attributes['id'].value === id)
                        return [el]
                }
                return []
            }
        }
    }

    var queryWildcard = function (root) {//获得页面上或者某个元素节点下的所有元素
        var all =  root.all || root.getElementsByTagName("*"),result;
        if(dom.ie){
            result = dom.filter(all,function(el){
                return el.nodeType === 1
            });
            if(dom.env.traverseAllElements)
                dom.merge(result,(root.getElementsByTagName("param") || []))
            return result;
        }else{
            return dom.slice(all);
        }
    };

    var queryTag = function(tagName, lastResult, tools){
        var result = [],ri = 0, n = lastResult.length, uniqResult = {},nodes;
        if(dom.lib.isNot){
            var all = n ? lastResult :queryWildcard(tools.context);
            return dom.filter(all,function(el){
                return el.tagName !== tagName;
            });
        }
        if (n === 0) {
            return dom.slice(tools.context.getElementsByTagName(tagName))
        } else {
            var i = 0 ,j ,jn ,node ,uid ;
            if(dom.lib.quickTag ){
                dom.lib.quickTag = false;
                while(i < n){
                    nodes = lastResult[i++].getElementsByTagName(tagName);
                    j = 0;
                    jn = nodes.length;
                    while(j < jn){
                        node = nodes[j++];
                        uid = tools.uuid(node);
                        if(uniqResult[uid] !== node){
                            result[ri++] = uniqResult[uid] = node;
                        }
                    }
                }
                return result;
            }else{
                while(i < n){
                    node = lastResult[i++];
                    if(node.nodeName === tagName )
                        result[ri++] = node;
                }
                return result;
            }
        }
    }

    var queryClass = function (className, lastResult, tools) {
        var result = [],ri = 0,i = 0, n = lastResult.length, el,
        reg =  new RegExp('(?:^|[ \\t\\r\\n\\f])' + className + '(?:$|[ \\t\\r\\n\\f])');
        if (n === 0) {//查找模式
            if (tools.byClass) {
                return Array.prototype.slice.call(tools.context.getElementsByClassName(className));
            } else {
                var els = tools.context.all || tools.context.getElementsByTagName("*");
                for(i=0;el=els[i++];){
                    if(reg.test(el.className || el.getAttribute("class")))
                        result[ri++] = el;
                }
                return result;
            }
        } else {//过滤模式
            for(i=0;el=lastResult[i++];){
                if(reg.test(el.className || el.getAttribute("class")) ^ dom.lib.isNot)
                    result[ri++] = el;
            }
            return result;
        }
    }

    var queryDescendant = function(className,lastResult,tools){//后代选择器
        var result = [],ri = 0, isAll = !className,//如果为空字符串或undefined
        uniqResult = {}, i = 0 ,n = lastResult.length, j ,jn ,
        nodes, node,el, reg, uid;
        if(!isAll){
            reg =  new RegExp('(?:^|[ \\t\\r\\n\\f])' + className + '(?:$|[ \\t\\r\\n\\f])');
        }
        lastResult = lastResult.sort( dom.lib.pageOrder );
        //className二级查找模式,利用原生的getElementsByClassName实现高速化
        if(!isAll && tools.byClass){
            while(i < n){
                nodes = lastResult[i++].getElementsByClassName(className);
                j = 0;
                jn = nodes.length;
                while(j < jn){
                    node = nodes[j++];
                    uid = tools.uuid(node)
                    if(uniqResult[uid] !== node){
                        result[ri++] = uniqResult[uid] = node;
                    }
                }
            }
        }else{
            while(i < n){
                el = lastResult[i++];
                if(uniqResult[tools.uuid(el)] !== el){
                    nodes = el.all || el.getElementsByTagName("*");
                    j = 0;
                    jn = nodes.length;
                    //className二级查找模式
                    while(j < jn){
                        node = nodes[j++];
                        if(uniqResult[tools.uuid(node)] === node) break;
                        if(node.nodeType === 1 && (isAll || reg.test(node.className || node.getAttribute("class")))){
                            uid = tools.uuid(node);
                            if(uniqResult[uid] === node){
                                break;
                            }else{
                                result[ri++] = uniqResult[uid] = node;
                            }
                        }
                    }
                }
            }
        }
        return result;
    };

    var queryChild  = function (nodeName,lastResult,tools) {//亲子选择器
        var isAll = nodeName === "*",result = [],ri = 0,
        n = lastResult.length,i = 0 ,nodes ,node,j , jn,
        prop = tools.children ? "children" : "childNodes";
        while(i < n){
            nodes = lastResult[i++][prop];
            j = 0;
            jn = nodes.length;
            while(j < jn){
                node = nodes[j++];
                if( ( tools.children || node.nodeType === 1) &&(isAll || nodeName === node.nodeName))
                    result[ri++] = node;
            }
        }
        return result;
    };

    var queryGeneral = function (nodeName,lastResult,tools) {//兄长选择器
        var isAll = nodeName === "*",result = [],ri = 0,
        n = lastResult.length,i = 0 ,uniqResult = {}, uid, node,
        prop = tools.element ? "nextElementSibling" :"nextSibling"
        while(i < n){
            node = lastResult[i++];
            if(uniqResult[tools.uuid(node)] !== node){
                for(node = node[prop];node;node = node[prop]){
                    if(uniqResult[node.uuid] === node) break;
                    if(( tools.element || node.nodeType === 1) && (isAll || nodeName === node.nodeName)){
                        uid = tools.uuid(node)
                        if(uniqResult[uid]){
                            break;
                        }else{
                            result[ri++] = uniqResult[uid] = node;
                        }
                    }
                }
            }
        }
        return result;
    };

    var queryAdjacent = function (nodeName,lastResult,tools) { //相邻选择器
        var isAll = nodeName === "*", result = [],ri = 0,
        n = lastResult.length,i = 0 ,node,
        prop = tools.element ? "nextElementSibling" :"nextSibling";
        while(i < n){
            node = lastResult[i++];
            for(node = node[prop];node;node = node[prop]){
                if(tools.element || node.nodeType === 1){
                    if (isAll || nodeName === node.nodeName)
                        result[ri++] = node;
                    break;
                }
            }
        }
        return result;
    };

    var queryAttribute = function (name,operator,value,lastResult, root) { //属性选择器
        if(lastResult.length === 0)
            lastResult = queryWildcard(root);
        var result = [],ri = 0,reg;
        switch (operator) {
            case '$=':reg =  new RegExp(   value + '$' );break ;
            case '~=':reg =  new RegExp(  '(?:^|[ \\t\\r\\n\\f])' + value + '(?:$|[ \\t\\r\\n\\f])');break;
            case '|=':reg =  new RegExp(  '(?:^|\\|)' + value + '(?:$|\\|)');break;
        }

        var el , i = 0 ,n = lastResult.length,attrib,flag

        while(i < n){
            el = lastResult[i++];
            attrib = dom.attr(el, name);//取得元素的实际属性值
            flag = (attrib != null) && (attrib !== "");
            if(flag && operator)
                switch (operator) {
                    case '=':  flag =  attrib === value ;break ;
                    case '!=': flag =  attrib !== value ;break ;
                    case '^=': flag =  attrib.indexOf(value) === 0 ;break ;
                    case '*=': flag =  attrib.indexOf(value) !== -1 ;break ;
                    default :  flag =  reg.test(attrib);break;
                }
            if (!!flag  ^ dom.lib.isNot)
                result[ri++] = el;
        }
        return result;
    }

    var queryPseudo = function (type, exp, lastResult,tools){//伪类选择器
        var position = _position
        if(lastResult.length === 0 )
            lastResult = queryWildcard(tools.context);
        var filter = filters[type], i = 0, n = lastResult.length, result = [],ri = 0, el;
        if(position[type]){//处理位置伪类
            //如果exp为空白则将集合的最大索引值传进去,否则将exp转换为数字
            exp = (exp === ""|| exp === void 0) ? n - 1 : ~~exp;
            while(i < n){
                el = lastResult[i];
                if(filter(i++, exp) ^ dom.lib.isNot)
                    result[ri++] = el;
            }
            return result;
        }
        if((typeof filter === "object") && filter.curry){
            var p = parseNth(exp);
            return filter.curry(lastResult, tools, p.a, p.b);
        }
        //处理target root checked disabled empty enabled lang 等伪类
        while(i < n){
            el = lastResult[i++];
            if(filter(el, exp, tools.context) ^ dom.lib.isNot)
                result[ri++] = el;
        }
        return result;
    };

    //适配器,根据选择器的类型调用相应的函数去处理
    var dispatcher_ = {
        wildcard:function(array, nodes, tools) {    //通配符选择器
            return dom.lib.isNot ? [] :queryWildcard(tools.context);
        },
        tag : function(array, nodes, tools){ //标签选择器
            var nodeName = tools.xml ? array[0] :array[0].toUpperCase();
            return queryTag(nodeName , nodes, tools);
        },
        id : function(array, nodes, tools){               //ID选择器
            var id = array[1];
            return dom.lib.isNot ? queryAttribute("id","=",id, nodes ,tools.context)
            :dom.queryId(id, tools.context);
        },
        "class":function(array, nodes, tools){     //类选择器
            var className = array[1];
            return dom.lib.isNot ? queryAttribute("class","~=",className,nodes, tools.context):
            queryClass(className, nodes, tools);
        },
        descendant:function(array, nodes, tools){ //后代选择器(第一个参数为className)
            return queryDescendant(array[2], nodes, tools);
        },
        child:function(array, nodes,tools){       //亲子选择器(第一个参数为nodeName)
            var nodeName = array[2] || "*"
            nodeName = tools.xml ? nodeName :nodeName.toUpperCase();
            return queryChild(nodeName,nodes,tools);
        },
        general:function(array, nodes,tools){    //兄长选择器(第一个参数为nodeName)
            var nodeName = array[2] || "*"
            nodeName = tools.xml ? nodeName :nodeName.toUpperCase();
            return queryGeneral(nodeName,nodes,tools);
        },
        adjacent:function(array, nodes,tools){   //相邻选择器(第一个参数为nodeName)
            var nodeName = array[2] || "*"
            nodeName = tools.xml ? nodeName :nodeName.toUpperCase();
            return queryAdjacent(nodeName,nodes,tools)
        },
        attribute:function(array, nodes, tools){ //属性选择器
            return queryAttribute(array[1], array[2], array[4], nodes, tools.context);
        },
        pseudo:function(array, nodes,tools){      //伪类选择器
            return queryPseudo(array[1], array[3], nodes, tools);
        }
    }
    var isRelationAndTag_ = dom.oneObject(String("adjacent general child descendant tag").match(/\w+/g));
    var removeBlank_ = /\s*([>,\+\~=])\s*(?=(?:(?:[^"']*"[^"']*){2}|(?:[^"']*'[^"']*){2})*[^"']*$)/g;

    dom.query = function (selectors, context, lastResult) {
        var result = [],
        types = types_,//引用外围变量
        regexes = regexes_,//引用外围变量
        dispatcher = dispatcher_,//引用外围变量
        removeBlank = removeBlank_,
        root = context.documentElement,
        //若关系选择器与tag选择器跟着ID选择器,则可以直接kill掉前面的
        isRelationAndTag = isRelationAndTag_,
        xml = dom.isXML(context),
        tools = {//用于装载当前文档的各种判定
            xml : xml,
            children : "children" in root,
            context : context,
            //http://www.w3.org/TR/ElementTraversal/
            element : "nextElementSibling" in root,
            byClass : "getElementsByClassName" in root,
            uuid: xml ? getUIDXML : getUIDHTML
        };
        selectors = selectors.replace(removeBlank, function ($1, $2) {
            return $2;
        });
        selectors = selectors.replace(/^\s+|\s+$/g, '');
        if("querySelectorAll" in context){
            try{
                var els = context.querySelectorAll(selectors);

                if(dom.env.sliceNodes){
                    return Array.prototype.slice.call(els);
                }else{
                    return dom.filter(els,function(el){
                        return el.nodeType === 1
                    });
                }

            }catch(e){  }
        }

        while (selectors.length) {
            var type = types[selectors.charAt(0)] || "tag",
            regex = regexes[type],
            array = selectors.match(regex),//使用match才有rightContext,exec没有
            segment = RegExp.lastMatch;
            selectors = RegExp.rightContext;
            //后代选择器跟紧标签选择器的情形进行优化,如p span或#id span 或.class span
            //属于高级查找 var els = el.getElementsByTagName(tag)
            if(lastResult.length && type === "descendant"){
                if(/[a-z0-9A-Z_]/.test(selectors.charAt(0))){//处理div div的情形
                    dom.lib.quickTag = true;
                    continue;
                }
                if(selectors.charAt(0) === "*"){//处理div *的情况
                    selectors = selectors.slice(1)
                }
            }
            //如果是并联选择器,那么就把上次的结果集放进最终结果集中
            if(type === "combine") {
                result = result.concat(lastResult);
                lastResult = [];
                continue;
            } else if(isRelationAndTag[type] && selectors.charAt(0) === "#"){
                continue;
            }else if(segment.slice(0,4) === ":not"){
                var add = segment.match(regexes.pseudo)[3] || "";
                selectors = add + ":yes()"+ selectors ;//自定义一个伪类,标明反选选择器的结束
                dom.lib.isNot = true;                  //使用反选选择器,反选选择器的括号里可以含有以下选择器
                continue;                              //id,class,attribute,pseudo(not除外)
            }else if(segment.slice(0,4) === ":yes"){
                dom.lib.isNot = false;
                continue;
            }
            lastResult = dispatcher[type](array, lastResult, tools );
            //如果结果集的长度为零,则中止循环
            if (lastResult === undefined || lastResult.length === 0) {
                break;
            }
        }
        //返回最终结果
        return result.concat(lastResult);
    }
})(window[escape(document.URL.split("#")[0])],this);
/*dom Framework version 1.0 Copyright 2010 Dual licensed under the MIT or GPL Version 2 licenses. author: <ruby> <rb>司徒正美<rp>(zhongqincheng)</rp></rb><rt>しとぅなさみ</rt></ruby> http://www.cnblogs.com/rubylouvre/ */ //========================================= // 选择器模块 //========================================== ;;;(function(dom,window,undefined){ dom.provide("query"); dom.lib.quickTag = false; dom.lib.isNot = false; dom.lib.pageOrder = ("sourceIndex" in document.documentElement) ? function (a, b) { return (a.sourceIndex - b.sourceIndex); }:function (a, b) { return (3 - (a.compareDocumentPosition(b) & 6)); }; //用于获取选择器的类型 var types_ = { "#":"id", //ID选择器 ".":"class", //类选择器 /*"tag"; //标签选择器*/ "[":"attribute", //属性选择器 " ":"descendant",//关系选择器(后代选择器) ">":"child", //关系选择器(亲子选择器) "+":"adjacent", //关系选择器(相邻选择器) "~":"general", //关系选择器(兄长选择器) ":":"pseudo", //伪类选择器 ",":"combine", //联合选择器 "*":"wildcard" //通配符选择器 } //用于移除相应的选择器 var regexes_ = { id: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/, //ID选择器 tag: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/, //标签选择器 attribute: /\[((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)(['"]*)(.*?)\3|)\]/, //属性选择器 "class": /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,//类选择器 pseudo: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/, //伪类选择器 combine: /,/, //联合选择器 child:/^(\>)\s*(\w*|\*)/, //亲子选择器 adjacent:/^(\+)\s*(\w*|\*)/, //相邻选择器 general:/^(\~)\s*(\w*|\*)/, //兄长选择器 descendant: /\s+(\.((?:[\w\u00c0-\uFFFF_-]|\\.)+))?/, //后代选择器 wildcard :/\*/ //通配符选择器 }; var queryPseudoHasExp = function(start_,next_,noCheck_){ return { curry :function(lastResult,a ,b){ //将外围变量变成本地变量 var start = start_,next = next_, isAll = noCheck_, result = [],ri = 0, uniqResult = {}, i = 0, n = lastResult.length, el, uid, find; while (i < n) { el = lastResult[i++]; uid = el.uuid || (el.uuid = "dom-"+ dom.uuid++), find = uniqResult[uid]; if (find === void 0) { for (var c = 0, node = el.parentNode[start], nodeName = el.nodeName;node; node = node[next]) if (node.nodeType === 1 && (isAll || nodeName === node.nodeName)) { ++c; uniqResult[node.uuid || (node.uuid = "dom-"+ dom.uuid++)] = a === 0 ? c === b : (c - b) % a === 0 && (c - b) / a >= 0; } find = uniqResult[uid]; } if (find ^ dom.lib.isNot) result[ri++] = el; } return result; } } } var queryPseudoNoExp = function(_direction,_noCheck){ return { curry : function(lastResult){ var result = [],ri = 0,els = lastResult,direction = _direction,isAll = _noCheck; for (var i = 0, el; el = els[i]; i++) { var tagName = isAll || el.nodeName, find = null if (find === null && direction <= 0){ for (var node = el.previousSibling; node; node = node.previousSibling) if (node.nodeType === 1 && (isAll || node.nodeName === tagName)) { find = false; break; } } if (find === null && direction >= 0) for (var node = el.nextSibling; node; node = node.nextSibling) if (node.nodeType === 1 && (isAll || node.nodeName === tagName)) { find = false; break; } if (find === null)//如果本身就是first-child或last-child find = true; if (find ^ dom.lib.isNot)//参与运算的两个值,如果两个相应bit位相同,则结果为0,否则为1。 result[ri++] = el; } return result; } } } var filters = { //伪类选择器的过滤器 enabled: function(el){//标准 return el.disabled === false && el.type !== "hidden"; }, disabled: function(el){//标准 return el.disabled === true; }, checked: function(el){//标准 return el.checked === true; }, indeterminate:function(el){//标准 return el.indeterminate = true && el.type === "checkbox" }, selected: function(el){ el.parentNode.selectedIndex; return el.selected === true; }, empty: function (el) {//标准 return !el.firstChild; }, lang: function (el, value) {//标准 var reg = new RegExp("^" + value, "i") while (el && !el.getAttribute("lang")) el = el.parentNode; return !!(el && reg.test(el.getAttribute("lang"))); }, header: function(el){ return /h\d/i.test( el.nodeName ); }, button: function(el){ return "button" === el.type || el.nodeName === "BUTTON"; }, input: function(el){ return /input|select|textarea|button/i.test(el.nodeName); }, hidden : function( el ) { dom.require("node"); return el.type === "hidden" || dom.getStyle(el,"display") === "none" }, visible : function( el ) { dom.require("node"); return el.type !== "hidden" && dom.getStyle(el,"display") !== "none" }, link:function(el){ return el.nodeName.toLowerCase() === "a"; }, root:function(el){//标准 return el === (el.ownerDocument || el.document).documentElement; }, target:function(el,_,root){//标准 var id = root.location.hash.slice(1); return (el.id || el.name) === id; }, parent : function( el ) { return !!el.firstChild; }, contains: function(el, exp) { return (el.textContent||el.innerText||'').indexOf(exp) !== -1 }, "first-child": queryPseudoNoExp(-1, true),//标准 "last-child": queryPseudoNoExp( 1, true),//标准 "only-child": queryPseudoNoExp( 0, true),//标准 "first-of-type": queryPseudoNoExp(-1, false),//标准 "last-of-type": queryPseudoNoExp( 1, false),//标准 "only-of-type": queryPseudoNoExp( 0 ,false),//标准 "nth-child": queryPseudoHasExp("firstChild", "nextSibling", true),//标准 "nth-last-child": queryPseudoHasExp("lastChild", "previousSibling", true),//标准 "nth-of-type": queryPseudoHasExp("firstChild", "nextSibling", false),//标准 "nth-last-of-type": queryPseudoHasExp("lastChild", "previousSibling", false),//标准 //与位置相关的过滤器 first: function(index){ return index === 0; }, last: function(index, num){ return index === num; }, even: function(index){ return index % 2 === 0; }, odd: function(index){ return index % 2 === 1; }, lt: function(index, num){ return index < num; }, gt: function(index, num){ return index > num; }, eq: function(index, num){ return index === num; } }; dom.each(String("text radio checkbox file password submit image reset").match(/\w+/g), function(name){ filters[name] = function(el){ return el.type === name } }); var parseNth = function (exp) { var match = /(-?)(\d*)n([-+]?\d*)/.exec(exp === "even" && "2n" || exp === "odd" && "2n+1" || !/\D/.test(exp) && "0n+" + exp || exp); return { a: (match[1] + (match[2] || 1)) - 0, b: match[3] - 0 }; }; var position_ = dom.oneObject(String("eq gt lt first last even odd").match(/\w+/g)); //http://www.cnblogs.com/rubylouvre/archive/2009/11/25/1610044.html dom.queryId = function (id, context) { var el = (context || document).getElementById(id); return el && [el] || [] }; if(dom.env.mixupsName){ //如果浏览器的getElementById不能区分name与id dom.queryId = function(id,root){ root = root || document; var el = root.getElementById(id); if (el && el.attributes['id'].value === id) { return [el] } else { var all = root.all[id]; for(var i=0;el=all[i++];){ if(el.attributes['id'].value === id) return [el] } return [] } } } var queryWildcard = function (root) {//获得页面上或者某个元素节点下的所有元素 var all = root.all || root.getElementsByTagName("*"),result; if(dom.ie){ result = dom.filter(all,function(el){ return el.nodeType === 1 }); if(dom.env.traverseAllElements) dom.merge(result,(root.getElementsByTagName("param") || [])) return result; }else{ return dom.slice(all); } }; var queryTag = function(tagName, lastResult, root){ var result = [],ri = 0, n = lastResult.length, uniqResult = {},nodes; if(dom.lib.isNot){ var all = n ? lastResult :queryWildcard(root); return dom.filter(all,function(el){ return el.tagName.toLowerCase() !== tagName.toLowerCase() }); } if (n === 0) { return dom.filter(root.getElementsByTagName(tagName),function(){ return true; }); } else { var i = 0 ,j ,jn ,node ,uid ; if(dom.lib.quickTag ){ dom.lib.quickTag = false; while(i < n){ nodes = lastResult[i++].getElementsByTagName(tagName); j = 0; jn = nodes.length; while(j < jn){ node = nodes[j++]; uid = node.uuid || (node.uuid = "dom-"+dom.uuid++); if(uniqResult[uid] !== node){ result[ri++] = uniqResult[uid] = node; } } } return result; }else{ while(i < n){ node = lastResult[i++]; if(node.nodeName === tagName ) result[ri++] = node; } return result; } } } var queryClass = function (className, lastResult, root, flags) { var result = [],ri = 0,i = 0, n = lastResult.length, isNot = dom.lib.isNot, el, reg = new RegExp('(?:^|[ \\t\\r\\n\\f])' + className + '(?:$|[ \\t\\r\\n\\f])'); if (n === 0) {//查找模式 if (flags.byClass) { return Array.prototype.slice.call(root.getElementsByClassName(className)); } else { var els = root.all || root.getElementsByTagName("*"); for(i=0;el=els[i++];){ if(reg.test(el.className || el.getAttribute("class"))) result[ri++] = el; } return result; } } else {//过滤模式 for(i=0;el=lastResult[i++];){ if(reg.test(el.className || el.getAttribute("class")) ^ isNot) result[ri++] = el; } return result; } } var queryDescendant = function(className,lastResult,flags){//后代选择器 var result = [],ri = 0, isAll = !className,//如果为空字符串或undefined uniqResult = {}, i = 0 ,n = lastResult.length, j ,jn , nodes, node,el, reg, uid; if(!isAll){ reg = new RegExp('(?:^|[ \\t\\r\\n\\f])' + className + '(?:$|[ \\t\\r\\n\\f])'); } lastResult = lastResult.sort( dom.lib.pageOrder ); //className二级查找模式,利用原生的getElementsByClassName实现高速化 if(!isAll && flags.byClass){ while(i < n){ nodes = lastResult[i++].getElementsByClassName(className); j = 0; jn = nodes.length; while(j < jn){ node = nodes[j++]; uid = node.uuid || (node.uuid = "dom-"+dom.uuid++); if(uniqResult[uid] !== node){ result[ri++] = uniqResult[uid] = node; } } } }else{ while(i < n){ el = lastResult[i++]; if(uniqResult[el.uuid] !== el){ nodes = el.all || el.getElementsByTagName("*"); j = 0; jn = nodes.length; //className二级查找模式 while(j < jn){ node = nodes[j++]; if(uniqResult[node.uuid] === node) break; if(node.nodeType === 1 && (isAll || reg.test(node.className || node.getAttribute("class")))){ uid = node.uuid || (node.uuid = "dom-"+dom.uuid++); if(uniqResult[uid] === node){ break; }else{ result[ri++] = uniqResult[uid] = node; } } } } } } return result; }; var queryChild = function (nodeName,lastResult,flags) {//亲子选择器 var isAll = nodeName === "*",result = [],ri = 0, n = lastResult.length,i = 0 ,nodes ,node,j , jn, prop = flags.children ? "children" : "childNodes"; while(i < n){ nodes = lastResult[i++][prop]; j = 0; jn = nodes.length; while(j < jn){ node = nodes[j++]; if( ( flags.children || node.nodeType === 1) &&(isAll || nodeName === node.nodeName)) result[ri++] = node; } } return result; }; var queryGeneral = function (nodeName,lastResult,flags) {//兄长选择器 var isAll = nodeName === "*",result = [],ri = 0, n = lastResult.length,i = 0 ,uniqResult = {}, uid,node, prop = flags.element ? "nextElementSibling" :"nextSibling" while(i < n){ node = lastResult[i++]; if(uniqResult[node.uuid] !== node){ for(node = node[prop];node;node = node[prop]){ if(uniqResult[node.uuid] === node) break; if(( flags.element || node.nodeType === 1) && (isAll || nodeName === node.nodeName)){ uid = node.uuid || (node.uuid = "dom-"+dom.uuid++) if(uniqResult[uid]){ break; }else{ result[ri++] = uniqResult[uid] = node; } } } } } return result; }; var queryAdjacent = function (nodeName,lastResult,flags) { //相邻选择器 var isAll = nodeName === "*", result = [],ri = 0, n = lastResult.length,i = 0 ,node, prop = flags.element ? "nextElementSibling" :"nextSibling"; while(i < n){ node = lastResult[i++]; for(node = node[prop];node;node = node[prop]){ if(flags.element || node.nodeType === 1){ if (isAll || nodeName === node.nodeName) result[ri++] = node; break; } } } return result; }; var queryAttribute = function (name,operator,value,lastResult, root) { //属性选择器 if(lastResult.length === 0) lastResult = queryWildcard(root); var result = [],ri = 0,reg; switch (operator) { case '$=':reg = new RegExp( value + '$' );break ; case '~=':reg = new RegExp( '(?:^|[ \\t\\r\\n\\f])' + value + '(?:$|[ \\t\\r\\n\\f])');break; case '|=':reg = new RegExp( '(?:^|\\|)' + value + '(?:$|\\|)');break; } var el , i = 0 ,n = lastResult.length,attrib,flag while(i < n){ el = lastResult[i++]; attrib = dom.attr(el, name);//取得元素的实际属性值 flag = (attrib != null) && (attrib !== ""); if(flag && operator) switch (operator) { case '=': flag = attrib === value ;break ; case '!=': flag = attrib !== value ;break ; case '^=': flag = attrib.indexOf(value) === 0 ;break ; case '*=': flag = attrib.indexOf(value) !== -1 ;break ; default : flag = reg.test(attrib);break; } if (!!flag ^ dom.lib.isNot) result[ri++] = el; } return result; } var queryPseudo = function (type, exp, lastResult,root){//伪类选择器 var position = position_ if(lastResult.length === 0 ) lastResult = queryWildcard(root); var filter = filters[type], i = 0, n = lastResult.length, result = [],ri = 0, el; if(position[type]){//处理位置伪类 //如果exp为空白则将集合的最大索引值传进去,否则将exp转换为数字 exp = (exp === ""|| exp === void 0) ? n - 1 : ~~exp; while(i < n){ el = lastResult[i]; if(filter(i++, exp) ^ dom.lib.isNot) result[ri++] = el; } return result; } if((typeof filter === "object") && filter.curry){ return filter.curry(lastResult,parseNth(exp).a,parseNth(exp).b); } //处理target root checked disabled empty enabled lang 等伪类 while(i < n){ el = lastResult[i++]; if(filter(el, exp, root) ^ dom.lib.isNot) result[ri++] = el; } return result; }; //适配器,根据选择器的类型调用相应的函数去处理 var dispatcher_ = { wildcard:function(array,nodes,root) { //通配符选择器 return dom.lib.isNot ? [] :queryWildcard(root); }, tag : function(array, nodes, root, flags){ //标签选择器 var nodeName = flags.xml ? array[0] :array[0].toUpperCase(); return queryTag(nodeName , nodes, root); }, id : function(array, nodes, context){ //ID选择器 var id = array[1]; return dom.lib.isNot ? queryAttribute("id","=",id,nodes ,context) :dom.queryId(id, context); }, "class":function(array, nodes, root,flags){ //类选择器 var className = array[1]; return dom.lib.isNot ? queryAttribute("class","~=",className,nodes, root): queryClass(className, nodes, root, flags); }, descendant:function(array, nodes, root, flags){ //后代选择器(第一个参数为className) var className = array[2]; return queryDescendant(className, nodes, flags); }, child:function(array, nodes,root,flags){ //亲子选择器(第一个参数为nodeName) var nodeName = array[2] || "*" nodeName = flags.xml ? nodeName :nodeName.toUpperCase(); return queryChild(nodeName,nodes,flags); }, general:function(array, nodes,root,flags){ //兄长选择器(第一个参数为nodeName) var nodeName = array[2] || "*" nodeName = flags.xml ? nodeName :nodeName.toUpperCase(); return queryGeneral(nodeName,nodes,flags); }, adjacent:function(array, nodes,root,flags){ //相邻选择器(第一个参数为nodeName) var nodeName = array[2] || "*" nodeName = flags.xml ? nodeName :nodeName.toUpperCase(); return queryAdjacent(nodeName,nodes,flags) }, attribute:function(array, nodes,root){ //属性选择器 return queryAttribute(array[1],array[2], array[4],nodes, root); }, pseudo:function(array, nodes,root){ //伪类选择器 return queryPseudo(array[1], array[3], nodes,root); } } var isRelationAndTag_ = dom.oneObject(String("adjacent general child descendant tag").match(/\w+/g)); var removeBlank_ = /\s*([>,\+\~=])\s*(?=(?:(?:[^"']*"[^"']*){2}|(?:[^"']*'[^"']*){2})*[^"']*$)/g; dom.query = function (selectors, context, lastResult) { var result = [], types = types_,//引用外围变量 regexes = regexes_,//引用外围变量 dispatcher = dispatcher_,//引用外围变量 removeBlank = removeBlank_, root = context.documentElement, //若关系选择器与tag选择器跟着ID选择器,则可以直接kill掉前面的 isRelationAndTag = isRelationAndTag_, flags = {//用于装载当前文档的各种判定 xml : dom.isXML(context), children : "children" in root, //http://www.w3.org/TR/ElementTraversal/ element : "nextElementSibling" in root, byClass : "getElementsByClassName" in root }; selectors = selectors.replace(removeBlank, function ($1, $2) { return $2; }); selectors = selectors.replace(/^\s+|\s+$/g, ''); if("querySelectorAll" in context){ try{ var els = context.querySelectorAll(selectors); if(dom.env.sliceNodes){ return Array.prototype.slice.call(els); }else{ return dom.filter(els,function(el){ return el.nodeType === 1 }); } }catch(e){ } } while (selectors.length) { var type = types[selectors.charAt(0)] || "tag", regex = regexes[type], array = selectors.match(regex),//使用match才有rightContext,exec没有 segment = RegExp.lastMatch; selectors = RegExp.rightContext; //后代选择器跟紧标签选择器的情形进行优化,如p span或#id span 或.class span //属于高级查找 var els = el.getElementsByTagName(tag) if(lastResult.length && type === "descendant" && /[a-z0-9A-Z_]/.test(selectors.charAt(0))){ dom.lib.quickTag = true; continue; } //如果是并联选择器,那么就把上次的结果集放进最终结果集中 if(type === "combine") { result = result.concat(lastResult); lastResult = []; continue; } else if(isRelationAndTag[type] && selectors.charAt(0) === "#"){ continue; }else if(segment.slice(0,4) === ":not"){ var add = segment.match(regexes.pseudo)[3] || ""; selectors = add + ":yes()"+ selectors ;//自定义一个伪类,标明反选选择器的结束 dom.lib.isNot = true; //使用反选选择器,反选选择器的括号里可以含有以下选择器 continue; //id,class,attribute,pseudo(not除外) }else if(segment.slice(0,4) === ":yes"){ dom.lib.isNot = false; continue; } lastResult = dispatcher[type](array, lastResult, context, flags ); //如果结果集的长度为零,则中止循环 if (lastResult === undefined || lastResult.length === 0) { break; } } //返回最终结果 return result.concat(lastResult); } })(window[escape(document.URL.split("#")[0])],this);

文档下载地址

下载回来后对着文件点右键-->属性-->解除锁定。

如果大家对上述方法有什么更好的实现,请不吝赐救!

posted on 2010-06-26 21:16  司徒正美  阅读(2743)  评论(6编辑  收藏  举报