前面的話
既然有getElementById()和getElementsByTagName()方法,為什么沒有getElementsByClassName()呢?id屬性、標簽名、class屬性并沒有什么優劣之分啊。終于,HTML5新增了getElementsByClassName()方法,由于在CSS布局中類名的廣泛使用,該方法正好切中痛點,使得通過類名選取元素不再困難,成為最受歡迎的一個方法。接下來,本文將詳細介紹該方法
使用
HTML元素的class屬性值是一個以空格隔開的列表,可以為空或包含多個標識符。在javascript中class是保留字,所以使用className屬性來保存HTML的class屬性值
getElementsByClassName()方法接收一個參數,即一個包含一個或多個類名的字符串,返回帶有指定類的所有元素的類數組對象HTMLCollection。傳入多個類名時,類名的先后順序不重要。與getElementsByTagName()類似,該方法既可以用于HTML文檔對象,也可以用于element元素對象
[注意]IE8-瀏覽器不支持
<ul id="list"> <li class="a ab c">1</li> <li class="a">2</li> <li class="ac">3</li> <li class="a b c">4</li> <li class="a b">5</li> </ul> <script> //類名中存在a成立 Array.prototype.forEach.call(list.getElementsByClassName('a'),function(item,index,arr){ item.style.fontWeight = 'bold'; }); //只有類名中同時存在a和c才成立 Array.prototype.forEach.call(list.getElementsByClassName('a c'),function(item,index,arr){ item.style.color = 'red'; }); </script>
classList屬性
在操作類名時,需要通過className屬性添加、刪除和替換類名。因為className是一個字符串,所以即使只修改字符串一部分,也必須每次都設置整個字符串的值。要從className字符串中刪除一個類名,需要把類名拆開,刪除不想要的那個,再重新拼成一個新字符串
HTML5為所有元素添加了classList屬性,這個classList屬性是新集合類型DOMTokenList的實例,它有一個表示自己包含多少元素的length屬性,而要取得每個元素可以使用item()方法,也可以使用方括號法
[注意]IE9-瀏覽器不支持
<div id="test" class="a b c"></div> <script> console.log(test.classList);//["a", "b", "c", value: "a b c"] console.log(test.classList[0]);//a console.log(test.classList.item(1));//b </script>
此外,這個新類型還定義如下方法:
add(value) 將給定的字符串值添加到列表中,如果值已存在,則不添加
contains(value) 表示列表中是否存在給定的值,如果存在則返回true,否則返回false
remove(value) 從列表中刪除給定的字符串
toggle(value) 如果列表中已經存在給定的值,刪除它;如果列表中沒有給定的值,添加它
有了classList屬性,className屬性基本沒有什么用武之地了
<style>
.cB{color: blue;}
</style>
<body>
<div id="test">測試文字</div>
<button id="btn1" onclick = "test.classList.add('cB')">add</button>
<button id="btn2" onclick = "test.classList.contains('cB')?alert(true):alert(false)">contains</button>
<button id="btn3" onclick = "test.classList.remove('cB')">remove</button>
<button id="btn4" onclick = "test.classList.toggle('cB')">toggle</button>
</body>
擴展
【1】由于原生的getElementsByClassName()方法不兼容IE8-瀏覽器,且該方法只能完全匹配參數中的類名列表。因此有如下擴展
擴展函數getElementsByClassName(),具有更豐富的功能。如果參數類名列表由空格分隔,則進行且匹配,即只有元素中的類名包含參數類名列表中的所有類名才算匹配成功;如果參數類名列表由逗號分隔,則進行或匹配,即只要元素中的類名包含參數類名列表中的其中一個類型就算匹配成功
Array.prototype.noRepeat = function(){ var result = []; for(var i = 0; i < this.length; i++){ if(result.indexOf(this[i]) == -1){ result.push(this[i]); } } return result; } Array.prototype.inArray = function(value){ for(var i = 0; i < this.length; i++){ if(this[i] === value){ return true; } } return false; } function getElementsByClassName(parentObj,classStr){ var result = []; //獲取parentObj下的所有子元素 var objs = parentObj.getElementsByTagName('*'); //條件一:如果classStr用空格分隔,則表示class必須同時滿足才有效 var targetArr1 = classStr.trim().split(/\s+/).noRepeat(); //條件二:如果classStr用逗號分隔,則表示class只要有一個滿足就有效 var targetArr2 = classStr.trim().split(/\s*,\s*/).noRepeat(); //只有一個class或者進行條件一測試 if(classStr.indexOf(',') == -1 ){ label: for(var i = 0; i < objs.length; i++){ //獲取每一個子元素的類名,將其轉換為數組后去重 var arr = objs[i].className.trim().split(/\s+/).noRepeat(); //進入循環,測試是否符合條件一 for(var j = 0; j < targetArr1.length; j++){ //如果條件一中的某一項在arr數組中不存在,則跳過該子元素 if(!arr.inArray(targetArr1[j])){ continue label; } } //將符合條件一的子元素對象放在結果數組中 result.push(objs[i]); } //返回結果數組 return result; //進行條件二測試 }else{ label: for(var i = 0; i < objs.length; i++){ //獲取每一個子元素的類名,將其轉換為數組后去重 var arr =objs[i].className.trim().split(/\s+/).noRepeat(); //進入循環,測試是否符合條件二 for(var j = 0; j < targetArr2.length; j++){ //只要條件二的中某一項在arr數組中存在,就符合 if(arr.inArray(targetArr2[j])){ //將符合條件二的子元素對象放在結果數組中 result.push(objs[i]); //接著進入下一個子元素測試 continue label; } } } //返回結果數組 return result; } }
<ul id="list"> <li class="a ab c">1</li> <li class="a">2</li> <li class="ac">3</li> <li class="a b c">4</li> <li class="a b">5</li> </ul> <script> //類名中存在a成立 getElementsByClassName(list,'a').forEach(function(item,index,arr){ item.style.fontWeight = 'bold'; }); //只有類名中同時存在a和c才成立 getElementsByClassName(list,'a c').forEach(function(item,index,arr){ item.style.color = 'red'; }); //只要類名中存在b或c即成立 getElementsByClassName(list,'b,c').forEach(function(item,index,arr){ item.style.backgroundColor = 'pink'; }); </script>
【2】由于IE9-瀏覽器不支持classList屬性,也就不支持add()、contains()、remove()和toggle()這四個方法,下面是這四個方法的兼容寫法
由于indexOf()和trim()方法都是ES5新增方法,在低版本IE瀏覽器中不支持,所以需要重新封裝
//數組的indexOf方法封裝 function indexOf(arr,value,start){ //如果不設置start,則默認start為0 if(arguments.length == 2){ start = 0; } //如果數組中存在indexOf方法,則用原生的indexOf方法 if(arr.indexOf){ return arr.indexOf(value,start); } for(var i = start; i < arr.length; i++){ if(arr[i] === value){ return i; } } return -1; } //數組去重方法封裝 function noRepeat(arr){ var result = []; for( var i = 0; i < arr.length; i++){ if(indexOf(result,arr[i]) == -1){ result.push(arr[i]); } } return result; } //inArray方法封裝 function inArray(arr,value){ for(var i = 0; i < arr.length; i++){ if(arr[i] === value){ return true; } } return false; } //去除首尾空格函數封裝 function trim(arr){ var result = arr.replace(/^\s+|\s+$/g,''); return result; }
1、add函數封裝
function addClass(obj,classStr){ var array = noRepeat(trim(obj.className).split('\s+')); if(!inArray(array,classStr)){ array.push(classStr); } obj.className = array.join(' '); return obj; }
2、contains函數封裝
function containsClass(obj,classStr){ var array = noRepeat(trim(obj.className).split('\s+')); if(inArray(array,classStr)){ return true; } return false; }
3、remove函數封裝
function removeClass(obj,classStr){ var array = noRepeat(trim(obj.className).split('\s+')); var index = indexOf(array,classStr); if(index != -1){ array.splice(index,1); obj.className = array.join(' '); } return obj; }
4、toggle函數封裝
function toggleClass(obj,classStr){ var array = noRepeat(trim(obj.className).split('\s+')); if(inArray(array,classStr)){ removeClass(obj,classStr); }else{ addClass(obj,classStr); } }
<style> .cB{color: blue;} </style> <div id="test">測試文字</div> <button id="btn1" onclick = "addClass(test,'cB')">add</button> <button id="btn2" onclick = "containsClass(test,'cB')?alert(true):alert(false)">contains</button> <button id="btn3" onclick = "removeClass(test,'cB')">remove</button> <button id="btn4" onclick = "toggleClass(test,'cB')">toggle</button>
文章列表