jQuery的源码思路1——后代选择器
这里探讨一下jQuery中后代选择器的封装原理,并自己写一下
getEle('#div1 ul li .box');
接受的参数就是个后代选择器,类似于这样:
#div1 ul li .box
id/tagname/class
div#div1
div.box
input[type=button]
li:eq(3)/lt(3)/gt(3)
li:first/last/odd/even
function getEle(str){
var arr = str.match(/S+/g); //先把传进的字符串用正则匹配一下,把多余的空格去掉再放进数组,知识点:match返回的是一个数组,这里也可以用split,split也可以放正则,但是要用小写's+'
var aParent = [document]; //一开始以document为父级,但是也要放在数组中
var aChild = [];
for(var i=0 ;i<arr.length; i++){//切好后的数组,循环,每次把抓到的数据放到aChild中,再把它赋给下一次循环的父级
aChild = getByStr(aParent,arr[i]); //需要一个函数,传入父级以及要抓该父级下字符串为第二个参数的元素,抓到的元素赋给数组aChild
aParent = aChild;//然后将该数组作为下一个循环的父级
}
return aChild;
}
function getByStr(aParent,str){
var aChild = [];
for (var i=0; i<aParent.length; i++){
switch (str.charAt(0)){ //判断字符串是否含有#.或者没有,分别代表id,class和标签
case '#':
var obj = aParent[i].getElementById(str.substring(1));
obj && aChild.push(obj);
break;
case '.':
var aEle = getByClass(aParent[i],str.substring(1));
for(var j=0; j<aEle.length; j++){
aChild.push(aEle[j]);
}
break;
default:
//div#div1
if(/w+#w+/.test(str)){
var arr = str.split('#');
var aEle = aParent[i].getElementsByTagName(arr[0]);
for(var j=0; j<aEle.length; j++){
if(aEle[j].id == arr[1]){
aChild.push(aEle[j]);
break; //只抓一个
}
}
}else if(/w+.w+/.test(str)){
var arr = str.split('.');
var aEle = aParent[i].getElementsByTagName(arr[0]);
var re = new RegExp('\b' + arr[1] + '\b'); //用边界的正则是为了避免出现class中出现多个空格,所以只要找到即可
for(var j=0; j<aEle.length; j++){
if(re.test(aEle[j].className)){
aChild.push(aEle[j]);
}
}
}else if(/w+[w+=w+]/.test(str)){ //input[type=button]
var arr = str.split(/[|=|]/); // ['input','type','button',]
var aEle = aParent[i].getElementsByTagName(arr[0]);
for(var j=0; j<aEle.length; j++){
if(aEle[j].getAttribute(arr[1]) == arr[2]){
aChild.push(aEle[j]);
}
}
}else if(/w+:w+((.))?/.test(str)){
var arr = str.split(/:|(|)/);//[tag,eq,3][tag,first]
var aEle = aParent[i].getElementsByTagName(arr[0]);
switch (arr[1]){
case 'first':
aChild.push(aEle[0]);
break;
case 'last':
aChild.push((aEle[aEle.length-1]));
break;
case 'odd':
for(var j=0; j<aEle.length; j++){
if(j%2==1){
aChild.push((aEle[j]));
}
}
break;
case 'even':
for(var j=0; j<aEle.length; j++){
if(j%2==0){
aChild.push((aEle[j]));
}
}
break;
case 'eq':
aEle[arr[2]] && aChild.push(aEle[arr[2]]);
break;
case 'lt':
for(var j=0; j<arr[2]; j++){
aChild.push(aEle[j]);
}
break;
case 'gt':
for(var j=Number(arr[2])+1;j<aEle.length; j++){
aChild.push(aEle[j]);
}
break;
}
}else{
var aEle = aParent[i].getElementsByTagName(str);
for(var j=0; j<aEle.length; j++)
aChild.push(aEle[j]);
}
}
}
return aChild;
}
function getByClass(oParent,sClass){
if(oParent.getElementsByClassName){
return oParent.getElementsByClassName(sClass);
}
var result = [];
var re = new RegExp('\b' + sClass + '\b');
var aEle = oParent.getElementsByTagName('*');
for(var i=0; i<aEle.length; i++){
if(re.test(aEle[i].className)){
result.push(aEle[i]);
}
}
return result;
}