2022年4月30日

ドキュメントの変更

DOM操作は、「ライブ」ページを作成するための鍵です。

ここでは、新しい要素を「オンザフライ」で作成し、既存のページコンテンツを変更する方法を見ていきます。

例:メッセージを表示する

例を使って説明しましょう。alertよりも見栄えの良いメッセージをページに追加します。

どのように見えるかはこちらです

<style>
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<div class="alert">
  <strong>Hi there!</strong> You've read an important message.
</div>

これはHTMLの例でした。それでは、JavaScriptで同じdivを作成してみましょう(スタイルはすでにHTML/CSSにあると仮定します)。

要素の作成

DOMノードを作成するには、2つの方法があります

document.createElement(tag)

指定されたタグを持つ新しい_要素ノード_を作成します

let div = document.createElement('div');
document.createTextNode(text)

指定されたテキストを持つ新しい_テキストノード_を作成します

let textNode = document.createTextNode('Here I am');

ほとんどの場合、メッセージのdivなど、要素ノードを作成する必要があります。

メッセージの作成

メッセージdivの作成には3つの手順が必要です

// 1. Create <div> element
let div = document.createElement('div');

// 2. Set its class to "alert"
div.className = "alert";

// 3. Fill it with the content
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";

要素を作成しました。しかし、今のところ、それはページではなく、divという名前の変数にのみ存在します。そのため、見ることはできません。

挿入方法

divを表示するには、documentのどこかに挿入する必要があります。たとえば、document.bodyによって参照される<body>要素に挿入します。

そのためには、特別なメソッドappendがあります:document.body.append(div)

完全なコードはこちらです

<style>
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<script>
  let div = document.createElement('div');
  div.className = "alert";
  div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";

  document.body.append(div);
</script>

ここでは、document.bodyappendを呼び出しましたが、他の要素でappendメソッドを呼び出して、別の要素をその中に配置することもできます。たとえば、div.append(anotherElement)を呼び出すことで、<div>に何かを追加できます。

挿入する場所を指定する、さらに挿入方法があります

  • node.append(...nodes or strings) – ノードまたは文字列をnodeの_最後に_追加します。
  • node.prepend(...nodes or strings) – ノードまたは文字列をnodeの_先頭に_挿入します。
  • node.before(...nodes or strings) -- ノードまたは文字列をnodeの_前に_挿入します。
  • node.after(...nodes or strings) -- ノードまたは文字列をnodeの_後に_挿入します。
  • node.replaceWith(...nodes or strings) -- nodeを指定されたノードまたは文字列に置き換えます。

これらのメソッドの引数は、挿入するDOMノードまたはテキスト文字列(自動的にテキストノードになる)の任意のリストです。

実際に見てみましょう。

リストに項目を追加し、その前後にテキストを追加するためにこれらのメソッドを使用する例を次に示します

<ol id="ol">
  <li>0</li>
  <li>1</li>
  <li>2</li>
</ol>

<script>
  ol.before('before'); // insert string "before" before <ol>
  ol.after('after'); // insert string "after" after <ol>

  let liFirst = document.createElement('li');
  liFirst.innerHTML = 'prepend';
  ol.prepend(liFirst); // insert liFirst at the beginning of <ol>

  let liLast = document.createElement('li');
  liLast.innerHTML = 'append';
  ol.append(liLast); // insert liLast at the end of <ol>
</script>

メソッドの動作を視覚的に示した図を次に示します

最終的なリストは次のようになります

before
<ol id="ol">
  <li>prepend</li>
  <li>0</li>
  <li>1</li>
  <li>2</li>
  <li>append</li>
</ol>
after

前述のように、これらのメソッドは、1回の呼び出しで複数のノードとテキストを挿入できます。

たとえば、ここでは文字列と要素が挿入されています

<div id="div"></div>
<script>
  div.before('<p>Hello</p>', document.createElement('hr'));
</script>

注意:テキストは「HTMLとして」ではなく「テキストとして」挿入され、<>などの文字は適切にエスケープされます。

最終的なHTMLは次のようになります

&lt;p&gt;Hello&lt;/p&gt;
<hr>
<div id="div"></div>

言い換えれば、文字列はelem.textContentが行うのと同じように安全な方法で挿入されます。

したがって、これらのメソッドはDOMノードまたはテキストを挿入するためにのみ使用できます。

