getElementsByClassNameを正しく反復する方法


100

私はJavascriptの初心者です。

私はを介してWebページを初期化しています。window.onloadクラス名(slide)で要素の束を見つけ、いくつかのロジックに基づいてそれらを異なるノードに再配布する必要があります。Distribute(element)要素を入力として受け取り、配布を行う関数があります。私はこのようなことをしたいです(例えばここまたはここで概説されているように):

var slides = getElementsByClassName("slide");
for(var i = 0; i < slides.length; i++)
{
   Distribute(slides[i]);
}

ただし、getElementsByClassName実際には配列を返さないため、これは私にとって魔法ではありませんが、、NodeListつまり

...これは私の推測です...

...関数内で変更されていますDistribute(DOMツリーがこの関数内で変更されており、特定のノードの複製が行われます)。For-eachループ構造も役に立ちません。

可変スライドは実際には決定論的ではなく、反復ごとに長さと要素の順序が大きく変化します。

私の場合、NodeListを反復処理する正しい方法は何ですか?一時的な配列を埋めることを考えていましたが、その方法がわかりません...

編集:

私が言及するのを忘れていた重要な事実は、別のスライドの中に1つのスライドがあるかもしれないということです。これはslides、ユーザーAlohciのおかげで見つけたばかりの変数を変更するものです

私の解決策は、最初に各要素を配列に複製し、Distribute()その後配列をono-by-oneに渡すことでした。


3
これは実際にそれを行う方法であるため、何か他のものを台無しにしている必要があります!
adeneo 2013

Distribute()関数はここにコピーされるように長くて複雑なことですが、私はDOM構造の内部を変更することだと確信して、私はまた、そこに要素を(クローニング)複製しています。デバッグすると、slides内部に渡されるたびに変数が変化することがわかります。
Kupto 2013

実際にどこかで変更しない限り、変更されません。
adeneo 2013

5
私はそれgetElementsByClassName()がlive を返すと信じているnodeListので、そのクラスの要素がnodeList変更を繰り返しているオーバーの長さに追加されます。
デビッドはモニカを復活させると2013

2
@ Kupto-ループを逆にすると、この種の問題が解決されることがよくあります。この場合、David Thomasが提供する理由により、Distribute関数が要素を削除または移動し、getElementsByClassName呼び出しと一致しなくなります。
Alohci 2013

回答:


129

MDNによると、からアイテムを取得する方法NodeListは次のとおりです。

nodeItem = nodeList.item(index)

したがって:

var slides = document.getElementsByClassName("slide");
for (var i = 0; i < slides.length; i++) {
   Distribute(slides.item(i));
}

私はこれを自分で試したことはありませんが(通常のforループは常に私のために機能しています)、試してみてください。


これは、同じクラスを持ち、互いの中にある要素を検索して変更しようとしない限り、正しい解決策です。質問の編集で回避策を説明しました。
Kupto 2013

確かに、それは考慮されていません。
Albert Xing

なぜ私が尋ねるかもしれないのに、なぜそうなのですか?このようにノードを反復できるように実装されていないのはなぜfor(var el in document.getElementsByClassName("foo")){}ですか?
Nearoo

3
for ... ofのように、NodeListを繰り返し処理できますfor (slide of slides) Distribute(slide)。ブラウザのサポートにはパッチがありますが、トランスパイルしている場合for ... ofは変換されますが変換されNodeList.forEachません。
Mr5o1 2017年

67

新しいquerySelectorAllを使用する場合は、forEachを直接呼び出すことができます。

document.querySelectorAll('.edit').forEach(function(button) {
    // Now do something with my button
});

以下のコメントごと。nodeListsにはforEach関数がありません。

これをbabelで使用する場合、追加できArray.from、非ノードリストをforEach配列に変換します。Array.from以下のブラウザー(IE 11を含む)ではネイティブで機能しません。

Array.from(document.querySelectorAll('.edit')).forEach(function(button) {
    // Now do something with my button
});

