JavaScript实现DOM对象选择器

根据传入的选择器类型选出第一个符合的DOM对象。 
①可以通过id获取DOM对象,例如 $("#adom"); 
②可以通过tagName获取DOM对象,例如 $("a"); 
③可以通过样式名称获取DOM对象,例如 $(".classa"); 
④可以通过attribute匹配获取DOM对象,例如 $("[data-log]"),$("[data-time=2015]"); 
⑤可以通过层叠组合获取DOM对象,例如 $("#adom .classa"); 

思路: 

需要区分复合选择还是单项选择,单项选择的话分别用各自的方法进行获取,复合选择的话就要进行筛选。 

所以第一步,区分是单项还是组合。 

实现方法是将传入选择器的字符串转换成数组,如果数组长度大于1的话,就是复合选择。如果不是的话,再判断是哪一种单项选择器。 

if(trim(selector).split(" ").length > 1){ //trim()方法用于去除字符串开头和结尾的空白 //复合选择器代码 } //判断是哪一种单项选择器

第二步,判断是哪一种单项选择器,然后进行筛选返回第一个元素。

①判断,有两种方法:

•方法一:用正则表达式。 

if(/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ //ID选择器 } if(/^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ //Tag选择器 } if(/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ //class选择器 } if(/^\[[A-Za-z0-9_-\S]+\]$/.test(selector)){ //属性选择器 }

•方法二:检查传入选择器的第一个字符 

var type=trim(selector).charAt(0); switch(type){ case ".": //class选择器 case "#": //id选择器 case "[": //属性选择器 default: //tag选择器 }

②根据选择器进行筛选。

•id和tag直接用DOM方法就可以了。
 •class的document.getElementsByClassName有兼容问题,需要为IE定义方法。
 •属性选择器需要遍历所有的DOM节点对象,选择出符合条件的。

//ID选择器 return document.getElementById(selector.slice(1,selector.length)); //tag选择器 return document.getElementsByTagName(selector)[0]; //类选择器 if(document.getElementsByClassName){ return document.getElementsByClassName(selector.slice(1,selector.length))[0]; }else{ var nodes = document.all ? document.all : document.getElementsByTagName('*'); for(var i=0;i<nodes.length;i++){ var classes=nodes[i].className.split(/\s+/); if(classes.indexOf(selector.slice(1))!=-1){ //indexOf不兼容,需要在原型上扩展 return nodes[i]; break; } } } } //属性选择器 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]; } } } }  

第三步,实现复杂选择器。

•思路一: 

最终筛选出的DOM对象一定是满足最后一个选择器的DOM对象集合之一,所以可以先选出这些对象,然后逐个检查他的祖先元素,是否符合上一层选择器,不符合的话就删掉。一直迭代到最外一层选择器,剩下的DOM对象集合中的第一个就是我们要找的DOM对象。 

那么,如果有n个选择器,就需要进行n-1轮筛选。 

这里需要做两件事情,①检查元素的祖先元素是否是选择器对象集合之一。②检查对象集合中的每个元素,删掉不符合条件的DOM对象。 

定义两个函数来做这两件事: 

//递归检查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,len=eles.length;i<len; i++) { if (!isParent(eles[i],str)) { eles.splice(i,1); i = i - 1; } } return eles; }

这个实现会有一个BUG,就是当HTML是下面这样的时候,他会筛选出“第一个”,然而它并不是我们期待的。 

JavaScript实现DOM对象选择器

虽然实际应用中很少会这样给父元素和子元素定义相同的class名,但我们不能忽略这个BUG的存在。 

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

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