26

我想...

  1. 扫描文档以查找具有特定类名的所有元素
  2. 在该元素的 innerHTML 上执行一些关键功能
  3. 更改该元素的类名,以便以后再进行扫描时不会重做该元素

我认为这段代码可以工作,但由于某种原因,它在第一个实例之后中断了循环,并且元素的类名永远不会改变。请不要框架。

function example()
{
    var elementArray;

    elementArray = document.getElementsByClassName("exampleClass");

    for(var i = 0; i < elementArray.length; i++)
    {
        // PERFORM STUFF ON THE ELEMENT
        elementArray[i].setAttribute("class", "exampleClassComplete");
        alert(elementArray[i].className);
    }   
}

编辑(最终答案) ——这是最终产品以及我如何在我的站点中实施@cHao 的解决方案。目标是获取页面上的各种时间戳并将它们更改为时间之前。谢谢大家的帮助,我从这个问题中学到了很多东西。

function setAllTimeAgos()
{
    var timestampArray = document.getElementsByClassName("timeAgo");

    for(var i = (timestampArray.length - 1); i >= 0; i--)
    {
        timestampArray[i].innerHTML = getTimeAgo(timestampArray[i].innerHTML);
        timestampArray[i].className = "timeAgoComplete";
    }
}
4

5 回答 5

15

问题是返回给您的 NodeList 是“实时的”——它会随着您更改类名而改变。也就是说,当您更改第一个元素的类时,列表立即比原来短一个元素。

尝试这个:

  while (elementArray.length) {
    elementArray[0].className = "exampleClassComplete";
  }

(无需使用setAttribute()设置“class”值 - 只需更新“className”属性。setAttribute()在旧版本的 IE 中使用无论如何都行不通。)

或者,将您的 NodeList 转换为普通数组,然后使用您的索引迭代:

  elementArray = [].slice.call(elementArray, 0);
  for (var i = 0; i < elementArray.length; ++i)
    elementArray[i].className = "whatever";

正如评论中所指出的,这具有不依赖于 NodeList 对象语义的优点。(还要注意,再次感谢评论,如果您需要它在旧版本的 Internet Explorer 中工作,您必须编写一个显式循环来将元素引用从 NodeList 复制到数组。)

于 2013-05-27T17:28:33.317 回答
8

大多数返回元素列表的 DOM 函数都返回 NodeList 而不是数组。最大的区别是 NodeList 通常是live,这意味着更改文档会导致节点神奇地出现或消失。这可能会导致节点移动一点,并抛出一个不考虑它的循环。

但是,您可以简单地在返回的列表上向后循环,而不是将列表转换为数组或其他任何东西。

function example()
{
    var elements = document.getElementsByClassName("exampleClass");

    for(var i = elements.length - 1; i >= 0; --i)
    {
        // PERFORM STUFF ON THE ELEMENT
        elements[i].className = "exampleClassComplete";

        // elements[i] no longer exists past this point, in most browsers
    }   
}

NodeList 的活跃度在这一点上并不重要,因为从中删除的唯一元素将是您当前所在的元素之后的元素。之前出现的节点不受影响。

于 2013-05-27T18:42:53.237 回答
1

另一种方法可能是使用选择器:

var arr = document.querySelectorAll('.exampleClass');
for (var i=0;i<arr.length;i++) {
    arr.innerHTML = "new value";
}

尽管它与旧版浏览器不兼容,但如果 web 内容适用于现代浏览器,它也可以做到这一点。

于 2013-05-27T18:15:53.960 回答
0

另一种可能性,也应该是跨浏览器,使用手工定制的 getElementsByClassName,它返回一个固定节点列表作为数组。这应该支持 IE5.5 及更高版本。

function getElementsByClassName(node, className) {
    var array = [],
        regex = new RegExp("(^| )" + className + "( |$)"),
        elements = node.getElementsByTagName("*"),
        length = elements.length,
        i = 0,
        element;

    while (i < length) {
        element = elements[i];
        if (regex.test(element.className)) {
            array.push(element);
        }

        i += 1;
    }

    return array;
}
于 2013-05-27T18:35:59.830 回答
0

您还可以使用 2 个数组,将数据推送到第一个数组中,然后执行您需要执行的操作 [例如更改元素的类]:

function example()
{
    var elementArray=[];
    var elementsToBeChanged=[];
    var i=0;

    elementArray = document.getElementsByClassName("exampleClass");

    for( i = 0; i < elementArray.length; i++){
        elementsToBeChanged.push(elementArray[i]);
    }

    for( i=0; i< elementsToBeChanged.length; i++)
    {
        elementsToBeChanged[i].setAttribute("class", "exampleClassComplete");
    }
}
于 2013-05-27T18:10:59.090 回答