Rage其实已经完成了半年多了,一直在内部使用。它的实现原理与Sizzle一致,都是通过最右近的表达式得到一个种子集,然后不断往左边切割,过滤种子集中不符合的元素,将它们置为flase,最后去掉这些false元素,就得到最后结果了。
支持CSS选择器类型,除jQuery自定义的位置伪类外,一切CSS选择器类型都支持。
由于Sizzle已经在这领域开发很久了,因此很难赶上其速度。
即使如此,我还是很有收获,如更深入了解Sizzle的运作,一些去重排序的算法(主要来自JK的帮助),新的子元素过滤伪类的算法,querySelectorAll的用法改进等等。
不过,第四代选择器最大的特色是其权重体系,它把所有选择器类型分为五类:
index : {//构建权重体系 "#":12, ".":23, "[":34, ":":55 //tagName:41 }, apis: { 12 : "getElementById", 23 : "getElementsByClassName", 34 : "getElementsByName", 41 : "getElementsByTagName" , 55 : "" },
查找时用这些数字的十位数,过滤时用这些数字的个位数,之所以速度慢下来,是从右到左的实现太复杂了,暂时还无法掌控它。但这东西迟早会应用我新一代选择器中。
使用方法,dom.query(expr,context),不过它是依赖于lang模块的
; (function(global,DOC){ var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')]; dom.log("已加载query模块") dom.define("query", "lang",function(){ dom.mix(dom,{ //http://www.cnblogs.com/rubylouvre/archive/2010/03/14/1685360. isXML : function(el){ var doc = el.ownerDocument || el return doc.createElement("p").nodeName !== doc.createElement("P").nodeName; }, //获取某个节点的文本,如果此节点为元素节点,则取其childNodes的所有文本, //为了让结果在所有浏览器下一致,忽略所有空白节点,因此它非元素的innerText或textContent getText : function( nodes ) { var ret = "", elem; for ( var i = 0; nodes[i]; i++ ) { elem = nodes[i]; // 对得文本节点与CDATA的内容 if ( elem.nodeType === 3 || elem.nodeType === 4 ) { ret += elem.nodeValue; //取得元素节点的内容 } else if ( elem.nodeType !== 8 ) { ret += this.getText( elem.childNodes ); } } return ret; } }); var reg_split = /^(?:[-\w\*]|[^\x00-\xa0]|\\.)+|[#:](?:[-\w]|[^\x00-\xa0]|\\.)+(?:\([^\)]*\))?|\.(?:[-\w*\.]|[^\x00-\xa0]|\\.)+|\[[^\]]*\]|(?:\s*)([>+~,\s])(?:\s*)(?=\S)/ var reg_attr = /\[\s*((?:[-\w]|[^\x00-\xa0]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/; var reg_pseudo = /^:(\w[-\w]*)(?:\((['"]*)(.*)\2\))?$/; var reg_name = /\[name=['"]*((?:[-\w]|[^\x00-\xa0]|\\.)+)['"]*\]/; var reg_escape =/([\/\[\]\:])/g var reg_class = /\.([^.]+)/g; var reg_ltrim = /^\s+/; var reg_rtrim = /\s+$/; var reg_input = /input|select|textarea|button/i; var reg_slash = /\\/g // CSS3 user action pseudo-classes var one_action = dom.oneObject('target,active,hover,focus', 2); var one_url = dom.oneObject('action,cite,codebase,data,href,longdesc,lowsrc,src,usemap', 2); //According to the W3C spec, document.querySelectorAll('[selected=selected]') //should return the same NodeList as document.querySelectorAll('[selected]'), var one_bool = dom.oneObject('checked,disabled,defer,ismap,multiple,readonly,selected'); var one_relative = dom.oneObject([" ", ">", "+", "~"]); var child_pseudo = "nth-child,nth-last-child"; var one_child = dom.oneObject((child_pseudo+","+child_pseudo.replace(/child/g,"of-type"))); var sort_type = function(a,b){ return a.charAt(1) - b.charAt(1); } var one_link = dom.oneObject(["a","A","area","AREA","link","LINK"]) var flag_repeat = false; var defaults = { value: 'defaultValue', checked: 'defaultChecked', selected: 'defaultSelected' } var props = dom.attrMap = {}; var to_s = {}.toString; var str = "accessKey|allowTransparency|bgColor|cellPadding|cellSpacing|codeBase|codeType|colSpan|dateTime|defaultChecked|defaultSelected|defaultValue|frameBorder|"+ "isMap|longDesc|maxLength|marginWidth|marginHeight|noHref|noResize|noShade|readOnly|rowSpan|tabIndex|useMap|vSpace|valueType|vAlign" str.replace(/\w+/g, function(name){ props[name.toLowerCase()] = name; }); dom.mix(props, { "accept-charset": "acceptCharset", "char": "ch", charoff: "chOff", "class": "className", "for": "htmlFor", "http-equiv": "httpEquiv" }); var Query = dom.query = function(token, context, result, seed){ result = result || []; context = context || DOC; if (context.nodeType !== 1 && context.nodeType !== 9) { return result; } Query.queryTime = new Date-0;//.replace(reg_rltrim,'') var right = token.replace(reg_ltrim,'').replace(reg_rtrim,''), loop = [], types = [],relative = one_relative,nodes, match, part; //将CSS表达式转换成二重数组,并根据'种子选择器取得候选集 do{ match = right.match(reg_split); right = RegExp.rightContext; part = match[1] || match[0]; if(part == ","){ break }else if(relative[part]){ loop.push(types,part); types = []; }else if(part){ (types[types.length] = new String(Query.index[part.charAt(0)] || 41))._ = part; } }while(right); // dom.log(types) match = seed ? { types: types, nodes: dom.slice(seed)//nte } :Query.getSeed(types, context);//取得种子集 types = match.types; nodes = match.nodes; var flag_xml = dom.isXML(context); if ( types.length) {//缩窄种子集的范围 nodes = to_s.call(nodes) === "[object Array]" ? nodes : dom.slice(nodes); // dom.log(types+" "+nodes); nodes = Query.sameLevelSift(types, nodes, flag_xml); } var i = 0, n = nodes.length; if(loop.length ){//处理左边选择器 var set = dom.slice(nodes);//复制一份构造映射集 while ( loop.length ) { part = types = loop.pop(); if ( relative[ part ] ) { types = loop.pop(); } else { part = " ";//默认为后代选择器 } Query.iterator[ part ]( types, set, flag_xml ); } for(; i < n; i++){ if(set[i]){ result[result.length] = nodes[i];//合并两个结果集 } } } else{ for(; i < n; i++){ result[result.length] = nodes[i] } } if ( right ) { Query( right, context, result,seed ); return result.length < 2 ? [] : dom.unique( result ); } return result; } dom.mix(Query, { index : {//构建权重体系 "#":12, ".":23, "[":34, ":":55 //tagName:41 }, apis: { 12 : "getElementById", 23 : "getElementsByClassName", 34 : "getElementsByName", 41 : "getElementsByTagName" , 55 : "" }, getAttribute : function(node, attribute) { return node.getAttribute(attribute) || ''; } , hasAttribute : function(node, attr) { return node.hasAttribute(attr); }, getElementById:function(expr){ var el = this.getElementById(expr.slice(1).replace(reg_slash,'')); return el && [el] || []; }, getElementsByClassName:function(expr){ return this.getElementsByClassName(expr.slice(1).replace(reg_slash,'').replace(/\./g, ' ')); }, getElementsByName:function(expr){ var match = expr.match(reg_name); return match && this.getElementsByName(match[1].replace(reg_slash,'')); }, getElementsByTagName:function(expr){ return this.getElementsByTagName(expr.replace(reg_slash,'')); }, isLink:function(node){ return Query.hasAttribute(node,'href') && one_link[node.nodeName]; }, cacheNTH:{}, parseNTH:function(expr){ var a = (expr === "even" && "2n0" || expr === "odd" && "2n1" || !/n/.test(expr) && ("0n"+expr) || expr.replace(/(^|\D+)n/g,"$11n") ).split(/n/); return (Query.cacheNTH[expr] = [a[0]|0,a[1]|0]); }, /*************************获取候选集***************************/ getSeed: function (types, context) { types.sort(); var i =0, type, api, nodes; for(; type = types[i]; i++){ api = Query.apis[type]; nodes = context[api] && Query[api].call(context,type._); if(nodes){ types.splice(i, 1); break; } } if (!nodes) { nodes = context.getElementsByTagName("*"); } return { nodes: nodes, types: types } }, //flag_false,是否将不符合条件的元素置换为false,默认直接去掉此元素 sameLevelSift:function(types, nodes, flag_xml, flag_false, flag_not){//平级过滤 types.sort(sort_type); var i = 0, type, n, ii , node, match, filter, t = 0 while ((type = types.shift())) { n = nodes.length; match = Query.preSift[ type ]( type._, flag_xml, flag_false, flag_not, nodes, n );//加工参数 if(!match) continue; filter = Query.filters[type]; for (i = ii = 0; i < n; i++) { if ((node = nodes[i])) { if (filter.call( node, match ) ^ flag_not) {//这里只处理ID CLASS TAG ATTR if(!flag_false){ nodes[ii++] = node; } } else if (flag_false) { nodes[i] = false;//过滤种子集 } } } if (!flag_false) { nodes.length = n = ii; } } return nodes; }, //表达式的类型 待检测的节点集合 是否为XML 测试值 目标元素的属性 crossLevelSift:function(type, nodes, flag_xml, check, prop){//越级过滤 var i = 0, n = nodes.length, time = Query.queryTime ++,STAR = "*",NIL, node, val; for (; i < n; i++) { if ((node = nodes[i])) { val = false; while ((node = node[prop])) { if (node.nodeType === 1) { if (node.queryTime === time) { val = nodes[node.queryIndex]; break; } if (check === node.nodeName || (check === NIL && Query.sameLevelSift([type], [node], flag_xml, false).length) || check === STAR) { node.queryTime = time; node.queryIndex = i; val = node; break; } } } nodes[i] = val; } } }, preSift:{ 12: function( expr ) {//ID return expr.slice(1).replace(reg_slash,''); }, 23: function( expr, flag_xml, flag_false, flag_not, nodes, n ) {//CLASS var i = 0, ii = 0, node, src = expr.replace(reg_escape, '\\$1').replace(reg_class, '(?=[ \\s\\S]*(?:^|\\s)$1(?: \\s|$))'), reg = new RegExp(src); if ( flag_xml ) { return reg; } for ( ; i < n ; i++ ) { if((node = nodes[i])){ if(node.className && reg.test(node.className) ^ flag_not){ if(!flag_false){ nodes[ii++] = node; } } else if ( flag_false ) { //不符合的置换为false nodes[i] = false; } } } if ( !flag_false ) nodes.length = ii; return false; }, 34:function(expr){//ATTR var match = expr.match(reg_attr), name = match[1].replace(reg_slash,''); var value = (match[4]||"").replace(reg_slash,''); if ( match[2] === "~=" ) { value = " " + value + " "; } return [name,match[2],value]; }, 41:function(expr, flag_xml){//TAG expr = expr.replace(reg_slash,''); if (expr === "*") return false; return flag_xml ? expr : expr.toUpperCase() }, 55:function(value, flag_xml, flag_false, flag_not, nodes, n){//PSEUDO var match = value.match(reg_pseudo),expr = (match[3] || "").replace(reg_ltrim,'').replace(reg_rtrim,''), type = match[1] ,i = 0, ii = 0, node, args = []; if((type === "nth-child" || type === "nth-last-child") && expr === "n") return false; if(one_child[type]){//拥有表达式的子元素过滤伪类 expr = expr.replace(/\s/g,''); args = Query.cacheNTH[expr] || Query.parseNTH(expr); }else if(one_action[type]){//目标伪类 args = [!flag_xml]; }else if(type === "lang"){//语言伪类 args = [new RegExp("^(" + expr + "$|" + expr + "-)", "i")]; }else if(type == "contains"){//内容伪类 args = [expr, flag_xml]; }else if(type === "not"){ var check = 0, whiterat = expr+""; while(whiterat){ whiterat.match(reg_split); whiterat = RegExp.rightContext; if(check==2) break; check++; } // if(check === 1 && expr.charAt(0) !== ":" && expr.slice(-1) !== ")") if(check > 1){//复杂 var els = Query(expr, null, null, nodes), hash = {}, j = 0, uuid; while((node = els[j++])){ uuid = node.uniqueNumber || (node.uniqueNumber = dom["@uuid"]++); hash[uuid] = 1; } args = [hash]; }else { (args[0] = new String(Query.index[expr.charAt(0)] || 41))._ = expr; Query.sameLevelSift(args, nodes, flag_xml, flag_false, true ^ flag_not); return false; } } var filter = Query.filters[type]; for ( ; i < n ; i++ ) { if((node = nodes[i])){ if(filter.apply(node, args) ^ flag_not){ if(!flag_false){ nodes[ii++] = node; } } else if ( flag_false ) { //不符合的置换为false nodes[i] = false; } } } if ( !flag_false ) nodes.length = ii; return false; } }, iterator:{ " ":function (types, nodes, flag_xml) { types.sort(sort_type); var prop = "parentNode", type = types.shift(), expr = type._, check ; if(type == "41"){ check = flag_xml ? expr : expr.toUpperCase(); } Query.crossLevelSift(type, nodes, flag_xml, check, prop);//越级过滤 types.length && Query.sameLevelSift(types, nodes,flag_xml, true);//平级过滤 }, "~":function (types, nodes, flag_xml) { types.sort(sort_type); var prop = "previousSibling", type = types.shift(), expr = type._, check; if(type == "41"){ check = flag_xml ? expr : expr.toUpperCase(); } Query.crossLevelSift(type, nodes, flag_xml, check, prop);//越级过滤 types.length && Query.sameLevelSift(types, nodes, flag_xml, true);//平级过滤 }, ">" : function(types, nodes, flag_xml) { types.sort(sort_type); var type = types[0], expr = type._, check , node; if(type == "41" && types.shift()){ check = flag_xml ? expr : expr.toUpperCase(); } for (var i = 0, n = nodes.length; i < n; i++) { if ((node = nodes[i])) { node = node.parentNode; nodes[i] = (check && node) ? node.nodeName === check && node : node; } } types.length && Query.sameLevelSift(types, nodes, flag_xml, true);//平级过滤 }, "+" : function(types, nodes, flag_xml) { types.sort(sort_type); var type = types[0], expr = type._, check , node; if(type == "41" && types.shift()){ check = flag_xml ? expr : expr.toUpperCase(); } for (var i = 0, n = nodes.length; i < n; i++) { if ((node = nodes[i])) { while ((node = node.previousSibling) && node.nodeType !== 1) {}; nodes[i] = (check && node) ? node.nodeName === check && node : node; } } types.length && Query.sameLevelSift(types, nodes, flag_xml, true);//平级过滤 } }, filters:{ 12:function(id){//这里用于XML return id === this.getAttribute("id"); }, 41: function (nodeName ) { return this.nodeName === nodeName; }, 23: function( reg ) {//这里用于XML return reg.test(this.getAttribute("class")); }, 34:function(match){ var name = match[0], operator = match[1], value = match[2]; if(!operator){ return Query.hasAttribute(this,name); } var attrib = Query.getAttribute(this, name, true); if( match[2] === "" ){//目标值不能为空字串 return false; } switch (operator) { case "=": return attrib === value; case "!=": return attrib !== value; case "~=": return attrib && (" " + attrib + " ").indexOf(value) !== -1; case "^=": return attrib && attrib.indexOf(value) === 0; case "$=": return attrib && attrib.lastIndexOf(value) + value.length === attrib.length; case "*=": return attrib && attrib.indexOf(value) !== -1; case "|=": return attrib === value || attrib.substring(0, value.length + 1) === value + "-"; } }, //CSS3属性伪类 enabled: function(){ return this.disabled === false && this.type !== "hidden"; }, //CSS3属性伪类 disabled: function(){ return this.disabled === true; }, //CSS3属性伪类 checked: function(){ return this.checked = true; }, //CSS3属性伪类 indeterminate:function(){ return this.indeterminate === true && this.type === "checkbox" ; }, //自定义属性伪类 selected: function () { this.parentNode.selectedIndex; //处理safari的bug return this.selected === true; }, //CSS3结构伪类(子元素过滤伪类) empty: function(){ var child = this.firstChild; return !(child && child.nodeType == 1) && !(this.innerText || this.textContent || '').length; }, //自定义可见性伪类 target: function (flag_html) { //CSS2.1目标标准 var id = location.hash.slice(1), check = this.id || flag_html && this.name; return check === id; }, link: function(){ return Query.isLink(this) && !this.visited }, visited: function(){ return Query.isLink(this) && this.visited }, active: function(flag_html){ return flag_html && this === this.ownerDocument.activeElement; }, hover: function(flag_html){ return flag_html && this === this.ownerDocument.hoverElement; }, focus:function(flag_html){ return flag_html && (this.type|| this.href) && this === this.ownerDocument.activeElement; }, //CSS2链接伪类 lang: function (reg) { //CSS3语言伪类 var node = this; while (!node.getAttribute("lang") && (node = node.parentNode)) {}; return reg.test(node.getAttribute("lang")); }, header: function(){ return /h\d/i.test( this.nodeName ) }, //自定义属性伪类 button: function(){ return this.type === "button" || this.nodeName === "BUTTON" }, //自定义属性伪类 input: function(){ return reg_input.test(this.nodeName) }, parent: function(){ return !!this.firstChild; }, //自定义内容伪类 contains:function(text, flag_xml){ return (this.textContent || this.innerText || (flag_xml ? dom.getText([ this ]) : "")).indexOf(text) >= 0; }, //自定义结构伪类 has: function (exp, flag_xml) { //自定义结构伪类(子元素过滤伪类,根据子节点的选择器情况进行筛选) return !!dom.query(exp, this, flag_xml).length; }, not: function (hash) { //CSS3反选伪类 return !hash[this.uniqueNumber]; }, hidden:function( ) { var width = this.offsetWidth, height = this.offsetHeight; return width === 0 || height === 0 || (!dom.support.reliableHiddenOffsets && (this.style.display || dom.css( this, "display" )) === "none"); } } }); dom.query.filters.visible = function( ) { return !dom.query.filters.hidden.call(this) }; var queryPseudoNoExp = function (name, isLast, isOnly) { var head = "var node = this;{0} while((node=node.{1})) if(node.{2} === {3}) return false;"; var body = "var prev = this;while ((prev = prev.previousSibling)) if (prev.{2} === {3}) return false;"; var foot = "return true;" var start = isLast ? "nextSibling" : "previousSibling"; var fills = { type: ["var tagName = this.nodeName;", start, "nodeName", "tagName"], child: ["", start, "nodeType", "1"] } [name]; var fn = isOnly ? head + body + foot : head + foot; return new Function(fn.replace(/{(\d)}/g, function ($, $1) { return fills[$1]; })); } var queryPseudoHasExp = function(child, sibling, ofType,cache){ return function(a,b){ var uid = this.uniqueNumber || (this.uniqueNumber = dom["@uuid"]++), uuid if (!cache[uid]){ var parent = this.parentNode; if (!parent) return false; var node = parent[child], count = 1, checkName = ofType ? "nodeName" : "nodeType", checkValue = ofType ? this.nodeName : 1; do { if (node[checkName] != checkValue) continue; uuid = node.uniqueNumber || (node.uniqueNumber = dom["@uuid"]++); cache[uuid] = count++; } while ((node = node[sibling])); } var pos = cache[uid]; if (a == 0) return b == pos; if (a > 0){ if (pos < b) return false; } else { if (b < pos) return false; } return ((pos - b) % a) == 0; }; }; dom.mix(Query.filters, { "first-child" : queryPseudoNoExp("child", false, false), "last-child" : queryPseudoNoExp("child", true, false), "only-child" : queryPseudoNoExp("child", true, true), "first-of-type" : queryPseudoNoExp("type", false, false), "last-of-type" : queryPseudoNoExp("type", true, false), "only-of-type" : queryPseudoNoExp("type", true, true), //CSS3子元素过滤伪类 "nth-child" : queryPseudoHasExp("firstChild", "nextSibling", false, {}), "nth-last-child" : queryPseudoHasExp("lastChild", "previousSibling", false, {}), "nth-of-type" : queryPseudoHasExp("firstChild", "nextSibling", true, {}), "nth-last-of-type": queryPseudoHasExp("lastChild", "previousSibling", true, {}) }); "text|radio|checkbox|file|password|submit|image|reset".replace(/\w+/g, function(name){ Query.filters[name] = function(){//自定义属性伪类 return "form" in this && this.type === name; } }); dom.unique = function(nodes){ var self = dom.unique; var n = nodes.length; var lists = self.getLists(nodes); lists.sort(function(a,b){ return a.length - b.length; });//按长度排序 var depth = lists[0].length, length = lists.length, parent, cut, ii = 0; for(var i =0; i < depth; i++){ parent = lists[0][i];//假设这个为LCA cut = true; for(var j = 1;j < length; j++){//与其他祖先树相比 if(parent !== lists[j][i]){ cut = false; break; } } if(cut){ ii++ }else{ break; } } var LCA = lists[0][ii-1]; lists = self.sliceLists(lists,ii); lists.sort(self.sortLists); var list, i = 0, result = []; while((list = lists[i++])){ result[result.length] = list.pop(); } if(result.length !== n){ result.unshift(LCA); if(result.length != n){ flag_repeat = true; } if ( flag_repeat ) { for ( i = 1; i < result.length; i++ ) { if ( result[i] === result[ i - 1 ] ) { result.splice( i--, 1 ); } } } } return result; } dom.mix(dom.unique,{ getList : function(node){//取得所有父元素 var list = []; while(node){ if(node.nodeType === 9){ break; } list.unshift(node); node = node.parentNode; } return list; }, getLists : function(nodes){//取得所有祖先的树 var lists = [], getList = this.getList, i=0, node; while((node = nodes[i++])){ lists[ lists.length ] = getList(node); } return lists; }, sliceLists : function(lists,num){ var result = [], i = 0, list; while((list = lists[i++])){ list = list.slice(num); if(list.length){ result[ result.length ] = list; } } return result; }, sortLists : function(a,b){ var n = Math.min(a.length,b.length),ap,bp; for(var i=0; i < n; i++){ ap = a[i],bp = b[i] if(ap !== bp){ while(ap = ap.nextSibling){ if(ap === bp){ return -1; } } return 1; } } return a.length-b.length; } },false); /************************根据浏览器特征重写部分函数**************************/ if ( reg_ltrim.test( "\xA0" ) ) { reg_ltrim = /^[\s\xA0]+/; reg_rtrim = /[\s\xA0]+$/; } var HTML = dom.html, whiterat = DOC.createElement("div"),id = "WHITERAT"; whiterat.innerHTML = '<a name="'+id+'"></a><b id="'+id+'"></b>'; HTML.insertBefore(whiterat, HTML.firstChild); //IE的getElementsById无法区分name与id if( DOC.getElementById(id) === whiterat.firstChild){ Query.filters["12"] = function(id){ return this.getAttributeNode("id").nodeValue === id; } } if(!whiterat.hasAttribute){ Query.hasAttribute = function(node, attribute) { attribute = attribute in props ?//处理HTML非对称的属性 props[attribute] : attribute; if (defaults[attribute] in node) {//处理default前缀的属性 return !!node[defaults[attribute]]; } node = node.getAttributeNode(attribute); return !!(node && (node.specified || node.nodeValue)); } } var input; //IE6/7/8(Q)中元素的attribute与property内部实现是不分的,IE8部分分离,IE9实现彻底分离了 //http://www.javaeye.com/topic/757522 (input = DOC.createElement('input')).setAttribute('value', '5'); if( input.defaultValue != 5){ Query.getAttribute = function(node, attr, use_in_query) { if (defaults[attr] in node) { return node[defaults[attr]] || ''; } var result = "" if(one_url[attr]){ result = node.getAttribute(attr, 2) }else if(use_in_query && one_bool[attr]){ result = node.getAttribute(attr) ? attr : '' }else{ result = (node = node.getAttributeNode(attr)) && node.value } return result || ""; } } //IE6/7/8的getElementsByName有严重bug,只支持搜索表单元素(6-7),并无法区分id与name if(DOC.getElementsByName(id).length === 0){//IE9返回正确的长度:2 delete Query.apis["34"]; } //如果支持sourceIndex我们将使用更为高效的节点排序 //http://www.cnblogs.com/jkisjk/archive/2011/01/28/array_quickly_sortby.html if(whiterat.sourceIndex){ dom.unique = function(nodes){ var result = [], array = [], uniq = {}, node ,index, ri = 0; for(var i = 0 , n = nodes.length; i< n; i++){ node = nodes[i]; index = node.sourceIndex+1e8; if(!uniq[index]){ (array[ri++] = new String(index))._ = node; uniq[index] = 1 } } array.sort(); while( ri ) result[--ri] = array[ri]._; return result; } } //如果支持querySelectorAll var one_qsa = { 1:1,//只使用第一个分支 2:0, 9:1 } if ( whiterat.querySelectorAll) { if (DOC.documentMode === 8){ one_qsa = { 1:0, 2:1, 9:1 } }; (function(){ var oldQuery = Query; // Safari can't handle uppercase or unicode characters when in quirks mode. if ( whiterat.querySelectorAll("#"+id).length === 0 ) { return; } Query = dom.query = function( expr, context, result, seed ) { context = context || DOC; //http://bugs.jquery.com/ticket/7949 if ( !seed && !dom.isXML(context) && !/\:lang\(/.test(expr) ) { expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); if ( one_qsa[context.nodeType] ) {// 1 9 try { return dom.slice( context.querySelectorAll(expr) ); } catch(e) {} } if ( one_qsa[context.nodeType+1] ) {//2 10 var id = context.getAttribute( "id" ),uuid = context.uniqueID if ( !id ) { context.setAttribute( "id", uuid ); } try { return context.querySelectorAll( "#" + uuid + " " + expr ); } catch(e) { } finally { if ( id == context.uniqueID ) { context.removeAttribute( "id" ); } } } } return oldQuery(expr, context, result, seed); }; for ( var prop in oldQuery ) { Query[ prop ] = oldQuery[ prop ]; } })(); } HTML.removeChild(whiterat); }); })(this,this.document); //2011.9.27 uniqueID改为uniqueNumber //2011.10.20 添加visible与hidden伪类 //2011.10.21 Fix visible BUG