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