JavaScriptでDOMノードのすべての子要素を削除します


873

JavaScriptでDOMノードのすべての子要素を削除するにはどうすればよいですか?

次の(醜い)HTMLがあるとします。

<p id="foo">
    <span>hello</span>
    <div>world</div>
</p>

必要なノードを次のように取得します。

var myNode = document.getElementById("foo");

残っているfooように、どのように私はの子を削除でき<p id="foo"></p>ますか?

私はただ行うことができますか:

myNode.childNodes = new Array();

または私はいくつかの組み合わせを使用する必要がありremoveElementますか?

正直なDOMで答えてください。ただし、DOMのみの回答とともにjQueryで回答を提供する場合は、追加のポイントが必要です。

回答:


1674

オプション1 A:清算innerHTML

  • このアプローチは単純ですが、ブラウザーのHTMLパーサーを呼び出すため、高性能アプリケーションには適さない場合があります(ただし、ブラウザー値が空の文字列である場合に最適化される場合があります)。

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  myNode.innerHTML = '';
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via innerHTML</button>

オプション1 B:清算 textContent

  • 上記と同じですが、を使用します.textContentMDNによると、これはinnerHTMLブラウザーがHTMLパーサーを呼び出さず、代わりに要素のすべての子を単一の#textノードに即座に置き換えるため、より高速です。

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  myNode.textContent = '';
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via textContent</button>

オプション2 A:すべてを削除するためのループlastChild

  • この回答に対する以前の編集が使用されましたfirstChildが、これはlastChildコンピュータサイエンスと同様に使用するように更新されています。一般に、最初の要素を削除するよりも、コレクションの最後の要素を削除する方がはるかに高速です(コレクションの実装方法によって異なります)。 )。
  • ループは、チェックするために続けてfirstChild 念のそれをチェックするために高速ですfirstChildよりもlastChild(例えば要素のリストはUAによって送らリンクリストとして実装されている場合)。

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  while (myNode.firstChild) {
    myNode.removeChild(myNode.lastChild);
  }
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via lastChild-loop</button>

