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 が「ライブ」であることです。クラス名を変更すると変化します。つまり、最初の要素のクラスを変更すると、リストはすぐに以前よりも 1 要素短くなります。

これを試して:

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

(「class」値を設定するために を使用する必要はありませんsetAttribute()。「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 から削除される要素は、現在使用している要素の次の要素だけになるため、その時点では 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 に答える