1

私はこれが数日前にうまく機能していたことを誓います...

elm = document.querySelectorAll(selector);
var frag = document.createDocumentFragment();
while (elm[0]){
    frag.appendChild(elm[0]);
}

そうです、これでelmノードリストから各ノードを追加する必要があります。最初のものが追加されると、2番目はノードリストの最初の位置に「移動」するため、次のものは常にelm[0]です。nodeListが完全に追加されると停止するはずです。elmしかし、これは私に無限ループを与えています。考え?

編集-私は何度か同じ答えを得たので...AnodeListは配列ではなく、ライブリファレンスです。ノードが「移動」(ここでは追加)されると、ノードリストから自動的に削除されます。答えはすべて「同じ要素を何度も追加している」と言っています。これが起こっていることですが、そうではないはずです。最初のノードが追加されると、次のノードがそのインデックスを取得するため、forループは機能しないはずです。

2回目の編集

したがって、問題は「なぜnodeList配列として動作するのか」ということです。ノードリストは、ノードがどこかに追加されるたびに更新される必要があります。最も独特です。

解決策(誰かがライブ+非ライブノードリストを処理するために何かを必要とする場合)

elm = (/*however you're getting a node list*/);
var frag = document.createDocumentFragment();
var elength = elm.length;
for (var b = 0; b<elength; b++){
    if (elm.length === elength){
        frag.appendChild(elm[b]);
    } else {
        frag.appendChild(elm[0].cloneNode());
    }
}

基本的には、ノードリストの長さが変更されているかどうかを確認するだけです。

4

6 に答える 6

4

MDNDocsから

Element.querySelectorAll

概要

指定されたCSSセレクターのグループに一致する、呼び出された要素の子孫であるすべての要素の非ライブNodeListを返します。

構文

elementList = baseElement.querySelectorAll(selectors);

どこ

  • elementList要素オブジェクトの非ライブリストです。
  • baseElement要素オブジェクトです。
  • selectors一致するセレクターのグループです。

上記のドキュメントから、ライブではないため、別の要素に追加しても自動的に削除されないことがわかります。デモを実行して、その機能を示します。

var selector = "div";
elm = document.querySelectorAll(selector);
var frag = document.createDocumentFragment();
console.log("before",elm.length);
frag.appendChild(elm[0]);
console.log("after",elm.length);

上記のコードを実行すると、コンソールに表示されます。

before    3
after     3

whileループを実行する場合は、配列に変換して項目をshift()オフにします

var selector = "div";
var elmNodeLIst = document.querySelectorAll(selector);
var frag = document.createDocumentFragment();
var elems = Array.prototype.slice.call(elmNodeLIst );
while (elems.length) {
    frag.appendChild(elems.shift());
}
console.log(frag);
于 2012-11-12T18:25:12.950 に答える
1

ノードリストの最初の項目を何度も何度も追加しています。配列からアイテムを削除することはありませんが、常に最初のアイテムをフラグメントに追加します。そして最初のものは常に同じです。

elm = document.querySelectorAll(selector);
var frag = document.createDocumentFragment();
while (elm.length){
    frag.appendChild(elm.shift());
}

これはあなたがやろうとしていたことに近いかもしれません。while (elm.length)アイテムが配列から削除されると、最終的に長さがゼロになり、これは不安定な値になり、ループが停止するため、使用できます。

また、配列からアイテムをフェッチするために使用elm.shift()します。これは、そのメソッドがインデックス0のアイテムを返し、配列から削除するためです。これにより、必要な元の配列のミューテーションが得られます。


ノードは親を1つしか持てないので、これが機能するかもしれないとあなたは思ったと思います。どこかに追加すると、前の親から削除されます。ただし、elmはDOMフラグメントではありません。これは、要素への参照を保持する単なるaray(またはおそらくNodeList)です。配列はこれらの要素の親ノードではなく、参照を保持するだけです。

このようにすると、ループが機能する可能性があります。これは、親ノードの子を毎回クエリするため、移動すると実際に変化するノードのリストです。

elm = document.getElementById(id);
var frag = document.createDocumentFragment();
while (elm.children[0]){
    frag.appendChild(elm.children[0]);
}
于 2012-11-12T18:06:48.623 に答える
0

そもそもうまくいくとは思っていなかったでしょう。

elmアレイは初期化され、更新されることはありません。実行の結果がdocument.querySelectorAll(selector);異なるものを返す場合でも、これによって配列内の現在の参照が変更されることはありません。

セレクターを再実行するか、配列の最初の要素を追加した後に手動で削除する必要があります。

于 2012-11-12T18:05:09.317 に答える
0

常に同じ要素を参照し、その要素がnullになることはないため、現在記述されているように、これは無限ループですelm[0](null以外/ゼロ以外の結果はtrueになります)。また、リスト全体で反復させるために、要素自体には何もしません。コレクションをトラバースするために、しばらくの間ではなくforループを使用するか、少なくとも何らかのインデクサーを使用する必要があります。

elm = document.querySelectorAll(selector);
var frag = document.createDocumentFragment();
for (i= 0; i < elm.length; i++)
{
    frag.appendChild(elm[i]);
}

編集:

ドキュメントから:

「ライブ」コレクション

ほとんどの場合、NodeListはライブコレクションです。これは、DOMツリーでの変更がコレクションに反映されることを意味します。

varlinks = document.getElementsByTagName('a'); //links.length === 2たとえば

document.body.appendChild(links [0] .cloneNode(true)); //別のリンクがドキュメントに追加されます
//'
links'NodeListが自動的に更新されます//links.length===3になりました。NodeListがdocument.querySelectorAllの戻り値である場合、それはライブではありません

このドキュメントを見ると、メソッドの現在の使用法は、ライブNodeListがないことを示しています。したがって、追加しても元のリストが変更されることはありません。この使用法を反映するようにループ内で使用法を変更するか、.cloneNode(true)手動で繰り返す必要があります。

于 2012-11-12T18:05:56.853 に答える
0

elm [0]は静的であり、上記のコード修正は以下のとおりです。

elm = document.querySelectorAll(".container");
var frag = document.createDocumentFragment();
console.log(elm);
var i=0;
while (elm[i]){
    frag.appendChild(elm[i++]);
}
于 2012-11-12T18:07:40.243 に答える
0

私は実際にはコードにあまり焦点を合わせていませんでした(そしてそれが理にかなっているかどうか-コメントから判断して-かどうか)。しかし、これが数日前に機能した場合、問題はコードセレクターに提供する入力にあります。

ユニットテストが役立つのはそのときです。コードが機能した入力を覚えている場合は、コードを再度機能させて、そこからデバッグを開始できます。

そうでなければ、あなたは自分自身に嘘をついているだけです。

于 2012-11-12T18:08:01.840 に答える