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);
 
下载回来后对着文件点右键-->属性-->解除锁定。
如果大家对上述方法有什么更好的实现,请不吝赐救!
    机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号