JavaScript跨浏览器获取页面中相同class节点的方法

网页开发时,在很多时候我们需要操作相同类名的元素,即class相同的元素。昨天参加笔试,有一道相关的题目没答上来:

JavaScript获取页面中class为test的节点

于是收集了一些相关的资料,在本文中列举了两种我觉得比较好的方法,不足之处,还望大家批评指正。如果大家有更好的方法,希望可以分享。

Solution1 Jeremy Keuth方案

Jeremy Keuth大叔在《JavaScript DOM 编程艺术》(第2版)(英文:DOM Scripting-Web Design with JavaScript and the Document Object Model)一书的第三章第四节中讲到了getElementsByClass这个方法,并讲到了如何在不支持该属性的浏览器(IE6,IE7和IE8,让我们鄙视他们)中应用这一方法,摘录在此,个别地方有修改。

HTML5 DOM中新增了一个方法让我们通过class属性中的类名来访问元素,这就是:getELementsByClassName,由于方法比较新,某些的DOM实现里还没有,因此在使用的时候要当心。下面我们先来看一看这个方法能帮我们做什么,然后在讨论怎么可靠的使用该方法。
与getELementsByTagName方法类似,getElementsByClassName也只接受一个参数,就是类名:

代码如下:

getElementsByClassName(class)

这个方法的返回值也与getElementsByTagName类似,都是一个具有相同类名的元素的数组,下面这行代码返回的就是一个数组,其中包含类名为“sale”的所有元素:

代码如下:

document.getElementsByClassName("sale")

使用这个方法还可以查找那些带有多个类名的元素。要指定多个类名,只要在字符串参数中用空格分隔类名即可。例如,在<script>标签中添加下面这行代码:

代码如下:

alert(document.getElementsByClassName("sale important").length);

完整代码

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Shopping List</title>
</head>
<body>
    <h1>What to buy</h1>
    <p title="a gentle reminder">Don't forget to buy this stuff.</p>
    <ul id="purchase">
        <li>A thin of beans</li>
        <li class="sale">Cheese</li>
        <li class="sale important">Milk</li>
    </ul>
    <script>
         alert(document.getElementsByClassName("sale important").length);
    </script>
</body>
</html>

你会看到警告框中显示1,表示只有一个元素匹配,因为只有一个元素同时带有”important”和”sale”类名。注意,即使在元素的class属性中,类名的顺序是”sale important”而非参数中指定的”important sale”,也会照样匹配该元素。不仅类名的实际顺序不重要,就算元素还带有更多类名也没有关系。与使用getELementsByTagName一样,也可以组合使用getElementsByClassName和getElementById。如果你想知道在id为purchase的元素中有多少类名包含test的列表项,可以先找到那个特定的对象,然后再调用getElementsByClassName:

代码如下:

var shopping=document.getElementById("purchase");
var sales = shopping.getElementsByClassName("sale");

这样,sales数组中包含的就只是位于”purchase”列表中的带有”sales”类的元素,运行下面这行代码,就会看到sales数组包含两项:

代码如下:

alert(sales.length);

这个getELementsByClassName方法非常有用,但只有较新的浏览器(Safari 3.1,Chorme,Firefox 3 and Opera 9.5以上)才支持它。为了弥补这一不足,DOM脚本程序员需要使用已有的DOM方法来实现自己的getElementsByClassName,有点像成人礼似的。而多数情况下,他们的实现过程都与下面这个getElementsByClassName大致相似,这个函数能适用于新老浏览器。

代码如下:

function getElementsByClassName(node,classname){
    if(node.getElementsByClassName){
         return node.getElementsByClassName(classname);
    }else{
        var results = [];
        var elems = node.getElementsByTagName("*");
        for(var i=0;i<elems.length;i++){
            if(elems[i].className.indexOf(classname)!=-1){
                results[results.length]=elems[i];
            }
        }
    return results;
    }
}

这个getElementsByClassName函数接受两个参数。第一个node表示DOM树中的搜索起点,第二个classname就是要搜索的类名了。如果传入节点上已经存在了适当的getElementsByClassName函数,那么这个新函数就直接返回相应的节点列表。如果getElementsByClassName函数不存在,这个新函数就会循环遍历所有标签,查找带有相应类名的元素。

