DOMを使用すると、要素とその内容をどうにでも操作できますが、最初に、対応するDOMオブジェクトにアクセスする必要があります。
DOMに対するすべての操作はdocumentオブジェクトから始まります。これはDOMの主な「エントリポイント」です。これからは、すべてのノードにアクセスできます。
ここで、DOMノード間を移動するためのリンクが表示されています
これらを詳しく説明しましょう。
上空にdocumentElementとbody
最上位ツリーノードは、documentプロパティとして直接利用できます
<html>=document.documentElement- 最上位ドキュメントノードは
document.documentElementです。これは<html>タグのDOMノードです。 <body>=document.body- 他の幅広く使用されているDOMノードは
<body>要素、つまりdocument.bodyです。 <head>=document.head<head>タグはdocument.headとして使用できます。
document.bodyはnullになる可能性がありますスクリプトは、実行時に存在しない要素にアクセスすることはできません。
特に、スクリプトが<head>内にある場合、ブラウザはまだ読み込んでいないため、document.bodyは使用できません。
したがって、以下の例では、最初のalertはnullを表示します
<html>
<head>
<script>
alert( "From HEAD: " + document.body ); // null, there's no <body> yet
</script>
</head>
<body>
<script>
alert( "From BODY: " + document.body ); // HTMLBodyElement, now it exists
</script>
</body>
</html>
nullは「存在しない」を意味しますDOMでは、null値は「存在しない」または「このようなノードはない」を意味します。
子供:childNodes、firstChild、lastChild
今後使用する用語が2つあります
- 子ノード(または子供) - 直接の子要素です。言い換えると、これらは指定された要素に正確にネストされています。たとえば、
<head>と<body>は<html>要素の子です。 - 子孫 - 指定された要素にネストされているすべての要素。これには、子供、子供の子供などが含まれます。
たとえば、ここ<body>には子<div>と<ul>(およびいくつかの空白テキストノード)があります
<html>
<body>
<div>Begin</div>
<ul>
<li>
<b>Information</b>
</li>
</ul>
</body>
</html>
…そして<body>の子孫には直接的な子<div>、<ul>だけでなくより深く入れ子になった要素も含まれます。たとえば<li>(<ul>の子)や<b>(<li>の子)など、サブツリー全体です。
childNodesコレクションにはテキストノードを含むすべての子ノードがリストされます。
次の例はdocument.bodyの子を示します。
<html>
<body>
<div>Begin</div>
<ul>
<li>Information</li>
</ul>
<div>End</div>
<script>
for (let i = 0; i < document.body.childNodes.length; i++) {
alert( document.body.childNodes[i] ); // Text, DIV, Text, UL, ..., SCRIPT
}
</script>
...more stuff...
</body>
</html>
ここで興味深いことに注意してください。上の例を実行すると、最後に表示される要素は<script>です。実際には、その下にもっと要素がありますが、スクリプトが実行された時点ではブラウザはまだ読み込んでいないため、スクリプトには見えません。
firstChildとlastChildプロパティは最初と最後の子への高速アクセスを提供します。
これらは単なる省略記号です。子ノードが存在する場合、常に次のことが当てはまります。
elem.childNodes[0] === elem.firstChild
elem.childNodes[elem.childNodes.length - 1] === elem.lastChild
子ノードがあるかどうかを確認するために使用できる特殊関数elem.hasChildNodes()もあります。
DOMコレクション
わかるように、childNodesは配列のように見えます。しかし実際には配列ではなく、コレクション、つまり配列のような反復可能な特殊なオブジェクトです。
これには2つの重要な結果があります。
for..ofを使用して反復処理できます。
for (let node of document.body.childNodes) {
alert(node); // shows all nodes from the collection
}
これは反復可能であり(必要なようにSymbol.iteratorプロパティを提供するため)、反復できます。
- これは配列ではないため、配列メソッドは機能しません。
alert(document.body.childNodes.filter); // undefined (there's no filter method!)
配列メソッドが必要な場合は、最初に重要なのは素晴らしいことです。2番目は許容できます。Array.fromを使用してコレクションから「本当の」配列を作成できます。
alert( Array.from(document.body.childNodes).filter ); // function
DOMコレクション、さらに言えば、この章に記載されているすべてのナビゲーションプロパティは読み取り専用です。
childNodes[i] = ...を割り当てて、子を別のものに変えることはできません。
DOMを変更するには他のメソッドが必要です。これらは次の章で説明します。
マイナスの例外を除くほとんどすべてのDOMコレクションはアクティブです。言い換えれば、それらはDOMの現在の状態を反映します。
elem.childNodesへの参照を保持し、ノードをDOMに追加または削除すると、それらは自動的にコレクションに表示されます。
for..inを使用しないでください。コレクションはfor..ofを使用して反復処理できます。通常はfor..inを使用しようとします。
使用しないでください。for..inループはすべての列挙可能なプロパティを反復処理します。そしてコレクションには、通常は取得したくない「追加」のまれに使用されるプロパティがいくつかあります。
<body>
<script>
// shows 0, 1, length, item, values and more.
for (let prop in document.body.childNodes) alert(prop);
</script>
</body>
兄弟と親
兄弟は、同じ親の子であるノードです。
たとえば、ここで<head>と<body>は兄弟です。
<html>
<head>...</head><body>...</body>
</html>
<body>を<head>の「次」または「右」兄弟と呼び、<head>を<body>の「前」または「左」兄弟と呼びます。
次の兄弟はnextSiblingプロパティにあり、前の兄弟はpreviousSiblingにあります。
親はparentNodeとして使用できます。
たとえば
// parent of <body> is <html>
alert( document.body.parentNode === document.documentElement ); // true
// after <head> goes <body>
alert( document.head.nextSibling ); // HTMLBodyElement
// before <body> goes <head>
alert( document.body.previousSibling ); // HTMLHeadElement
要素のみのナビゲーション
上でリストしたナビゲーションプロパティは、すべてのノードを参照します。たとえば、childNodesでは、テキストノード、要素ノード、さらには存在する場合コメントノードの両方を見ることができます。
しかし、多くのタスクではテキストノードやコメントノードは必要ありません。タグを表し、ページの構造を形成する要素ノードを操作したいのです。
そこで、要素ノードのみを考慮するナビゲーションリンクをさらに詳しく見てみましょう
リンクは上記のリンクと似ていますが、Elementワードが内部にあるだけです
children– 要素ノードのみです。firstElementChild、lastElementChild– 最初の要素の子と最後の要素の子です。previousElementSibling、nextElementSibling– 近隣の要素です。parentElement– 親要素です。
parentElementなのか?親は要素以外になれないのか?parentElementプロパティは「要素」親を返し、parentNodeは「任意のノード」親を返します。これらのプロパティは通常同じです。どちらも親を取得します。
document.documentElementの例外を除いて
alert( document.documentElement.parentNode ); // document
alert( document.documentElement.parentElement ); // null
理由は、ルートノードdocument.documentElement(<html>)が親としてdocumentを持っているためです。ただし、documentは要素ノードではないため、parentNodeはそれを返し、parentElementは返しません。
任意の要素elemから<html>まで移動したいが、documentに移動したくない場合、この詳細が役立つ場合があります
while(elem = elem.parentElement) { // go up till <html>
alert( elem );
}
上記の例を修正しましょう。childNodesをchildrenに置き換えます。これで要素のみが表示されます
<html>
<body>
<div>Begin</div>
<ul>
<li>Information</li>
</ul>
<div>End</div>
<script>
for (let elem of document.body.children) {
alert(elem); // DIV, UL, DIV, SCRIPT
}
</script>
...
</body>
</html>
さらにリンク: テーブル
これまで、基本的なナビゲーションプロパティを説明してきました。
特定の種類のDOM要素は、利便性のためにその種類に固有の追加プロパティを提供する場合があります。
テーブルは素晴らしい実例で、特に重要なケースを表しています
<table>要素は(上記に加えて)これらのプロパティをサポートしています
table.rows– テーブルの<tr>要素のコレクションです。table.caption/tHead/tFoot–要素<caption>、<thead>、<tfoot>への参照です。table.tBodies–<tbody>要素のコレクションです(標準に従って複数存在できますが、ソースHTMLにない場合でも、ブラウザは常にDOMに入れます)。
<thead>、<tfoot>、<tbody>要素はrowsプロパティを提供します
tbody.rows– 内部の<tr>のコレクションです。
<tr>:
tr.cells– 指定された<tr>内の<td>および<th>セルのコレクションです。tr.sectionRowIndex– 囲まれた<thead>/<tbody>/<tfoot>内の指定された<tr>の位置(インデックス)です。tr.rowIndex– 表全体の<tr>の番号(すべての表行を含む)。
<td>および<th>
td.cellIndex– 囲まれた<tr>内のセルの番号です。
使用方法の例
<table id="table">
<tr>
<td>one</td><td>two</td>
</tr>
<tr>
<td>three</td><td>four</td>
</tr>
</table>
<script>
// get td with "two" (first row, second column)
let td = table.rows[0].cells[1];
td.style.backgroundColor = "red"; // highlight it
</script>
仕様: 表データ。
HTMLフォーム用の追加のナビゲーションプロパティもあります。フォームの使用を開始すると、後でそれらについて検討します。
要約
DOMノードが与えられると、ナビゲーションプロパティを使用してそのすぐ近くのノードに移動できます。
それらには2つの主要なセットがあります
- すべてのノードに対して、
parentNode、childNodes、firstChild、lastChild、previousSibling、nextSibling。 - 要素ノードに対してのみ、
parentElement、children、firstElementChild、lastElementChild、previousElementSibling、nextElementSibling。
テーブルなどの特定の種類のDOM要素では、追加のプロパティとコレクションが提供され、そのコンテンツにアクセスできます。
コメント
<code>タグを使用し、数行の場合は<pre>タグで囲み、10 行を超える場合はサンドボックス (plnkr、jsbin、codepen…) を使用します。