しかし、elem.innerHTMLが行うのと同じように、すべてのタグなどが機能するHTML文字列を「htmlとして」挿入したい場合はどうでしょうか?

insertAdjacentHTML/Text/Element

そのためには、別の非常に用途の広いメソッド:elem.insertAdjacentHTML(where, html)を使用できます。

最初のパラメーターはコードワードであり、elemを基準にしてどこに挿入するかを指定します。次のいずれかである必要があります

  • "beforebegin"htmlelemの直前に挿入します。
  • "afterbegin"htmlelemの先頭に挿入します。
  • "beforeend"htmlelemの最後に挿入します。
  • "afterend"htmlelemの直後に挿入します。

2番目のパラメーターはHTML文字列であり、「HTMLとして」挿入されます。

例えば

<div id="div"></div>
<script>
  div.insertAdjacentHTML('beforebegin', '<p>Hello</p>');
  div.insertAdjacentHTML('afterend', '<p>Bye</p>');
</script>

…は次のようになります

<p>Hello</p>
<div id="div"></div>
<p>Bye</p>

このようにして、任意のHTMLをページに追加できます。

挿入バリアントの図を次に示します

これと前の図の類似点に簡単に気付くことができます。挿入ポイントは実際には同じですが、このメソッドはHTMLを挿入します。

このメソッドには2つの兄弟がいます

  • elem.insertAdjacentText(where, text) – 同じ構文ですが、HTMLの代わりにtextの文字列が「テキストとして」挿入されます。
  • elem.insertAdjacentElement(where, elem) – 同じ構文ですが、要素を挿入します。

これらは主に構文を「統一」するために存在します。実際には、ほとんどの場合、insertAdjacentHTMLのみが使用されます。要素とテキストについては、メソッドappend/prepend/before/afterがあるため、記述が短く、ノード/テキストを挿入できます。

メッセージを表示する別の方法は次のとおりです

<style>
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<script>
  document.body.insertAdjacentHTML("afterbegin", `<div class="alert">
    <strong>Hi there!</strong> You've read an important message.
  </div>`);
</script>

ノードの削除

ノードを削除するには、メソッドnode.remove()があります。

1秒後にメッセージを消してみましょう

<style>
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<script>
  let div = document.createElement('div');
  div.className = "alert";
  div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";

  document.body.append(div);
  setTimeout(() => div.remove(), 1000);
</script>

注意:要素を別の場所に_移動_したい場合は、古い場所から削除する必要はありません。

すべての挿入メソッドは、古い場所からノードを自動的に削除します。

たとえば、要素を交換してみましょう

<div id="first">First</div>
<div id="second">Second</div>
<script>
  // no need to call remove
  second.after(first); // take #second and after it insert #first
</script>

ノードの複製:cloneNode

同様のメッセージをもう1つ挿入するにはどうすればよいでしょうか?

関数を作成してそこにコードを配置することもできます。しかし、別の方法は、既存のdivを_複製_し、その中のテキストを変更することです(必要な場合)。

大きな要素がある場合、それがより高速で簡単な場合があります。

  • elem.cloneNode(true)の呼び出しは、すべての属性とサブ要素を含む要素の「ディープ」クローンを作成します。elem.cloneNode(false)を呼び出すと、子要素のないクローンが作成されます。

メッセージをコピーする例

<style>
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<div class="alert" id="div">
  <strong>Hi there!</strong> You've read an important message.
</div>

<script>
  let div2 = div.cloneNode(true); // clone the message
  div2.querySelector('strong').innerHTML = 'Bye there!'; // change the clone

  div.after(div2); // show the clone after the existing div
</script>

DocumentFragment

DocumentFragmentは、ノードのリストを渡すためのラッパーとして機能する特別なDOMノードです。

他のノードを thereto に追加できますが、それをどこかに挿入すると、代わりにその内容が挿入されます。

たとえば、以下のgetListContent<li>項目を含むフラグメントを生成し、後で<ul>に挿入されます

<ul id="ul"></ul>

<script>
function getListContent() {
  let fragment = new DocumentFragment();

  for(let i=1; i<=3; i++) {
    let li = document.createElement('li');
    li.append(i);
    fragment.append(li);
  }

  return fragment;
}

ul.append(getListContent()); // (*)
</script>