昨夜のミートアップで、forEachがないノードリストを処理する別の方法を発見しました

[...document.querySelectorAll('.edit')].forEach(function(button) {
    // Now do something with my button
});

ブラウザのサポート[...]

ノードリストとして表示

ノードリストとして表示

配列として表示

配列として表示


4
これについては、nodeListsにはすべてのブラウザーでforEach関数がありません。あなたはプロトタイプといじくり回すに喜んでいる場合は、それが行う簡単な十分です:if ( !NodeList.prototype.forEach ) {NodeList.prototype.forEach = Array.prototype.forEach;}
joshcanhelp

私の答えと@joshcanhelpからのコメントを組み合わせれば、エレガントなソリューションになります。おかげで:)もちろん、これは複数のループでラインの利点につながるだけです。
yarwest

1
すべてのブラウザで機能するとは限らないため、これは避けてください。ここで私が使用する簡単な回避策だと完全にどこでも動作するようです:css-tricks.com/snippets/javascript/...
tixastronauta

私はあなたが意味したと思います[...document.getElementsByClassName('.edit')].forEach(function(button) {
wp-overwatch.com

@ wp-overwatch.comドットはクラス名には必要ありません。正しいバージョンは次のようになります[...document.getElementsByClassName('edit')].forEach(function(button) {
MXT

11

常に配列メソッドを使用できます:

var slides = getElementsByClassName("slide");
Array.prototype.forEach.call(slides, function(slide, index) {
    Distribute(slides.item(index));
});

とても素敵で美しい答え、ありがとうございました!
Olga Farber 2017

配布とは何ですか?
lesolorzanov

7

ライブなので、逆にループするというAlohciの推奨に従いましたnodeList。好奇心が強い人のために私がしたことは...

  var activeObjects = documents.getElementsByClassName('active'); // a live nodeList

  //Use a reverse-loop because the array is an active NodeList
  while(activeObjects.length > 0) {
    var lastElem = activePaths[activePaths.length-1]; //select the last element

    //Remove the 'active' class from the element.  
    //This will automatically update the nodeList's length too.
    var className = lastElem.getAttribute('class').replace('active','');
    lastElem.setAttribute('class', className);
  }

1
 <!--something like this--> 
<html>
<body>



<!-- i've used for loop...this pointer takes current element to apply a 
 particular change on it ...other elements take change by else condition 
-->  


<div class="classname" onclick="myFunction(this);">first</div>  
<div class="classname" onclick="myFunction(this);">second</div>


<script>
function myFunction(p) {
 var x = document.getElementsByClassName("classname");
 var i;
 for (i = 0; i < x.length; i++) {
    if(x[i] == p)
    {
x[i].style.background="blue";
    }
    else{
x[i].style.background="red";
    }
}
}


</script>
<!--this script will only work for a class with onclick event but if u want 
to use all class of same name then u can use querySelectorAll() ...-->




var variable_name=document.querySelectorAll('.classname');
for(var i=0;i<variable_name.length;i++){
variable_name[i].(--your option--);
}



 <!--if u like to divide it on some logic apply it inside this for loop 
 using your nodelist-->

</body>
</html>

0

私はイテレーションで同様の問題があり、私はここに着陸しました。たぶん他の誰かが私がしたのと同じ間違いをしているのかもしれません。

私の場合、セレクターはまったく問題ではありませんでした。問題は、JavaScriptコードをめちゃくちゃにしていたことです。ループとサブループがありました。サブループものi代わりにカウンターとして使用していたjため、サブループがiメインループの値をオーバーライドしていたため、このループが2回目の反復に到達することはありませんでした。

var dayContainers = document.getElementsByClassName('day-container');
for(var i = 0; i < dayContainers.length; i++) { //loop of length = 2
        var thisDayDiv = dayContainers[i];
        // do whatever

        var inputs = thisDayDiv.getElementsByTagName('input');

        for(var j = 0; j < inputs.length; j++) { //loop of length = 4
            var thisInput = inputs[j];
            // do whatever

        };

    };
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.