オプション2 B:すべてを削除するためのループlastElementChild

  • このアプローチは、親のすべての非Element(つまり、#textノードと<!-- comments -->)子を保持します(子孫は保持しません)。これは、アプリケーションで望ましい場合があります(たとえば、インラインHTMLコメントを使用してテンプレート命令を格納するテンプレートシステム)。
  • Internet Explorer lastElementChildがIE9のサポートを追加しただけなので、このアプローチは近年まで使用されていませんでした。

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  while (myNode.lastElementChild) {
    myNode.removeChild(myNode.lastElementChild);
  }
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <!-- This comment won't be removed -->
  <span>Hello <!-- This comment WILL be removed --></span>
  <!-- But this one won't. -->
</div>
<button id='doFoo'>Remove via lastElementChild-loop</button>

ボーナス:Element.clearChildrenモンキーパッチ:

  • ElementJavaScript のプロトタイプに新しいメソッドプロパティを追加して、その呼び出しを単純化できますel.clearChildren()(HTML要素オブジェクトelはどこにある)。
  • (厳密に言えば、これはポリフィルではなくサルパッチです。これは標準のDOM機能や欠落機能ではないためです。多くの状況では、モンキーパッチは当然推奨されません。)

if( typeof Element.prototype.clearChildren === 'undefined' ) {
    Object.defineProperty(Element.prototype, 'clearChildren', {
      configurable: true,
      enumerable: false,
      value: function() {
        while(this.firstChild) this.removeChild(this.lastChild);
      }
    });
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello <!-- This comment WILL be removed --></span>
</div>
<button onclick="this.previousElementSibling.clearChildren()">Remove via monkey-patch</button>


6
jQueryからは、次の2つの問題が考えられます。このメソッドは、子(およびその他の子孫)要素だけでなく、一致する要素のセット内のテキストも削除します。これは、DOM仕様に従って、要素内のテキストの文字列はその要素の子ノードと見なされるためです。さらに、「メモリリークを回避するために、jQueryは、要素自体を削除する前に、子要素からデータやイベントハンドラなどの他の構成要素を削除します。」
jottos

104
ところで、lastChildを使用する方が少し効果的ですjsperf.com/innerhtml-vs-removechild/15
Andrey Lushnikov

24
innerHTMLは、HTMLのみを扱う場合にのみ機能します。たとえば内部にSVGがある場合、要素の削除のみが機能します
stwissel 2013年

34
絶対にinnerHTML = ''を使用しないでください。しないでください。問題は、アイテムが削除されたように見えますが、内部的にはノードが存続し、処理速度が低下することです。理由により、すべての個別ノードを削除する必要があります。Google ChromeとIEの両方でテスト済み。間違っているため、innerHTMLの「ソリューション」を削除することを検討してください。
Kenji

15
@vsync賢治のコメントが根拠があるとは思わない。やることinnerHTML = ''は遅いですが、「間違っている」とは思いません。メモリリークの主張は証拠とともにバックアップする必要があります。
Chris Middleton

115

innerHTMLm93aが正しく言及しているように、現在受け入れられている答えは(少なくともIEとChromeでは)遅くなるという点で間違っています。

このメソッドを使用すると、ChromeとFFが劇的に高速になります(アタッチされたjqueryデータが破壊されます)。

var cNode = node.cloneNode(false);
node.parentNode.replaceChild(cNode, node);

FFとChromeではるかに速く、IEで最速です。

node.innerHTML = '';

InnerHTML は、イベントハンドラーを破壊したりjquery参照を壊したりすることはありません。https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTMLのソリューションとしても推奨され ます

最速のDOM操作方法(前の2つよりもまだ遅い)はRange除去ですが、範囲はIE9までサポートされません。

var range = document.createRange();
range.selectNodeContents(node);
range.deleteContents();

言及されている他のメソッドは同等であるように見えますが、異常値jquery(1.1.1および3.1.1)を除いて、innerHTMLよりもはるかに低速です。

$(node).empty();

ここでの証拠:

http://jsperf.com/innerhtml-vs-removechild/167 http://jsperf.com/innerhtml-vs-removechild/300 https://jsperf.com/remove-all-child-elements-of-a- dom-node-in-javascript (古いURLの編集が機能しないため、jsperfの再起動用の新しいURL)

Jsperfの「テストループごと」は「繰り返しごと」として理解されることが多く、削除するノードがあるのは最初の反復だけなので、結果は意味がなく、このスレッドにテストが誤って設定されていたため、投稿時に結果は意味がありません。


2
あなたのjsperfは完全に壊れています。それはあまり良い証拠ではありません。
bryc 2015年

4
これが現時点で最良の答えです。このスレッドの他のすべては偽情報です(!)これらすべての悪い古いテストをクリーンアップしていただきありがとうございます。
ベン

6
「InnerHTMLは、イベントハンドラーを破壊したり、jquery参照を台無しにしたりすることはありません」データjQuery.cacheを管理するために使用できる唯一の参照が、破棄したばかりの要素にあったため、に保持されているデータが孤立し、メモリリークが発生します。

1
「InnerHTMLは、イベントハンドラーを破壊したり、jquery参照を台無しにしたりすることはありません」とは、子ではなくコンテナーを指します。cloneNodeコンテナーを切り替えます。つまり、コンテナーへの参照は維持されません(jqueryなど)。jqueryのキャッシュは、jqueryデータが付加されている場合、jqueryを使用して要素を削除する価値があるかもしれません。うまくいけば、彼らはいつかWeakMapsに切り替えるでしょう。$ .cacheのクリーニング(またはその存在さえ)は、正式に文書化されていないようです。
npjohns

10
jsperfテストはここで壊れています。テストエンジンは、「エラー:反復中にDomノードが再作成されないため、テスト結果は無意味になります」と報告します。
センダーレ2017年

73

最新のJavascriptをremove

const parent = document.getElementById("foo");
while (parent.firstChild) {
    parent.firstChild.remove();
}

これは、ES5でノードの削除を記述する新しい方法です。それはバニラJSであり、以前のバージョンよりもはるかによく読みます。

ほとんどのユーザーは最新のブラウザを使用する必要があります。必要に応じて、トランスパイルできます。

ブラウザのサポート -95%Dec 2019


14
parent.children / parent.childNodesはライブリストなので、forループは機能しません。removeを呼び出すとリストが変更されるため、イテレータはすべてを繰り返すとは限りません。たとえば、クロムでは、他のすべてのノードをスキップすることになります。while (parent.firstChild) { parent.removeChild(parent.firstChild); }ループを使用することをお勧めします。developer.mozilla.org/en-US/docs/Web/API/ParentNode/children developer.mozilla.org/en-US/docs/Web/API/Node/childNodes
qix

3
読みにくいですがクールな速記:while (parent.firstChild && !parent.firstChild.remove());
Gibolt 2017年

1
パフォーマンスがそれほど[...parent.childNodes].forEach(el => el.remove());

1
これはTypescriptでは機能しません...代わりに使用してくださいwhile (selectElem.firstElementChild) { selectElem.firstElementChild.remove(); }
John Henckel

43
var myNode = document.getElementById("foo");
var fc = myNode.firstChild;

while( fc ) {
    myNode.removeChild( fc );
    fc = myNode.firstChild;
}

jQueryの影響を受ける子孫がある可能性がある場合は、jQueryデータをクリーンアップするいくつかのメソッドを使用する必要あります。

$('#foo').empty();

jQuery .empty()メソッドは、削除される要素に関連付けられたjQueryが確実にクリーンアップするようにします。

DOM単に子を削除する方法を使用する場合、そのデータは残ります。


innerHTMLメソッドは、最もパフォーマンスが優れています。つまり、jqueryの.empty()によってクリーンアップされるデータ:再帰ループを使用して子タグに関連付けられたjquery内のdata()を排除します(遅いですが、メモリ使用量を大幅に削減する可能性があります)。 .onclick = ...を使用するようなjquery 削除する子にそのようなイベントがない場合、innerHTMLの設定はリークしません。したがって、最良の答えは-場合によります。
Chris Moschini、2011年

1
firstChild式をwhileループの条件に直接入れてみませんか?while ( myNode.firstChild ) {
Victor Zamanian 2016年

while(fc = myNode.firstChild){ myNode.removeChild(fc); }
Valen

36

jQueryを使用する場合:

$('#foo').empty();

そうしない場合:

var foo = document.getElementById('foo');
while (foo.firstChild) foo.removeChild(foo.firstChild);

20

最速...

var removeChilds = function (node) {
    var last;
    while (last = node.lastChild) node.removeChild(last);
};

jsperf.com(クールなサイト!)へのリンクを提供しくれたAndrey Lushnikovに感謝します。

編集:明確にするために、firstChildとlastChildの間でChromeのパフォーマンスに違いはありません。一番上の答えは、パフォーマンスの優れたソリューションを示しています。


LINT警告なしで同じこと:clear:function(container){for(;;){var child = container.lastChild; if(!child)break; container.removeChild(child); }}
cskwg

9

子のないノードだけが必要な場合は、次のようにノードのコピーを作成することもできます。

var dupNode = document.getElementById("foo").cloneNode(false);

あなたが達成しようとしていることに依存します。


3
たぶん、これをフォローすることもできparent.replaceChild(cloned, original)ますか?これは、子を1つずつ削除するよりも速く、DOMをサポートするすべてのもの(つまり、SVGを含むすべてのタイプのXMLドキュメント)で機能するはずです。innerHTMLを設定すると、子を1つずつ削除するよりも高速になる可能性がありますが、HTMLドキュメント以外では機能しません。しばらくテストする必要があります。
Maarten

13
これは、を使用して追加されたイベントリスナーをコピーしませんaddEventListener
マシュー

あなたがその制限に耐えられるなら
DanMan

7

ここに別のアプローチがあります:

function removeAllChildren(theParent){

    // Create the Range object
    var rangeObj = new Range();

    // Select all of theParent's children
    rangeObj.selectNodeContents(theParent);

    // Delete everything that is selected
    rangeObj.deleteContents();
}

1
これは興味深いですが、他の方法に比べるとかなり遅いようです:jsperf.com/innerhtml-vs-removechild/256
Polaris878

6
element.textContent = '';

標準以外はinnerTextに似ています。それはです少し遅くよりもremoveChild()、それが使いやすいですし、削除するためにあまりにも多くのものを持っていない場合は多くのパフォーマンスの違いをすることはありません。


テキストノードは要素ではありません
check_ca 2014

申し訳ありませんが、実際にはすべての子要素が削除されます
check_ca

これは、古いバージョンのInternet Explorerでは機能しません。
pwdst 2017年

4

DanMan、Maarten、およびMattへの応答。ノードを複製してテキストを設定することは、私の結果では確かに実行可能な方法です。

// @param {node} node
// @return {node} empty node
function removeAllChildrenFromNode (node) {
  var shell;
  // do not copy the contents
  shell = node.cloneNode(false);

  if (node.parentNode) {
    node.parentNode.replaceChild(shell, node);
  }

  return shell;
}

// use as such
var myNode = document.getElementById('foo');
myNode = removeAllChildrenFromNode( myNode );

また、これは、parentNodeにアクセスしようとするとnullを返すdomにないノードでも機能します。さらに、安全を確保する必要がある場合は、コンテンツを追加する前にノードを空にしておくと非常に便利です。下のユースケースを検討してください。

// @param {node} node
// @param {string|html} content
// @return {node} node with content only
function refreshContent (node, content) {
  var shell;
  // do not copy the contents
  shell = node.cloneNode(false);

  // use innerHTML or you preffered method
  // depending on what you need
  shell.innerHTML( content );

  if (node.parentNode) {
    node.parentNode.replaceChild(shell, node);
  }

  return shell;
}

// use as such
var myNode = document.getElementById('foo');
myNode = refreshContent( myNode );

要素内の文字列を置き換えるときにこの方法が非常に役立つことがわかります。ノードに何が含まれるかわからない場合は、混乱をクリーンアップする方法を心配する代わりに、最初からやり直してください。


3
最悪の事態。元のノードをそのクローンに置き換えると、元のノードへの参照が失われます。イベントハンドラーやその他のバインディングは機能しません。
Arun Aravind

4

これが私が通常行うことです:

HTMLElement.prototype.empty = function() {
    while (this.firstChild) {
        this.removeChild(this.firstChild);
    }
}

そして出来上がり、後であなたは任意のdom要素を空にすることができます:

anyDom.empty()

私はこの解決策が好きです!innerHTMLを空の文字列に設定する代わりにこれを使用する必要がある理由は何ですか?
TheCodenator

パフォーマンス:domEl.innerHTML = ""貧弱であり、悪い習慣と見なされている
Ado Ren

3

それを達成するためのいくつかのオプションがあります:

最速 ():

while (node.lastChild) {
  node.removeChild(node.lastChild);
}

代替案(遅い):

while (node.firstChild) {
  node.removeChild(node.firstChild);
}

while (node.hasChildNodes()) {
  node.removeChild(node.lastChild);
}

推奨オプションのベンチマーク


3
var empty_element = function (element) {

    var node = element;

    while (element.hasChildNodes()) {              // selected elem has children

        if (node.hasChildNodes()) {                // current node has children
            node = node.lastChild;                 // set current node to child
        }
        else {                                     // last child found
            console.log(node.nodeName);
            node = node.parentNode;                // set node to parent
            node.removeChild(node.lastChild);      // remove last node
        }
    }
}

これにより、要素内のすべてのノードが削除されます。


...それは不必要な複雑なものであり、それがどのように機能するかについての説明は与えられていないため(これは実際には自明ではありません)、私は疑っています。
Periata Breatta 2016年

2

innerTextが勝者です!http://jsperf.com/innerhtml-vs-removechild/133。以前のすべてのテストで、親ノードの内部domは最初の反復で削除され、次にinnerHTMLまたはremoveChildが空のdivに適用されました。


5
innerText独自のMSのものです。ただ言って。
DanMan、2014

1
これは欠陥のあるテストであることを確認してください。var boxとしてではなく、IDに基づくDOMルックアップを介して利用できることに依存しています。whileループがこの低速な呼び出しを何度も行うため、ペナルティが課せられます。
nrabinowitz

2

Javascriptを介してノードの子ノードを削除する最も簡単な方法

var myNode = document.getElementById("foo");
while(myNode.hasChildNodes())
{
   myNode.removeChild(myNode.lastChild);
}

2

私は人々がやっているのを見ました:

while (el.firstNode) {
    el.removeChild(el.firstNode);
}

その後、誰かが使用して言った el.lastNodeが速い

ただし、これが最速だと思います。

var children = el.childNodes;
for (var i=children.length - 1; i>-1; i--) {
    el.removeNode(children[i]);
}

どう思いますか?

PS:このトピックは私にとって命の恩人でした。私のFirefoxアドオンがinnerHTMLを使用して拒否されました。それは長い間習慣でした。それから私はこれを見つけました。と私は実際に速度の違いに気づきました。ロード時にinnerhtmlは更新に少し時間がかかりましたが、addElementを使用するとすぐに更新されます。


1
まあ、私は最速かどうかを考えて、いくつかのjsperfテストはどちらのケースも証明できます
Nikos M.

これらのテストに感謝します。for (var i=0...ただし、それらは含まれません。しかし、ここで私はこれらのテストを実行したときに、私が得たものである:i.imgur.com/Mn61AmI.pngはので、これら3回のテストでfirstNodeが速い本当のクールでlastNodeとinnerHTMLのよりだった
Noitidart

テストを追加しました:jsperf.com/innerhtml-vs-removechild/220 el.firstNodeメソッドを実行する興味深いものは、最速の方法です
Noitidart

2

範囲ループを使用するのが私にとって最も自然な感じです。

for (var child of node.childNodes) {
    child.remove();
}

ChromeとFirefoxでの私の測定によると、それは約1.3倍遅いです。通常の状況では、これはおそらく問題にはなりません。


2
 let el = document.querySelector('#el');
 if (el.hasChildNodes()) {
      el.childNodes.forEach(child => el.removeChild(child));
 }

1
あなたのコードが何をしているのかを回答で説明してください。
Nirav Joshi

1
その自明
ブラックシープ

1

通常、JavaScriptは配列を使用してDOMノードのリストを参照します。したがって、これは、HTMLElements配列を介して実行することに関心がある場合にうまく機能します。また、注目に値します。JavaScriptprotoの代わりに配列参照を使用しているため、これはIEを含むすべてのブラウザーで機能するはずです。

while(nodeArray.length !== 0) {
  nodeArray[0].parentNode.removeChild(nodeArray[0]);
}

1

ここで最も簡単な方法に従って、内部でループされた "remove"を実行しないのはなぜですか。

const foo = document.querySelector(".foo");
while (foo.firstChild) {
  foo.firstChild.remove();     
}
  • 親divを選択する
  • Whileループ内で "remove"メソッドを使用して、最初の子要素を削除し、なくなるまで。

他のユーザーがその機能を理解できるように、コード行を説明してください。ありがとう!
イグナシオアラ

@IgnacioAra完了しました!
Neelansh Verma

1

誰かがこの質問を別の人が言っているのを見ただけで、私がまだ見ていない方法を追加しようと思いました:

function clear(el) {
    el.parentNode.replaceChild(el.cloneNode(false), el);
}

var myNode = document.getElementById("foo");
clear(myNode);

clear関数は、要素を取得し、親ノードを使用して、子を含まないコピーに置き換えます。要素がスパースの場合、パフォーマンスはそれほど向上しませんが、要素に多数のノードがある場合、パフォーマンスの向上が実現します。


1
実際、ここで言及されたようです。stackoverflow.com/ a
15441725/576767 –FélixGagnon-Grenier

フェリックス私はそれを逃したに違いありません、訂正+1のおかげで。
ハリーChilinguerian

1

機能のみのアプローチ:

const domChildren = (el) => Array.from(el.childNodes)
const domRemove = (el) => el.parentNode.removeChild(el)
const domEmpty = (el) => domChildren(el).map(domRemove)

domChildrenの「childNodes」は、直接の子要素のnodeListを提供します。子要素が見つからない場合は空になります。nodeListをマッピングするために、domChildrenはそれを配列に変換します。domEmptyは、関数domRemoveを削除するすべての要素にマップします。

使用例:

domEmpty(document.body)

body要素からすべての子を削除します。


0

jQueryの他の方法

var foo = $("#foo");
foo.children().remove();
//or
$("*", foo ).remove();
//or
foo.html("");
//or
foo.empty();

OPが正解のDOMで回答を述べたため、反対票を投じます。
ブウィンデルズ2015年

また、jQueryには.empty()メソッド$("#foo").empty()があります。
それで

-1

単にIEのみ:

parentElement.removeNode(true);

true -完全に削除することを意味します-つまり、すべての子も削除されます


1
IE?これは21世紀です。
everlasto

-1

最も簡単な方法:

let container = document.getElementById("containerId");
container.innerHTML = "";

これは機能しますcontainer.innerHTML = nullが、Internet Explorerがテキストを表示することに注意してくださいnull。だから、これは本当に子供たちを取り除くわけではない、と私は言うでしょう。
アルジャン

-1

シンプルで高速なforループの使用!!

var myNode = document.getElementById("foo");

    for(var i = myNode.childNodes.length - 1; i >= 0; --i) {
      myNode.removeChild(myNode.childNodes[i]);
    }

これは<span>タグでは機能しません!


上記のすべてのソリューションでは、コードが<span>タグを削除していません
Mohit Karkar

-3

その中に何かを戻したい場合divは、innerHTMLおそらくより良いです。

私の例:

<ul><div id="result"></div></ul>

<script>
  function displayHTML(result){
    var movieLink = document.createElement("li");
    var t = document.createTextNode(result.Title);
    movieLink.appendChild(t);
    outputDiv.appendChild(movieLink);
  }
</script>

.firstChildまたは.lastChildメソッドを使用すると、displayHTML()関数は後で機能しなくなりますが、.innerHTMLメソッドには問題ありません。


-4

これは私がjQueryを使用していない純粋なjavascriptですが、IEを含むすべてのブラウザーで機能し、非常に簡単に理解できます

   <div id="my_div">
    <p>Paragraph one</p>
    <p>Paragraph two</p>
    <p>Paragraph three</p>
   </div>
   <button id ="my_button>Remove nodes ?</button>

   document.getElementById("my_button").addEventListener("click",function(){

  let parent_node =document.getElemetById("my_div"); //Div which contains paagraphs

  //Let find numbers of child inside the div then remove all
  for(var i =0; i < parent_node.childNodes.length; i++) {
     //To avoid a problem which may happen if there is no childNodes[i] 
     try{
       if(parent_node.childNodes[i]){
         parent_node.removeChild(parent_node.childNodes[i]);
       }
     }catch(e){
     }
  }

})

or you may simpli do this which is a quick way to do

document.getElementById("my_button").addEventListener("click",function(){

 let parent_node =document.getElemetById("my_div");
 parent_node.innerHTML ="";

})

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