最後の行(*)ではDocumentFragmentを追加しますが、「ブレンドイン」されるため、結果の構造は次のようになります

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>

DocumentFragmentが明示的に使用されることはめったにありません。ノードの配列を返すことができるのに、なぜ特別な種類のノードに追加するのでしょうか?書き直された例

<ul id="ul"></ul>

<script>
function getListContent() {
  let result = [];

  for(let i=1; i<=3; i++) {
    let li = document.createElement('li');
    li.append(i);
    result.push(li);
  }

  return result;
}

ul.append(...getListContent()); // append + "..." operator = friends!
</script>

DocumentFragmentについては、後で説明するテンプレート要素など、その上にいくつかの概念があるため、主に言及しています。

従来の挿入/削除メソッド

従来の方法
この情報は古いスクリプトを理解するのに役立ちますが、新しい開発には必要ありません。

歴史的な理由で存在する「従来の」DOM操作メソッドもあります。

これらのメソッドは非常に古い時代から来ています。今日では、appendprependbeforeafterremovereplaceWithなどの最新のメソッドの方が柔軟性があるため、これらを使用する理由はありません。

これらのメソッドをここでリストする唯一の理由は、多くの古いスクリプトで見つけることができるからです

parentElem.appendChild(node)

nodeparentElemの最後の子として追加します。

次の例では、新しい<li><ol>の最後に追加します

<ol id="list">
  <li>0</li>
  <li>1</li>
  <li>2</li>
</ol>

<script>
  let newLi = document.createElement('li');
  newLi.innerHTML = 'Hello, world!';

  list.appendChild(newLi);
</script>
parentElem.insertBefore(node, nextSibling)

nodeparentElemnextSiblingの前に挿入します。

次のコードは、2番目の<li>の前に新しいリスト項目を挿入します

<ol id="list">
  <li>0</li>
  <li>1</li>
  <li>2</li>
</ol>
<script>
  let newLi = document.createElement('li');
  newLi.innerHTML = 'Hello, world!';

  list.insertBefore(newLi, list.children[1]);
</script>

newLiを最初の要素として挿入するには、次のようにします

list.insertBefore(newLi, list.firstChild);
parentElem.replaceChild(node, oldChild)

parentElemの子の中でoldChildnodeに置き換えます。

parentElem.removeChild(node)

nodeparentElemから削除します(nodeがその子であると仮定します)。

次の例では、最初の<li><ol>から削除します

<ol id="list">
  <li>0</li>
  <li>1</li>
  <li>2</li>
</ol>

<script>
  let li = list.firstElementChild;
  list.removeChild(li);
</script>

これらのメソッドはすべて、挿入/削除されたノードを返します。言い換えれば、parentElem.appendChild(node)nodeを返します。しかし、通常は戻り値は使用されず、メソッドを実行するだけです。

「document.write」について

Webページに何かを追加する、非常に古いメソッドがもう1つあります:document.write

構文

<p>Somewhere in the page...</p>
<script>
  document.write('<b>Hello from JS</b>');
</script>
<p>The end</p>

document.write(html)の呼び出しは、htmlをページに「今すぐここ」に書き込みます。html文字列は動的に生成できるため、ある程度柔軟性があります。JavaScriptを使用して本格的なWebページを作成し、書き込むことができます。

このメソッドは、DOMも標準もない時代、本当に古い時代から来ています。それを使用するスクリプトがあるため、まだ生きています。

最新のスクリプトでは、次の重要な制限があるため、めったに見られません

document.writeの呼び出しは、ページの読み込み中にのみ機能します。

後で呼び出すと、既存のドキュメントの内容が消去されます。

例えば

<p>After one second the contents of this page will be replaced...</p>
<script>
  // document.write after 1 second
  // that's after the page loaded, so it erases the existing content
  setTimeout(() => document.write('<b>...By this.</b>'), 1000);
</script>

そのため、「読み込み後」の段階では、上記で説明した他のDOMメソッドとは異なり、使い物になりません。

それが欠点です。

利点もあります。技術的には、ブラウザが受信HTMLを読み込んでいる(「パース」している)間に document.write が呼び出され、何かを書き込むと、ブラウザはそれをHTMLテキストに最初から存在していたかのように処理します。

そのため、DOM操作が不要 なため、非常に高速に動作します。DOMがまだ構築されていない間に、ページテキストに直接書き込みます。

