深入理解javascript选择器API系列第二篇——getElementsByClassName

×

目录

[1]使用 [2]classList [3]扩展

前面的话

  既然有getElementById()和getElementsByTagName()方法,为什么没有getElementsByClassName()呢?id属性、标签名、class属性并没有什么优劣之分啊。终于,HTML5新增了getElementsByClassName()方法,由于在CSS布局中类名的广泛使用,该方法正好切中痛点,使得通过类名选取元素不再麻烦,成为最欢迎的一个方法。接下来,本文将详细介绍该方法

使用

  HTML元素的class属性值是一个以空格隔开的列表,可以为空或包含多个标识符。在javascript中class是保留字,所以使用className属性来保存HTML的class属性值

  getElementsByClassName()方法接收一个参数,即一个包含一个或多个类名的字符串,返回带有指定类的所有元素的类数组对象NodeList。传入多个类名时,类名的先后顺序不重要。与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>
时间: 2024-08-01 10:45:23

深入理解javascript选择器API系列第二篇——getElementsByClassName的相关文章

深入理解javascript函数进阶系列第二篇——函数柯里化

前面的话 函数柯里化currying的概念最早由俄国数学家Moses Schönfinkel发明,而后由著名的数理逻辑学家Haskell Curry将其丰富和发展,currying由此得名.本文将详细介绍函数柯里化(curring) 定义 currying又称部分求值.一个currying的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来.待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值 从

深入理解表单脚本系列第二篇——表单字段

× 目录 [1]访问 [2]属性 [3]方法[4]事件 前面的话 表单字段又叫表单元素,表示表单所包含控件,如<input>.<select>等.本文将详细介绍表单字段的内容 访问 每个表单都有elements属性,该属性是表单中所有元素的集合.这个elements集合是一个有序列表,其中包含着表单中的所有字段,如<input>.<textarea>.<button>和<fieldset> 每个表单字段在elements集合中的顺序,

深入理解DOM事件机制系列第二篇——事件处理程序

× 目录 [1]HTML [2]DOM0级 [3]DOM2级[4]IE[5]总结 前面的话 事件处理程序又叫事件侦听器,实际上就是事件的绑定函数.事件发生时会执行函数中相应代码.事件处理程序有HTML事件处理程序.DOM0级事件处理程序.DOM2级事件处理程序和IE事件处理程序四类,下面将详细介绍该部分内容 HTML事件处理程序 某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定.这个特性的值应该是能够执行的JavaScript代码 在事件处理程序函数内部,this

深入理解javascript选择器API——4种元素选择器

× 目录 [1]id属性 [2]标签名 [3]name属性[4]all 前面的话 说到最常见的DOM应用,恐怕就要数取得特定的某个或某组元素的引用了.DOM定义了许多方式来选取元素,包括getElementById().getElementsByTagName().getElementsByName()和document.all()4种.接下来,将对这4种方法进行详细介绍 getElementById() 任何HTML元素可以有一个id属性,在文档中该值必须唯一 [注意]若浏览器中出现多个id名

深入理解javascript作用域系列第二篇——词法作用域和动态作用域

× 目录 [1]词法 [2]动态 前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极易出错.这实际上是由两种作用域工作模型导致的,作用域分为词法作用域和动态作用域,分清这两种作用域模型就能够对变量查找过程有清晰的认识.本文是深入理解javascript作用域系列第二篇——词法作用域和动态作用域 词法作用域 第一篇介绍过,编译器的第一个工作阶段叫作分词,就是把由字符组成的字符串分解成

EnjoyingSoft之Mule ESB基础系列第二篇:Mule ESB基本概念

目录 1. 使用Anypoint Studio开发 2. Mule ESB Application Structure - Mule ESB应用程序结构 3. Mule ESB Application整体构造 4. Mule ESB构造元素 - Flow 5. Mule ESB构造元素 - Connector 6. Mule ESB构造元素 - Processor Mule ESB在众多开源的ESB中处于领先者的地位,MuleSoft公司也作为独角兽,2017年在纽交所上市.我们作为MuleSo

ansible系列第二篇(模块使用)

ansible系列第二篇(模块使用) 模块使用 设置ansible提权 在hosts文件加入sudo提权的密码: 18.18.23.102 ansible_become_pass='passwd' 执行: ansible test -S -R root -m shell -a "ls -l /" 查看ansible有那些模块: ansible-doc -l 获取各个模块详细帮助信息 ansible-doc -s ping ping模块: ansible test -m ping 从受控

深入理解javascript对象系列第二篇——属性操作

× 目录 [1]查询 [2]设置 [3]删除[4]继承 前面的话 对于对象来说,属性操作是绕不开的话题.类似于“增删改查”的基本操作,属性操作分为属性查询.属性设置.属性删除,还包括属性继承.本文是对象系列的第二篇——属性操作 属性查询 属性查询一般有两种方法,包括点运算符和方括号运算符 var o = { p: 'Hello World' }; o.p // "Hello World" o['p'] // "Hello World" [注意]变量中可以存在中文,因

chromium浏览器开发系列第二篇:如何编译最新chromium源码

说一下为什么这么晚才发第二篇,上周和这周department的工作太多了,晚上都是十点半从公司出发,回家以后实在没有多余的精力去摸键盘了.所以请大家包涵! 上期回顾: chromium源码下载: 1.找个靠谱的vpn(我试过了,网上说的不用vpn拿代码的都不靠谱): 2.获取depot_tools,解压,设置环境变量; 3.gclient获取python和git,svn,设置环境变量: 4.fetch–nohooks chromium –nosvn=true 获取源码: 5.gclientsyn