【学】jQuery的源码思路1——后代选择器

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;
}
原文地址:https://www.cnblogs.com/bluefantasy728/p/5778003.html