我们在 javascript 中有 getElementsByClassName 吗?

IT技术 javascript
2021-02-17 02:41:04

就像在 jQuery 中我们可以使用 $(".classname") 一样,javascript 中是否也有类似的东西?或者,如果我们没有这样的方法,那么我该如何实现。
根据http://www.dustindiaz.com/getelementsbyclass/, 我将不得不遍历所有标签,然后收集所有具有指定类的元素。

有没有更好的解决办法?

5个回答

我将不得不遍历所有标签,然后收集所有具有指定类的元素。

是的。不过,有几种方法可以改善您链接的页面的功能:

  • 传入的 RegExp 转义类名,这样它就不会被类名中的标点符号破坏。例如,调用不getElementsByClassName('ab.cd')应该匹配class="abxcd"

  • 定义的 HTML5 规范getElementsByClassName允许多个以空格分隔的类名,所有这些都必须出现在元素上才能匹配。实施这一点。

  • 可选地,允许传入标记名称的提示以缩小函数必须查看的元素数量,以查找仅影响一种类型的标记的常见情况。(这对真正的浏览器原生getElementsByClassName调用没有任何作用,所以你不应该依赖它来过滤掉你不想要的元素。)

示例实现:

if (!('getElementsByClassName' in document)) {
    document.getElementsByClassName= function(classnames, taghint) {
        var exps= classnames.split(/\s+/).map(function(name) {
            name= name.replace(/([/\\^$*+?.()|[\]{}])/g, '\\$1');
            return new RegExp('(^|\\s)'+name+'(\\s|$)');
        });
        var els= this.getElementsByTagName(taghint || '*');
        var matches= [];
        for (var i= 0, n= this.length; i<n; i++)
            var el= els[i];
            if (exps.every(function(exp) {
                return exp.test(el.className);
            }))
                matches.push(el);
        }
        return matches;
    };
}

然而,这也使用了一些 IE 还没有的 ECMAScript Fifth Edition(或 JavaScript 1.6)数组方法,因此您也必须为这些方法添加回退实现:

if (!('map' in Array.prototype)) {
    Array.prototype.map= function(mapper, that) {
        var other= new Array(this.length);
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this)
                other[i]= mapper.call(that, this[i], i, this);
        return other;
    };
}

if (!('every' in Array.prototype)) {
    Array.prototype.every= function(tester, that) {
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this && !tester.call(that, this[i], i, this))
                return false;
        return true;
    };
}
@bobince:你为什么不缓存this.length回调可能会改变数组,此时此实现与 1.6 中内置的实现不同。
2021-04-16 02:41:04
好点,2009-050 ​​最终草案似乎确实要求重现此行为。更新。
2021-05-01 02:41:04

不幸的是浏览器之间不一致。如果您不需要所有的 jQuery,但仍想根据 CSS 选择器进行选择,请查看Sizzle,jQuery 使用的选择器库。

另一个很好的实现 getElementsByClassName

混合了 XPath 和 DOM 实现;尽可能使用 XPath。

if (!('getElementsByClassName' in document)) {
    document.getElementsByClassName = function(className, parentElement) {
        if (Prototype.BrowserFeatures.XPath) {
            var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
            return document._getElementsByXPath(q, parentElement);
        } else {
            var children = ($(parentElement) || document.body).getElementsByTagName('*');
            var elements = [],
                child;
            for (var i = 0, length = children.length; i < length; i++) {
                child = children[i];
                if (Element.hasClassName(child, className)) elements.push(Element.extend(child));
            }
            return elements;
        }
    };
}​


PS:把它在这里是因为我猜它比bobince 的答案更快无意冒犯:)
从 John Resig 的getElementsByClassName 速度比较中得到这个

一些浏览器,例如 Firefox 3 支持getElementsByClassName,其他的你必须遍历所有的标签,所以如果你想用一个函数支持所有的浏览器,你应该使用迭代方法。

最好的解决方案是使用 jQuery 或任何其他将使用最佳可用方法的框架。

此外,了解您用于该性能测试的基准测试会很有趣。DOM 越小,它们看起来就越慢,但在较大的 DOM 树中,差异可以忽略不计。
2021-04-16 02:41:04
其实jQuery的1.3.2丰盈的querySelectorAllgetElementsByClassName,至少在我的浏览器(Firefox 3.5),使得它更慢。当然仍然比 JS 原生元素过滤要快得多,但不是最好的。
2021-04-17 02:41:04
querySelectorAll实际上预计会比 慢getElementsByClassName有人可能应该针对 jQuery 提交错误。
2021-04-20 02:41:04

是的,您必须迭代以支持所有浏览器。如果您这样做,请确保您利用浏览器存在的内置功能:

if(document.getElementsByClassName) {
   return document.getElementsByClassName(className);
} else {
   // iterate
}

除此之外,我和 Jochen 在一起;使用框架

if (document.getElementsByClassName), 或者if (typeof document.getElementsByClassName)==='function') - 上面的方法不会很有效,因为它会'undefined'成功测试字符串的真实性。
2021-05-01 02:41:04
哇,是的,我一定是在那里打断了自己的思路。嘿,你怎么在第一个版本中检查身份,而不是平等?..鉴于它typeof总是产生一个字符串?或者你只是认为这是一种最佳做法?
2021-05-12 02:41:04