そのため、ページ読み込み段階で、大量のテキストをHTMLに動的に追加する必要があり、速度が重要な場合は、役立つ可能性があります。しかし、実際にはこれらの要件が揃うことはまれです。そして、通常、このメソッドは古いスクリプトにのみ見られます。

まとめ

  • 新しいノードを作成する方法

    • document.createElement(tag) – 指定されたタグを持つ要素を作成します。
    • document.createTextNode(value) – テキストノードを作成します(めったに使用されません)。
    • elem.cloneNode(deep) – 要素を複製します。deep==true の場合は、すべての子孫も含めて複製します。
  • 挿入と削除

    • node.append(...nodes or strings)node の末尾に挿入します。
    • node.prepend(...nodes or strings)node の先頭に挿入します。
    • node.before(...nodes or strings)node の直前に挿入します。
    • node.after(...nodes or strings)node の直後に挿入します。
    • node.replaceWith(...nodes or strings)node を置き換えます。
    • node.remove()node を削除します。

    テキスト文字列は「テキストとして」挿入されます。

  • 「旧式」のメソッドもあります

    • parent.appendChild(node)
    • parent.insertBefore(node, nextSibling)
    • parent.removeChild(node)
    • parent.replaceChild(newElem, node)

    これらのメソッドはすべて node を返します。

  • html にHTMLがいくつかある場合、elem.insertAdjacentHTML(where, html)where の値に応じてHTMLを挿入します。

    • "beforebegin"elem の直前に html を挿入します。
    • "afterbegin"htmlelemの先頭に挿入します。
    • "beforeend"htmlelemの最後に挿入します。
    • "afterend"elem の直後に html を挿入します。

    また、同様のメソッド elem.insertAdjacentTextelem.insertAdjacentElement があり、テキスト文字列と要素を挿入しますが、これらはめったに使用されません。

  • ページの読み込みが完了する前にHTMLを追加するには

    • document.write(html)

    ページの読み込み後、このような呼び出しはドキュメントを消去します。主に古いスクリプトで見られます。

タスク

重要度: 5

空のDOM要素 elem と文字列 text があります。

次の3つのコマンドのうち、どれが全く同じ動作をしますか?

  1. elem.append(document.createTextNode(text))
  2. elem.innerHTML = text
  3. elem.textContent = text

答え: 1と3

どちらのコマンドも、text を「テキストとして」elem に追加します。

例を示します

<div id="elem1"></div>
<div id="elem2"></div>
<div id="elem3"></div>
<script>
  let text = '<b>text</b>';

  elem1.append(document.createTextNode(text));
  elem2.innerHTML = text;
  elem3.textContent = text;
</script>
重要度: 5

要素からすべてを削除する関数 clear(elem) を作成します。

<ol id="elem">
  <li>Hello</li>
  <li>World</li>
</ol>

<script>
  function clear(elem) { /* your code */ }

  clear(elem); // clears the list
</script>

まず、間違った 方法を見てみましょう

function clear(elem) {
  for (let i=0; i < elem.childNodes.length; i++) {
      elem.childNodes[i].remove();
  }
}

これはうまくいきません。remove() を呼び出すと、コレクション elem.childNodes がシフトするため、要素は毎回インデックス 0 から始まります。しかし、i は増加し、一部の要素はスキップされます。

for..of ループも同様です。

正しい方法は次のとおりです

function clear(elem) {
  while (elem.firstChild) {
    elem.firstChild.remove();
  }
}

また、同じことを行うためのより簡単な方法があります

function clear(elem) {
  elem.innerHTML = '';
}
重要度: 1

以下の例では、table.remove() の呼び出しはドキュメントからテーブルを削除します。

しかし、実行すると、テキスト "aaa" がまだ表示されていることがわかります。

なぜそうなるのですか?

<table id="table">
  aaa
  <tr>
    <td>Test</td>
  </tr>
</table>

<script>
  alert(table); // the table, as it should be

  table.remove();
  // why there's still "aaa" in the document?
</script>

タスクのHTMLが正しくありません。それが奇妙なことが起こる理由です。

ブラウザはそれを自動的に修正する必要があります。ただし、仕様ではテーブル固有のタグのみが許可されているため、<table> 内にテキストがない場合があります。そのため、ブラウザは <table>"aaa" を表示します。