这个方法的缺点是不适用于多个类名。

如果使用这个函数来模拟前面取得购物列表的操作,就可以这样写:

代码如下:

var shopping=document.getElementById("purchase");
var sales = shopping.getElementsByClassName(shopping,"test");
console.log(sales);

因此,要解决文章开头的那道题目,所用代码如下:

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Shopping List</title>
</head>
<body>
    <h1>What to buy</h1>
    <p title="a gentle reminder">Don't forget to buy this stuff.</p>
    <ul id="purchase">
        <li>A thin of beans</li>
        <li class="sale">Cheese</li>
        <li class="sale important">Milk</li>
    </ul>
<script>
    function getElementsByClassName(node,classname){
        if(node.getElementsByClassName){
            return node.getElementsByClassName(classname);
        }else{
            var results = [];
            var elems = node.getElementsByTagName("*");
            for(var i=0;i<elems.length;i++){
               if(elems[i].className.indexOf(classname)!=-1){
                   results[results.length]=elems[i];
               }
            }
            return results;
        }
    }
    var body = document.getElementsByTagName("body")[0];
    var sales= getElementsByClassName(body,"sales");
    console.log(sales);
</script>
</body>
</html>

Solution2 Robert Nyman方案

搜索匹配的DOM元素的方法还有很多,但真正高效的却不多,Jeremy Keuth大叔的方法有一个缺点就是不能用于多个类名,2008年,Robert Nyman在文章 The Ultimate GetElementsByClassName, Anno 2008中提供了自己的解决方案。在2005年,Robert大叔就已经给出了自己的getElementsByClassName的函数,在2008年的时候,修改了部分代码,添加了许多新的功能:

1.如果当前浏览器支持getElementsByClassName函数,则调用该原生函数;
2.如果当前浏览器支持则使用XPath;//小飞鱼:一种浏览器内置的定位XML文档的强大方式,不过浏览器支持方面不统一
3.支持多个类名的搜索,不计先后顺序;
4.返回真正的节点数组,而不是原生的一个nodelist。//小飞鱼:原生的getElementsByClassName方法返回的是一个NodeList对象,它很像数组,有length和数字索引属性,但并不是数组,不能用pop,push等数组特有的方法,Robert提供的代码中,将NodeList对象转成了数组。可以将NodeList对象转换成数组的方法:

代码如下:

myList = Array.prototype.slice.call (myNodeList)

这是Robert大叔的方法,有些地方还不太明白,待我研究一下再来更新好了。

代码如下:

/*
Developed by Robert Nyman, http://www.robertnyman.com
Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/
var getElementsByClassName = function (className, tag, elm){
    if (document.getElementsByClassName) {
        getElementsByClassName = function (className, tag, elm) {
            elm = elm || document;
            var elements = elm.getElementsByClassName(className),
                nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
                returnElements = [],
                current;
            for(var i=0, il=elements.length; i<il; i+=1){
                current = elements[i];
                if(!nodeName || nodeName.test(current.nodeName)) {
                    returnElements.push(current);
                }
            }
            return returnElements;
        };
    }
    else if (document.evaluate) {
        getElementsByClassName = function (className, tag, elm) {
            tag = tag || "*";
            elm = elm || document;
            var classes = className.split(" "),
                classesToCheck = "",
                xhtmlNamespace = "http://www.w3.org/1999/xhtml",
                namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
                returnElements = [],
                elements,
                node;
            for(var j=0, jl=classes.length; j<jl; j+=1){
                classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
            }
            try {
                elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
            }
            catch (e) {
                elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
            }
            while ((node = elements.iterateNext())) {
                returnElements.push(node);
            }
            return returnElements;
        };
    }
    else {
        getElementsByClassName = function (className, tag, elm) {
            tag = tag || "*";
            elm = elm || document;
            var classes = className.split(" "),
                classesToCheck = [],
                elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
                current,
                returnElements = [],
                match;
            for(var k=0, kl=classes.length; k<kl; k+=1){
                classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
            }
            for(var l=0, ll=elements.length; l<ll; l+=1){
                current = elements[l];
                match = false;
                for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
                    match = classesToCheck[m].test(current.className);
                    if (!match) {
                        break;
                    }
                }
                if (match) {
                    returnElements.push(current);
                }
            }
            return returnElements;
        };
    }
    return getElementsByClassName(className, tag, elm);
};

(0)

相关推荐

  • js实现加载更多功能实例

    项目的一个前端页面展示已购买商品时,要求能下拉加载更多.关于如何实现『加载更多』功能,网上有插件可用,例如比较著名的使用iscroll.js实现的上拉加载更多.下拉刷新功能. 但实际用起来却是很麻烦.由于是第三方插件,要按照对方定义的方法使用,用起来总感觉很不顺心.再加上iscroll.js本身并没有集成加载更多的功能,需要进行自行扩展.想继续使用iscroll.js实现加载更多功能的,上面给的链接可以看看. h5项目里需要实现简单的分页功能,由于是移动端,考虑用『加载更多』会更好,而不是PC端

  • JavaScript判断窗口是否最小化的代码(跨浏览器)

    复制代码 代码如下: function isMinStatus() { var isMin = false; if (window.outerWidth != undefined) { isMin = window.outerWidth <= 160 && window.outerHeight <= 27; } else { isMin = window.screenTop < -30000 && window.screenLeft < -30000

  • myEvent.js javascript跨浏览器事件框架

    event究竟有多么复杂?可见前辈的6年前的努力:最佳的addEvent是怎样诞生的,后起之秀jQuery也付出了一千六百多行血汗代码(v 1.5.1)搞定了6年后出现的各种核的浏览器. 我参考前辈的代码以及自己的理解尝试写了一个事件框架,我的框架完成了一个事件机制的核心,它能提供统一接口实现多事件绑定以及避免内存泄漏等其他一些问题,更重要的是性能还不错. 我的手法: 所有回调函数根据元素.事件类型.回调函数唯一ID缓存在一个_create对象中(其内部具体结构可见下面源码的关于_cache的注

  • JavaScript实现跨浏览器的添加及删除事件绑定函数实例

    本文实例讲述了JavaScript实现跨浏览器的添加及删除事件绑定函数.分享给大家供大家参考.具体如下: IE 的事件绑定函数是 attachEvent:而 Firefox, Safari 是 addEventListener:Opera 则两种都支持.使用jQuery就可以使用简单的bind(),或者$().click()之类的函数解决,而如果不使用JavaScript框架的时候,大家可是使用下面的封装bind()函数. 添加事件绑定 bind() /*********************

  • js 实现一些跨浏览器的事件方法详解及实例

    js实现一些跨浏览器的事件方法 用JavaScript实现事件的绑定,移除,以及一些常用的事件属性的获取,时常要考虑到在不同浏览器下的兼容性,下面给出了一个跨浏览器的事件对象: var EventUtil = { on: function(element, type, handler) {/* 添加事件 */ if (element.addEventListener) { element.addEventListener(type, handler, false); } else if (ele

  • 基于JS快速实现导航下拉菜单动画效果附源码下载

    这是一个带变形动画特效的下拉导航菜单特效.该导航菜单在菜单项之间切换时,下拉菜单会快速的根据菜单内容的大小来动态变形,显示合适的下拉菜单大小,效果非常棒. 快速的导航下拉菜单动画效果如下所示: 效果演示         源码下载 HTML 该导航菜单的HTML结构如下: <header class="cd-morph-dropdown"> <a href="#0" class="nav-trigger">Open Nav&

  • 跨浏览器通用、可重用的选项卡tab切换js代码

    由于近来学了点js,于是我装逼道...不太难吧...就切一下display属性?同学无视我..说要搞个通用的...什么还要跟ajax交互..???我愣是没有听懂...到底要搞什么...权当作练手,我自己胡弄了一个. 需求:同学口中的通用我不知道神马意思...那我就按自己的理解吧.. ①跨浏览器,IE6+,FF,Chrome,Safari,Opera ②同一个页面可以用同一个js设置不同的选项卡. 说太多没啥米用,来看代码吧. 一.html部分(其实这还没啥好看的,设置了三个,前两个是一样的,通过

  • javascript跨浏览器的属性判断方法

    今天在写代码的时候发现一个很容易出错的地方.当我们在声明变量时,常常会因为不同的 browser 有不同的 API 定义,然后用以下的写法来判断哪一个属性,例如: 复制代码 代码如下: var fullscreenElement = document.mozFullScreenElement || document.webkitFullscreenElement || document.fullscreenElement; 用||来检查要用哪一个 attribute.不过要小心 javascri

  • JavaScript跨浏览器获取页面中相同class节点的方法

    网页开发时,在很多时候我们需要操作相同类名的元素,即class相同的元素.昨天参加笔试,有一道相关的题目没答上来: JavaScript获取页面中class为test的节点 于是收集了一些相关的资料,在本文中列举了两种我觉得比较好的方法,不足之处,还望大家批评指正.如果大家有更好的方法,希望可以分享. Solution1 Jeremy Keuth方案 Jeremy Keuth大叔在<JavaScript DOM 编程艺术>(第2版)(英文:DOM Scripting-Web Design wi

  • JavaScript获取页面中第一个锚定文本的方法

    本文实例讲述了JavaScript获取页面中第一个锚定文本的方法.分享给大家供大家参考.具体如下: 下面的JS代码通过document.archors数组获取第一个archor的innerHTML <!DOCTYPE html> <html> <body> <a name="html">jb51.net</a><br> <a name="css">CSS Tutorial</a

  • JavaScript获取页面中超链接数量的方法

    本文实例讲述了JavaScript获取页面中超链接数量的方法.分享给大家供大家参考,具体如下: 这里演示JavaScript取得页面的超链接数,感兴趣的朋友可以学习借鉴一下. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-total-link-num-codes/ 具体代码如下: <html> <head> <title>JavaScript取得页面的超链接数</title> <script l

  • css与javascript跨浏览器兼容性总结

    本文以大量实例形式总结了css与javascript跨浏览器的兼容性问题.分享给大家供大家参考.具体总结如下: 一.CSS样式兼容性 1. FLOAT闭合(clearing float) 网页在某些浏览器上显示错位很多时候都是因为使用了float浮动而没有真正闭合,这也是div无法自适应高度的一个原因.如果父div没有设float而其子div却设了float的话,父div无法包住整个子DIV,这种情况一般出现在一个父DIV下包含多个子DIV.解决办法: 1) 给父DIV也设上float 2) 在

  • javascript 跨浏览器开发经验总结(五) js 事件

    简单事件模型和高级事件模型 简单事件模型和高级事件模型简单事件,就是事件与页面元素直观的绑定在一起的形式,如: 复制代码 代码如下: <div onclick="alert(this.innerHTML);"> element.onclick = function(){alert(this.innerHTML);} 只要不是用了个别浏览器独有的事件,一般的click,mouseover事件等在各浏览器中都可以这么使用. 但是当一个事件需要绑定多个监听,或者需要动态注册/移出

  • 使用JavaScript获取URL中的参数(两种方法)

    本文给大家分享两种方法使用js获取url中的参数,其中方法二是使用的正则表达式方法,大家可以根据需要选择比较好的方法,废话不多说了,直接看详细介绍吧. 方法一: //取url参数 var type = request("type") function request() { var query = location.search; var paras = arguments[0]; if (arguments.length == 2) { query = arguments[1]; }

  • 详解javascript跨浏览器事件处理程序

    本文为大家分享了javascript跨浏览器事件处理机制,供大家参考,具体内容如下 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>跨浏览器的事件处理程序</title> </head> <body> <input type="button" value=

  • Jquery和JS获取ul中li标签的实现方法

    js 获取元素下面所有的li var content=document.getElementById("content"); var items=content.getElementsByTagName("ul"); var itemss=items[2].getElementsByTagName("li");//获取第二个li标签 或 var div=document.getElementById('a'); var ul=div.childN

  • Python基于lxml模块解析html获取页面内所有叶子节点xpath路径功能示例

    本文实例讲述了Python基于lxml模块解析html获取页面内所有叶子节点xpath路径功能.分享给大家供大家参考,具体如下: 因为需要使用叶子节点的路径来作为特征,但是原始的lxml模块解析之后得到的却是整个页面中所有节点的xpath路径,不是我们真正想要的形式,所以就要进行相关的处理才行了,差了很多网上的博客和文档也没有找到一个是关于输出html中全部叶子节点的API接口或者函数,也可能是自己没有那份耐心,没有找到合适的资源,只好放弃了寻找,但是这并不说明没有其他的方法了,在对页面全部节点

随机推荐