使用原生JS实现jQuery的css选择器,考虑以下几个问题:
1.jQuery用$符号传参的形式获取节点的对象:1)传参有可能是字符串;2)有可能是一个节点对象;3)有可能直接是一个函数,就是$(function(){}),这个形式。所以需要分三种情况
2.字符串又分以下几种情况:1)包含层层递进的css选择器,例如$('#a .b p'),中间会出现空格;2)只有一个字符串
3.不管是层层递进的后代选择器还是简单选择的情况,具体选择时每一个字符串可能是ID选择,类选择,或者普通选择
function Base(args){ //定义一个构造函数,参数为args this.elements=[]; //定义一个存放查找到的节点对象或者对象集合 if(typeof args=='string'){ //判断传递的参数是那种情况,字符串或者对象节点或者函数
if(args.indexOf(' ') !=-1){ //判断字符串的时候是否有空格 var elements=args.split(' '); //将字符串用空格分割成数组,并保存在elements变量里面 var childElements=[]; //定义一个子数组,存放当前查找的节点,最后结果赋值给对象的elements数组 var node=[]; for(var i=0;i<elements.length;i++){ //遍历elements数组,判断每个数组值得第一个字符 if(node.length==0) node=document; //每次查找的n.getElementById()中n为当前查找到的节点 switch(elements[i].charAt(0)){ case '#': childElements=[]; childElements.push(this.getId(elements[i].substring(1))); node=childElements; break; case '.': childElements=[]; //下一次循环时先将之前的大范围清空,准备放小范围 for(var j=0;j<node.length;j++){ var temps=this.getClass(elements[i].substring(1),node[j]); for(var k=0;k<temps.length;k++){ childElements.push(temps[k]); } } node=childElements; //将本次得到的节点作为父节点保存起来 break; default: childElements=[]; for(var j=0;j<node.length;j++){ var temps=this.getTagName(elements[i],node[j]); for(var k=0;k<temps.length;k++){ childElements.push(temps[k]); } } node=childElements; } } this.elements=childElements; //将最后得到的小范围数组赋值给原型数组准备后续的操作 }else{ //find查找节点 switch(args.charAt(0)){ case '#': this.elements.push(this.getId(args.substring(1))); //不一定得到一个,所以直接放进数组,不用放到数组里面的第一个 break; //直传一个参数,所以判断出时直接跳出循环 case '.': this.elements=this.getClass(args.substring(1)); break; default: this.elements=this.getTagName(args); } } }else if(typeof args=='object'){ //undefiend和对象都返回object if(typeof args!='undefined'){ this.elements[0]=args; } }else if(typeof args=='function'){ this.ready(args); } };
//工具函数,给原型对象中添加方法
Base.prototype.getId=function(id){ return document.getElementById(id); }
Base.prototype.getClass=function(className,parentNode){ var node=null; var temps=[]; if(parentNode!=undefined){ node=parentNode; }else{ node=document; } var all=node.getElementsByTagName('*'); //通过标签*获取全部节点 for(var i=0;i<all.length;i++){ if((new RegExp('(\\s|^)' +className +'(\\s|$)')).test(all[i].className)){ temps.push(all[i]); } } return temps; }
Base.prototype.getTagName=function(tag,parentNode){ var node=null; var temps=[]; if(parentNode!=undefined){ node=parentNode; }else{ node=document; } var tags=node.getElementsByTagName(tag); for(var i=0;i<tags.length;i++){ temps.push(tags[i]); } return temps; }
Base.prototype.ready=function(args){ //DOM加载 }
//通过$调用
var $=function(args){
return new Base(args);
};