類選擇器,就是通過class屬性獲取節點。比如壹個html結構中,有三個p標簽都具有class=”red”的屬性,那麽類選擇器返回的就是這三個p標簽。
在jquery中,我們可以很方便的通過$(“.red”)這種方式按照類獲取節點。但是在原生的javascript中,有getElementById(按照id屬性獲取元素)、getElementsByTagName(按照標簽名獲取元素)等方法,但是並沒有類選擇器相關方法。因此,編寫原生js實現類選擇器的方法非常關鍵。
二、類選擇器的實現
通過利用原生js編寫類選擇器,可以更深入的了解js中的DOM相關操作,下面我們就來看壹個簡單的類選擇器是如何實現的:
function getElementsByClass(classnames){
var classobj = newArray();
var classint = 0;
var tags =document.getElementsByTagName("*");
for(var i in tags){
if(tags[i].nodeType == 1){
if(tags[i].getAttribute("class") == classnames){
classobj[classint] = tags[i];
classint++;
}
}
}
return classobj;
}我們封裝了壹個getElementsByClass()方法,該方法的效果是:獲取所有DOM節點,它們的class屬性為選定值,並返回到壹個數組中。該方法傳遞壹個參數,即需要選擇的class值。
該類選擇器的實現方法,首先創建壹個空的數組classobj,用來存放獲取到的DOM節點。classint變量用來進行索引的表示,方便數組操作。我們利用getElementsByTagName(“*”)方法獲取了這個頁面上的所有DOM節點(*表示匹配所有)。
取出了所有DOM節點,我們就可以進行判斷了。循環遍歷取到的每壹個節點,如果它的nodeType是1(元素節點),則利用getAttribute(“class”)方法獲取節點的class屬性值,並與傳遞進來的class參數進行比對,如果相同,說明是我們想要的節點,存入事先定義好的數組中。最後返回該數組即可。
三、原生js類選擇器測試
下面我們來驗證壹下我們自己編寫的類選擇器是否正常工作,測試代碼如下:
<!DOCTYPE htmlPUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""plete'){
fn();
}
});
}
}
function getByClass(oParent,sClass){
//高級瀏覽器支持getElementsByClassName直接使用
if(oParent.getElementsByClassName){
return oParent.getElementsByClassName(sClass);
}else{
//不支持需要選中所有標簽的類名來選取
var res=[];
var aAll=oParent.getElementsByTagName('*');
for(var i=0;i<aAll.length;i++){
//選中標簽的全部類名是個str='btn on red'=aAll[i].className 使用正則 reg=/\b sClass \b/g
var reg= new RegExp('\\b'+sClass+'\\b','g');
if(reg.test(aAll[i].className)){
res.push(aAll[i]);
}
}
return res;
}
}
//如果參數是str 進行選擇器的操作
function getByStr(aParent,str){
//用來存放選中的元素的數組 這個數組在getEle存在,為了每次執行的時候都需要清空,所以使用局部函數的變量
var aChild=[];
//aParent開始是[document],再執行完getByStr的時候getEle將aParent指向了getByStr函數的返回值aChild數組以確保循環父級下面的所有匹配元素
for(var i=0;i<aParent.length;i++){
switch(str.charAt(0)){
//id選擇器 eg: #box 使用document.getElementById選取
case '#':
var obj=document.getElementById(str.substring(1));
aChild.push(obj);
break;
//類選擇器 eg: .box 使用上面封裝的getByClass選取
case '.':
//由於壹個標簽可以有多個類選擇器 所以需要進行循環選取
var aRes=getByClass(aParent[i],str.substring(1));
for(var j=0;j<aRes.length;j++){
aChild.push(aRes[j]);
}
break;
//今天先簡單的編寫選擇器 這裏我們假設除了id和類選擇器,就是標簽選擇器
default:
// 如果是li.red 那麽用正則來判斷
if(/\w+\.\w+/g.test(str)){
//先選擇標簽,在選擇類選擇器 使用類選擇器的時候重復選擇器函數即可
var aStr=str.split('.');
var aRes=aParent[i].getElementsByTagName(aStr[0]);
var reg=new RegExp('\\b'+aStr[1]+'\\b','g');
//循環選取標簽,註意外層已經有i的循環
for(var j=0;j<aRes.length;j++){
if(reg.test(aRes[j].className)){
aChild.push(aRes[j]);
}
}
//如果是li:eq(2) 或者 li:first這樣的選擇器 書寫正則是的時候註意()可有可以無為? 有或者沒有為* 至少有壹個也就是若幹個為+ {2,5}這種則為2-5個
}else if(/\w+\:\w+(\(\d+\))?/g.test(str)){
//講str進行整理 [li,eq,2] 或者 [li,first]
var aStr=str.split(/\:|\(|\)/);
//aStr[2]是eq、lt、gt傳入的參數,這裏使用n來保存
var n=aStr[2];
//在父級下獲取所有匹配aStr[0]項的標簽
var aRes=aParent[i].getElementsByTagName(aStr[0]);
//這時候會循環判斷aStr[1]項是的內容,jquery中經常使用的為eq、lt、gt、even、odd、first、last
switch(aStr[1]){
//如果是eq則把第n項傳入aChild數組即可
case 'eq':
aChild.push(aRes[n]);
break;
//如果是lt需要將aRes數組中獲取到的小於n的標簽循環推入aChild中
case 'lt':
for(var j=0;j<n;j++){
aChild.push(aRes[j]);
}
break;
//如果是gt則和lt相反
case 'gt':
for(var j=n;j<aRes.legth;j++){
aChild.push(aRes[j]);
}
break;
//如果是event的話需要隔數添加,註意jquery中的event是從第0開始循環的
case 'event':
for(var j=0;j<aRes.length;j+=2){
aChild.push(aRes[j]);
}
break;
//如果是odd的和event不同的只是從第1項開始循環
case 'odd':
for(var j=1;j<aRes.length;j+=2){
aChild.push(aRes[j]);
}
break;
//如果是first,則將aRes[0]推入aChild
case 'first':
aChild.push(aRes[0]);
break;
case 'last':
aChild.push(aRes[aRes.length-1]);
break;
}
//屬性選擇器 eg:input[type=button] 同樣適用正則來判斷
}else if(/\w+\[\w+\=\w+\]/g.test(str)){
//將屬性選擇器切成數組 [input,type,button]
var aStr=str.split(/\[|\=|\]/g);
var aRes=aParent[i].getElementsByTagName(aStr[0]);
//在選中標簽中選出有aRes[1]的屬性
for(var j=0;j<aRes.length;j++){
//把屬性值為aRes[2]的標簽推入aChild中
if(aRes[j].getAttribute(aStr[1])==aStr[2]){
aChild.push(aRes[j]);
}
}
//標簽選擇器 p、span
}else{
var aRes=aParent[i].getElementsByTagName(str);
for(var j=0;j<aRes.length;j++){
aChild.push(aRes[j]);
}
}
break;
}
}
return aChild;
}
function getEle(str){
//如果是字符串的話先要去除收尾空格 eg:" on replace index play auto "
var arr = str.replace(/^\s+|\s+$/g,'').split(/\s+/g);
var aChild = [];
var aParent = [document];
for(var i = 0;i<arr.length;i++){
aChild = getByStr(aParent,arr[i]);
aParent = aChild
}
return aChild;
}
//實現jquery $符號的寫法
function $(arg){
return new Jquery(arg);
}