これで、テーブルを削除すると、テーブルが残ることが明らかです。

ブラウザツールを使用してDOMを調べると、簡単に質問に答えることができます。<table> の前に "aaa" が表示されます。

HTML標準では、不正なHTMLの処理方法が詳細に指定されており、ブラウザのこのような動作は正しいです。

重要度: 4

ユーザー入力からリストを作成するインターフェースを作成します。

リスト項目ごとに

  1. prompt を使用して、ユーザーにコンテンツについて尋ねます。
  2. それで <li> を作成し、<ul> に追加します。
  3. ユーザーが入力を取り消す(Esc キーを押すか、空の入力をする)まで続けます。

すべての要素は動的に作成する必要があります。

ユーザーがHTMLタグを入力した場合、それらはテキストとして扱われる必要があります。

新しいウィンドウでデモ

<li> コンテンツを割り当てるために textContent を使用していることに注意してください。

サンドボックスでソリューションを開く。

重要度: 5

ネストされたオブジェクトからネストされた ul/li リストを作成する関数 createTree を作成します。

例えば

let data = {
  "Fish": {
    "trout": {},
    "salmon": {}
  },

  "Tree": {
    "Huge": {
      "sequoia": {},
      "oak": {}
    },
    "Flowering": {
      "apple tree": {},
      "magnolia": {}
    }
  }
};

構文

let container = document.getElementById('container');
createTree(container, data); // creates the tree in the container

結果(ツリー)は次のようになります

このタスクを解決するには、次の2つの方法のいずれかを選択します

  1. ツリーのHTMLを作成し、container.innerHTML に割り当てます。
  2. ツリーノードを作成し、DOMメソッドで追加します。

両方できれば素晴らしいです。

追伸 ツリーには、リーフの空の <ul></ul> など、「余分な」要素があってはなりません。

タスクのサンドボックスを開く。

オブジェクトをウォークする最も簡単な方法は、再帰を使用することです。

  1. innerHTMLを使用したソリューション.
  2. DOMを使用したソリューション.
重要度: 5

ネストされた ul/li として編成されたツリーがあります。

<li> に子孫の数を追加するコードを作成します。リーフ(子を持たないノード)はスキップします。

結果

タスクのサンドボックスを開く。

<li> にテキストを追加するには、テキストノード data を変更できます。

サンドボックスでソリューションを開く。

重要度: 4

関数 createCalendar(elem, year, month) を作成します。

呼び出しは、指定された年/月のカレンダーを作成し、elem 内に配置する必要があります。

カレンダーはテーブルにする必要があります。週は <tr>、日は <td> です。テーブルの上部は、曜日名を含む <th> にする必要があります。最初の曜日は月曜日で、日曜日まで続きます。

たとえば、createCalendar(cal, 2012, 9) は、要素 cal に次のカレンダーを生成する必要があります

追伸 このタスクでは、カレンダーを生成するだけで十分です。まだクリック可能にする必要はありません。

タスクのサンドボックスを開く。

テーブルは文字列として作成します:"<table>...</table>"、そしてそれを innerHTML に割り当てます。

アルゴリズム

  1. <th> と曜日名を使用してテーブルヘッダーを作成します。
  2. 日付オブジェクト d = new Date(year, month-1) を作成します。これは month の最初の日です(JavaScriptでは月は 0 から始まることに注意してください。1 からではありません)。
  3. 月の最初の日 d.getDay() までの最初のいくつかのセルは空の場合があります。それらを <td></td> で埋めましょう。
  4. d の日付を増やします:d.setDate(d.getDate()+1)d.getMonth() がまだ次の月でない場合は、新しいセル <td> をカレンダーに追加します。日曜日であれば、改行 “</tr><tr>” を追加します。
  5. 月が終了したが、テーブル行がまだ満杯でない場合は、空の <td> を追加して、正方形にします。

サンドボックスでソリューションを開く。

重要度: 4

こちらのようなカラークロックを作成します

スタイリングにはHTML/CSSを使用し、JavaScriptは要素の時刻のみを更新します。

タスクのサンドボックスを開く。

まず、HTML/CSSを作成しましょう。

時刻の各コンポーネントは、独自の <span> に表示すると見栄えがよくなります

