JavaScript实现DOM对象选择器(2)

这个实现的性能也是很差的,因为当他检查对象集合中的一个对象的祖先元素是否符合一个选择器时,他先检查他的父元素,不满足的话再检查他父元素的父元素,一直到没有父元素为止。然后他还需要检查是否符合下一个选择器,这样他又遍历了一遍他的父元素。这里有重复访问的地方。 

思路一的所有代码: 

//需要一个可以选择所有元素的方法 function getElements(selector){ //类选择器,返回全部项 if(/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ if(document.getElementsByClassName){ return document.getElementsByClassName(selector.slice(1,selector.length)); } var nodes = document.all ? document.all : document.getElementsByTagName('*'); var arr=[]; //用来保存符合的className; for(var i=0;i<nodes.length;i++){ if(hasClass(nodes[i],selector.slice(1,selector.length))){ arr.push(nodes[i]); } } return arr; } //ID选择器 if(/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ return document.getElementById(selector.slice(1,selector.length)); } //tag选择器 if(/^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ return document.getElementsByTagName(selector); } //属性选择器 if(/^\[[A-Za-z0-9_-\S]+\]$/.test(selector)){ selector = selector.slice(1,selector.length-1); var eles = document.getElementsByTagName("*"); selector = selector.split("="); var att = selector[0]; var value = selector[1]; var arr = []; if (value) { for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(att)==value){ arr.push(eles[i]); } } }else{ for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(att)){ arr.push(eles[i]); } } } return arr; } } //检查ele的祖先对象是否符合选择器 function isParent(ele,str){ if (!isArray(str)) { str = toArray(str); } if (ele.parentNode) { if (str.indexOf(ele.parentNode)>-1) { return true; }else{ return isParent(ele.parentNode,str); } }else{ return false; } } //从eles中删掉祖先对象不符合选择器的对象 function fliterEles(eles,str){ if(!isArray(eles)){ eles = toArray(eles); } for (var i = 0; i < eles.length; i++) { if (!isParent(eles[i],str)) { eles.splice(i,1); i = i - 1; } } return eles; } //DOM元素选择器 function $(selector){ if(!typeof selector === "string"){ return false; } //复合选择器 if(trim(selector).split(" ").length > 1){ var all = trim(selector).split(" "); var eles = getElements(all[all.length-1]); for(var i = 2 ; i < all.length+2 && all.length-i >=0; i++){ eles = fliterEles(eles,getElements(all[all.length-i])); } return eles[0]; } //ID选择器 if(/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ return document.getElementById(selector.slice(1,selector.length)); } //tag选择器,只返回第一个 if(/^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ return document.getElementsByTagName(selector)[0]; } //类选择器 if(/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ if(document.getElementsByClassName){ return document.getElementsByClassName(selector.slice(1,selector.length))[0]; } var nodes = document.all ? document.all : document.getElementsByTagName('*'); for(var i=0;i<nodes.length;i++){ if(hasClass(nodes[i],selector.slice(1,selector.length))){ return nodes[i]; } } } //属性选择器 if(/^\[[A-Za-z0-9_-\S]+\]$/.test(selector)){ selector = selector.slice(1,selector.length-1); var eles = document.getElementsByTagName("*"); selector = selector.split("="); var att = selector[0]; var value = selector[1]; if (value) { for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(att)==value){ return eles[i]; } } }else{ for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(att)){ return eles[i]; } } } } }

•思路二: 

从最外层向里面筛选。 

先从document选出符合最外层选择器的对象集,目标对象一定是这个对象集的一个对象的子孙元素。 

所以,遍历这个对象集中的每个元素,从中选出符合第二个选择器的对象集,然后再遍历新的对象集。 

直到筛选完最后一个选择器,剩下的对象集中的第一个就是目标对象。 

这个方法不需要区分符合选择器和单项选择器,也不需要重新定义获得所有元素的方法。 

function $(selector){ var all=selector.split(/\s+/); var result = [],rooot=[document]; for (var i = 0; i < all.length; i++) { var type=all[i][0]; switch(type){ //ID case "#" : for (var j = 0; j < rooot.length; j++) { var ele=rooot[j].getElementById(all[i].slice(1)); if (ele) { result.push(ele); } } break; //class case ".": for (var j = 0; j < rooot.length; j++) { if (document.getElementsByClassName) { var eles=rooot[j].getElementsByClassName(all[i].slice(1)); if (eles) { result=result.concat(Array.prototype.slice.call(eles)); } }else{ var arr = rooot[j].getElementsByTagName("*"); for (var i = 0; i < arr.length; i++) { if (hasClass(arr[i], className)) { result.push(arr[i]); } } } } break; //属性 case "[": var att = all[i].slice(1,all[i].length-1).split("="); var key = att[0],value=att[1]; for (var j = 0; j < rooot.length; j++) { var eles=rooot[j].getElementsByTagName("*"); for (var i = 0; i < eles.length; i++) { if (value) { for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(key)==value){ result.push(eles[i]); } } }else{ for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(key)){ result.push(eles[i]); } } } } } break; //tag default: for (var j = 0; j < rooot.length; j++) { eles=rooot[j].getElementsByTagName(all[i]); if (eles) { result=result.concat(Array.prototype.slice.call(eles)); } } }//switch rooot=result; result=[]; }//for return rooot[0]; }

用到的公共方法: 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzjggp.html