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 ); |
下载回来后对着文件点右键-->属性-->解除锁定。
如果大家对上述方法有什么更好的实现,请不吝赐救!
如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码


机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
标签:
javascript
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?