<div id="clock">
  <span class="hour">hh</span>:<span class="min">mm</span>:<span class="sec">ss</span>
</div>

また、色を付けるにはCSSが必要です。

update 関数はクロックを更新し、毎秒 setInterval によって呼び出されます

function update() {
  let clock = document.getElementById('clock');
  let date = new Date(); // (*)
  let hours = date.getHours();
  if (hours < 10) hours = '0' + hours;
  clock.children[0].innerHTML = hours;

  let minutes = date.getMinutes();
  if (minutes < 10) minutes = '0' + minutes;
  clock.children[1].innerHTML = minutes;

  let seconds = date.getSeconds();
  if (seconds < 10) seconds = '0' + seconds;
  clock.children[2].innerHTML = seconds;
}

(*) では、毎回現在の日付を確認しています。setInterval の呼び出しは信頼できません。遅延が発生する可能性があります。

クロック管理関数

let timerId;

function clockStart() { // run the clock
  if (!timerId) { // only set a new interval if the clock is not running
    timerId = setInterval(update, 1000);
  }
  update(); // (*)
}

function clockStop() {
  clearInterval(timerId);
  timerId = null; // (**)
}

update() の呼び出しは clockStart() でスケジュールされるだけでなく、行 (*) ですぐに実行されることに注意してください。そうしないと、訪問者は setInterval の最初の実行まで待たなければなりません。そして、それまでクロックは空になります。

また、クロックが実行されていない場合にのみ、clockStart() で新しい間隔を設定することが重要です。そうでない場合、開始ボタンを数回クリックすると、複数の同時インターバルが設定されます。さらに悪いことに、最後の間隔の timerID のみが保持され、他のすべての間隔への参照が失われます。そうすると、クロックを二度と停止できません!行 (**) でクロックが停止したときに timerID をクリアする必要があることに注意してください。そうすることで、clockStart() を実行してクロックを再び開始できます。

サンドボックスでソリューションを開く。

重要度: 5

ここで2つの <li> の間に <li>2</li><li>3</li> を挿入するコードを作成します

<ul id="ul">
  <li id="one">1</li>
  <li id="two">4</li>
</ul>

HTMLの一部をどこかに挿入する必要がある場合、insertAdjacentHTML が最適です。

ソリューション

one.insertAdjacentHTML('afterend', '<li>2</li><li>3</li>');
重要度: 5

テーブルがあります

<table>
<thead>
  <tr>
    <th>Name</th><th>Surname</th><th>Age</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>John</td><td>Smith</td><td>10</td>
  </tr>
  <tr>
    <td>Pete</td><td>Brown</td><td>15</td>
  </tr>
  <tr>
    <td>Ann</td><td>Lee</td><td>5</td>
  </tr>
  <tr>
    <td>...</td><td>...</td><td>...</td>
  </tr>
</tbody>
</table>

さらに多くの行が含まれている場合があります。

"name" 列でソートするコードを作成します。

タスクのサンドボックスを開く。

ソリューションは短いですが、少しトリッキーに見えるかもしれないので、ここでは詳細なコメントを付けて提供します

let sortedRows = Array.from(table.tBodies[0].rows) // 1
  .sort((rowA, rowB) => rowA.cells[0].innerHTML.localeCompare(rowB.cells[0].innerHTML));

table.tBodies[0].append(...sortedRows); // (3)

ステップバイステップのアルゴリズム

  1. <tbody> からすべての <tr> を取得します。
  2. 次に、最初の <td>(名前フィールド)のコンテンツで比較してソートします。
  3. 次に、.append(...sortedRows) でノードを正しい順序に挿入します。

行要素を削除する必要はありません。単に「再挿入」するだけで、古い場所から自動的に移動します。

追伸 この場合、テーブルには明示的な <tbody> がありますが、HTMLテーブルに <tbody> がない場合でも、DOM構造には常に <tbody> があります。

サンドボックスでソリューションを開く。

チュートリアルマップ

コメント

コメントする前に読んでください…
  • 改善の提案がある場合は、コメントする代わりに、GitHub issue を送信するか、プルリクエストを送信してください。
  • 記事の内容が理解できない場合は、詳しく説明してください。
  • 短いコードを挿入するには <code> タグを使用し、複数行の場合は <pre> タグで囲み、10行を超える場合はサンドボックス(plnkrjsbincodepen など)を使用してください。