本日はJavaScriptでDOMの要素にアクセスし、それらを操作していく方法を解説致します。
JavaScript Documentオブジェクトは、ドキュメントのすべてのHTML要素へのアクセスを提供するオブジェクトとなります。
ドキュメントオブジェクトは、HTML、head、body、その他のHTMLタグなどのHTMLドキュメントの要素をオブジェクトとして格納します。
ドキュメントオブジェクトモデルまたはDOMが分からない方は下記で解説しております。
ドキュメントオブジェクトのプロパティ
ドキュメントオブジェクトは、ブラウザを参照するWindowオブジェクトの子オブジェクトとなります。
オブジェクトのプロパティは、オブジェクトに関連付けられた値です。
JavaScriptオブジェクトは、順序付けされていないプロパティのコレクションとなり、プロパティは通常では、変更、追加、および削除できますが、一部は読み取り専用です。
オブジェクトの状態を表すのがプロパティです。
プロパティには、下記の表記を使用してアクセスします。
objectName.propertyName
これら、追加、削除、変更、読み取りのプロパティはメソッドを扱う際に一緒に解説致します。
JavaScript オブジェクトメソッド
HTML要素はDOMで『オブジェクト』として定義されており、各オブジェクトにはいくつかのメソッドとプロパティを提供しています。
つまり、ブラウザに表示されたHTMLおよびそれに関連するCSSを操作する為の機能が多数用意されています。
本日、DOM操作に欠かせない学習する主なメソッドは下記となります。
メソッド名 | 構文 | 取得 |
---|---|---|
getElementById() | #sample | ID |
getElementsByClassName() | .sample | クラス |
getElementsByTagName() | h1 | タグ名 |
querySelector() | 複数 | セレクタ(単一) |
querySelectorAll() | 複数 | セレクタ(すべて) |
createElement() | "p" | タグ生成 |
remove() | * | 要素の削除 |
removeChild() | * | 要素の最後を削除 |
appendChild() | * | 新しいまたは既存のノードをドキュメントに挿入 |
setProperty() | * | CSSプロパティを指定し更新 |
removeProperty() | * | CSSプロパティを削除 |
まずはHTMLドキュメント内の要素を取得する最も一般的な方法の紹介を致します。
IDによる要素へのアクセス
指定されたIDを持つ要素には、下記のメソッドでアクセスできます。
document.getElementById()
指定されたIDを持つ単一の要素のみを返し、そのIDを持つ要素が見つからないまたは、存在しない場合は『null』を返します。
これは最も簡単な方法の1つです。
pタグでidの値はelementとします。
<p id="element">paragraph</p>
let element = document.getElementById("element"); element.innerHTML = "Hello!!"; // 出力 Hello!!
getElementById()メソッドでidの値である『element』を取得し、同じ名前の変数としてinnerHTMLプロパティで要素内をHello!!に書き換えています。
『innerHTML』プロパティは要素の中身であるコンテンツを取得します。
HTML要素の中身を自由自在に変更する際に使用されるプロパティとなります。
See the Pen IDによる要素の取得 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
別の例でも見てみましょう。
<body> <p id="demo">sample text to get elements by id.</p> <script> let demo = document.getElementById("demo"); //取得し変数に格納 console.log(demo);// 空 console.log(demo.innerHTML); //sample text to get elements by id. </script> </body>
取得した要素は『demo』変数に格納されます。
innerHTMLでコンテンツを取得し表示します。
このdocument.getElementById()メソッドは同じIDを持つ要素が複数(2つ以上)ある場合は、IDを持つ最初の要素のみを返します。
See the Pen IDによる要素へのアクセス by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
クラス名の要素へアクセス
HTMLの要素は、要素に同じクラス名を割り当てることでグループ化する事ができます。
それら要素はdocument.getElementsByClassName()メソッドを使用し取得が可能となります。
下記のHTMLを用意します。
pタグでクラス名は『demo』とします。
<body> <p class="demo">paragraph 1</p> <p class="demo">paragraph 2</p> <p class="demo">paragraph 3</p> </body>
下記では、getElementsByClassName()メソッドでidの値を引数にし、取得しています
要素はdemo変数に格納されております。
for文を使用しinnerHTMLで要素内を書き換えてdemoの要素を返します。
const sampleDemo = () => { let demo = document.getElementsByClassName("demo"); //取得し変数に格納 console.log(demo);// 0,1,2 for (i = 0; i < demo.length; i++) { console.log(demo[i].innerHTML = "The text has been rewritten."); } } sampleDemo() // 出力 The text has been rewritten. The text has been rewritten. The text has been rewritten. length: 3
これは、それぞれの要素には配列みたいなインデックスからアクセスできます。
ですが、正確には配列を返しているわけではありません。
そのため、上記のコードではループを使用して要素を読み取ることはできますが、配列のメソッドを使用できません。
See the Pen クラス名の要素へアクセス by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
では要素に複数のクラスが含まれる場合での取得を見ていきましょう。
<body> <p class="demo test">paragraph 1</p> <p class="demo">paragraph 2</p> <p class="demo">paragraph 3</p> <script> const sampleDemo = () => { let demo = document.getElementsByClassName("demo test"); //取得し変数に格納 console.log(demo); for (i = 0; i < demo.length; i++) { console.log(demo[i].innerHTML = "The text has been rewritten."); } } sampleDemo() </script> </body> // 出力 The text has been rewritten. test length: 0
この場合上記では、『demo 』と『test』を持つ要素を返し、指定したクラス名の要素が存在しない場合は、このメソッドは長さ『0』のHTMLコレクションを返します。
See the Pen 要素に複数のクラスがある場合の取得 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
要素に複数のクラスが含まれている場合は、スペースで区切られたクラスの名前でアクセス可能となります。
タグ名の要素にアクセス
タグ名で要素にアクセスすることも可能です。
document.getElementsByTagName()メソッドを使用します。
指定されたタグ名のすべての見つかった要素を、ドキュメントに存在する順序で返します。
下記では『 li 』タグ名を指定することにより、ドキュメントで使用可能なリスト要素を取得し数をカウントしてアラートでそれを通知します。
<body> <li>List 1</li> <li>List 2</li> <li>List 3</li> <li>List 4</li> <button onclick="sampleDemo()">Count </button> <script> const sampleDemo = () => { let demo = document.getElementsByTagName("li") // liタグ取得し変数に格納 alert("Total number of listings : " + demo.length); //Total number of listings : 4 } </script> </body>
See the Pen タグ名の要素を取得 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
ボタンタグでのonclickはイベントをトリガーにし処理を実行させるためのプロパティで、イベントハンドラーとなります。
ユーザーが要素をクリックしたタイミングで実行されます。
渡す値は関数または関数式(無名関数)となります。
上記ではアロー関数を使用しているので、渡すのは無名関数である変数名となります。
このgetElementsByTagName()で返されるのはHTMLコレクションです、HTMLコレクションは配列ではないため、ループを使用した場合は無限ループになるかまたは実行できない可能性があります。
それを回避するには、代わりに別のメソッドを使用します、後ほど紹介致しします。
クエリセレクタによる要素へのアクセス
HTML要素は、クエリセレクタを使用して選択することも可能です。
その方法は主に2種類ございます。
document.querySelector()メソッド
document.querySelectorAll()メソッド
querySelector()は指定されたセレクタに一致する最初の要素のみを返します。
一方で、querySelectorAll()は全ての要素を返します。
querySelector()から見ていきましょう。
querySelector()メソッドはid、クラス、タグおよびその他の全ての有効なCSSセレクター要素を取得できます。
querySelector("#id"); // id querySelector(".list"); //クラス querySelector("li"); //タグ
それだけでなく要素を具体的に指定し取得も可能です。
querySelector("li.header");
<body> <li class="header">List 1</li> <li>List 2</li> <li>List 3</li> <script> const sampleDemo = () => { let demo = document.querySelector("li.header"); //タグとクラスを取得し変数に格納 demo.innerHTML = "Text Replacement"; } sampleDemo() </script> </body>
See the Pen CSSセレクターによる要素へのアクセス by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
タグとクラスを同時に取得し、CSSセレクターを通る最初の要素を返します。
querySelectorAll()
querySelectorAll()メソッドは、CSSセレクターに適合するすべての要素を返すことを除いてはquerySelector()と完全に同じメソッドです。
下記にHTML要素があるとします。
<body> <ul> <li id="test1" class="demo">List 1</li> <li id="test2">List 2</li> <li id="test3" class="demo">List 3</li> </ul> </body>
メソッドの引数に"li"タグを渡す事により、全ての要素を取得可能です。
let elements = document.querySelectorAll("li"); // NodeList(3) [li#test1.demo, li#test2, li#test3.demo] console.log(elements); console.log(elements[0]); //<li id="test1" class="demo">List 1</li> elements[0].innerHTML = '書き換え 1' elements[1].innerHTML = '書き換え 2' elements[2].innerHTML = '書き換え 3'
See the Pen 全ての要素を取得 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
開始要素と終了要素のみを取得したい場合は下記のようにします。
カンマ繋ぎで記述して下さい。
let elements = document.querySelectorAll("#test1, #test2"); let elements = document.querySelectorAll(".demo");
下記ではより具体的にクラス属性が等しいすべてのdiv要素を取得します。
const elements = document.querySelectorAll(`div[class="box"]`);
それだけなく、targetやvalueなど他の属性で要素を取得できます。
document.querySelectorAll("[target=_sample]"); document.querySelectorAll("[value=red]");
返される値は、配列のようなオブジェクトになります、なのでこのメソッドもオブジェクトメソッドはありません。
querySelectorAll()は『 :hover 』のようなCSSセレクタの疑似クラスや『 :active 』もサポートされています。
document.querySelectorAll(':hover')
属性の部分一致によってすべてのDOM要素を取得
属性を部分的に照合してすべてのDOM要素を取得するには querySelectorAllの値が特定の文字列で始まるまたは終わる、もしくは特定の文字列を含む属性と一致するセレクタを使用してメソッドを使用します。
下記のようにクラス名を用意します。
3番目のクラス名は異なる事になります。
<div class="navigation">nav 1</div> <div class="navigation">nav 2</div> <div class="navigation-3">nav 3</div>
const elements = document.querySelectorAll(`[class$="on"]`); elements[0].innerHTML = "取得可能"; elements[1].innerHTML = "取得可能"; // elements[2].innerHTML = "取得不可";
上記では、( $="" )内に引用符で属性の値が( on )で終わるすべてのDOM要素を選択しています。
ですので3番目の属性の値の最後は( 3 )で終わっているため、これは部分一致による取得となります。
See the Pen 属性の部分一致による取得 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
では、属性の値が( nav )で始まる場合の取得では下記のようにします。
<body> <div class="navigation">nav 1</div> <div class="navigation">nav 2</div> <div class="na-vigation">nav 3</div> <script> const elements = document.querySelectorAll(`[class^="nav"]`); elements[0].innerHTML = "取得可能"; elements[1].innerHTML = "取得可能"; // elements[2].innerHTML = "取得不可"; </script> </body>
( ^ )正規表現で使用した場合と同じ意味を持つキャレット記号については、CSSでも扱われるのでご存知かもしれません。
属性の値が最初で始まる文字で指定し、取得する際はこのキャレット記号を使用します。
See the Pen 属性の値の始めの文字列を取得 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
querySelectorAll()メソッドから返される NodeList オブジェクトはLive(動的)ではなく、非Liveまたは静的 (static)である必要性があります。
返されるのは配列のように見えますが、実際は異なります。
つまり、非LiveはDOMの変更がコレクションに影響を与えないことを意味します、なのでUIの更新をしても変更される事はありません。
逆にLive(動的)はオブジェクトの属性とメソッドが、実際の基になるデータを操作する必要があり、DOMの変更がコレクションに反映されるコレクションとなります。
この非Live(静的)なNodeListオブジェクトはメソッドを実装しforEach()やWhite()を使用できます。
これにより、オブジェクトをループしてメソッドによって返される各要素を処理できます。
前述で解説しました、getElementsByClassName()やgetElementsByTagName()メソッドが返す値はLive(動的)なオブジェクトのHTMLコレクションなので、ループを使用する際はquerySelectorAll()で無限ループを回避できます。
このLiveコレクションと非Liveコレクションについてですが、JavaScriptライブコレクションはめったに話されない話題の1つでもあります。
ほとんどの方々が何が起こっているのかを理解していません。
詳しく解説したいのですが、どうしても長くなってしまいます、また別途まとめて記事に致します。
このLiveと非Liveを理解していない場合、様々な問題が発生する恐れがあるのでしっかりと学習下さい。
スタイルの変更
JavaScriptには要素にさまざまなスタイルを設定できるプロパティがあります。
要素にインラインスタイルを追加する為に、読み取り専用の『style』プロパティを使用します。
これは値が設定されているかどうかを確認します。
要素のスタイルにプロパティが含まれていない場合は、空の文字列が返されます。
console.log(box.style.backgroundColor)
直接文字列を代入するとインラインスタイルとして追加できます。
スタイルの宣言は『null』または空(" ")文字列を設定するとリセットが可能です。
下記では要素を取得し、文字の色と背景の色を変えます。
<div> <p id="demo">sample text</p> </div>
const demo = document.getElementById("demo"); demo.style.color = "red"; //または const div = document.getElementsByTagName("div") div[0].style.backgroundColor = "black";
CSSプロパティは、通常のCSSプロパティ名ではなく、キャメルケースで記述する必要があります。
See the Pen スタイルの変更・文字の色 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
代入演算子( = )ではなく、メソッドを使用して対象のプロパティを指定し更新できます。
setProperty()メソッドを使用します。
これは2つの引数をとります。
box.style.setProperty('background-color', 'red'); console.log(box.style.backgroundColor) // red
1つ目の引数は対象のプロパティ名の指定です。
2つの目の引数は( 値 )valueなのでプロパティの値となります。
プロパティ名に( !important )を指定すれば、スタイルが最優先されます。
複数単語のプロパティ名はハイフンでつながれており、こちらではキャメルケースではないことにも注意してください。
See the Pen スタイルの更新setProperty()メソッド by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
追加したスタイルを削除
要素のインラインスタイルからCSSプロパティを削除する必要がある場合は removeProperty()オブジェクトのメソッドを呼び出してあげます。
const box = document.getElementById('box'); box.style.backgroundColor = "red" alert(box.style.backgroundColor) //red box.style.removeProperty('background-color'); //削除
See the Pen CSSプロパティを削除removeProperty() by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
要素の追加と削除
新しい要素を追加したり、既存の要素を削除したりする方法となります。
要素の追加
新しく要素を追加するには、createElement()メソッドを使用します。
const div = document.createElement("div");
上記ではdiv要素を作成しています。
タグを引数として受け取り、変数に割り当ててます。
これをコンテンツを追加し、DOMドキュメントに挿入する必要があります。
下記のように追加します。
const div = document.createElement("div"); div.innerHTML = '<p>CreateElement example</p>'; document.body.appendChild(div);
divをドキュメントに挿入するには、appendChild()メソッドを使用します。
このメソッドは、新しいノードを挿入したり、既存のノードを特定の親ノードの最後の子として再配置したりするために使用されます。
divタグを作成しテキストを追加してから、その後に本文に追加しています。
appendChild()は、ノードの1つの引数のみを受け入れます。
See the Pen 新しく要素を追加 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
またdivにidやクラスを追加した後に新しいノードとして挿入したりします。
const div = document.createElement("div"); div.id = "content"; // id追加 div.className = 'foo'; //クラスを追加 div.innerHTML = '<p>CreateElement example</p>'; document.body.appendChild(div);
classNameプロパティに新しく値を設定することで、その要素のクラス属性を変更することができ、クラス属性が変更された場合は、ブラウザはそれに合わせてレンダリングし再描画します。
要素の削除
要素を削除するには、Element.remove()メソッドを使用します。
remove()
このremove()メソッドは要素をDOMから削除します。
<body> <p id="element1">paragraph</p> <p id="element2">paragraph</p> </body>
idの値、element2を取得していきます。
const element2 = document.getElementById('element2'); element2.textContent = "Hello!!" console.log(element2) //Hello!! element2.remove()//削除 console.log(element2) //空
上記では、element2を取得してからtextContentプロパティで要素をHello!!に書き換えてから、remove()メソッドで要素を削除しています。
要素の最後を削除したい場合はremoveChild()メソッドを使用して削除します。
removeChild();
<body> <ul id="element"> <li>List 1</li> <li>List 2</li> <li>List 3</li> </ul> <script> let element = document.getElementById('element'); element.removeChild(element.lastElementChild); </script> </body>
removeChild()で最後のリストアイテムを削除します。
.lastElementChildプロパティでは、最後の子要素を返します。
See the Pen 要素の削除 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
要素のすべての子ノードを削除するには、whileループ関数でfirstChildプロパティとremoveChild()メソッドを使用します。
下記ではidの値が『btn』であるボタンをクリックすると関数が実行されます。
let btn = document.getElementById('btn'); btn.onclick = () => { let element = document.getElementById('root'); while(element.firstChild) { element.removeChild(element.lastChild); } }
See the Pen 要素の子ノード全てを削除 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
White文を使用すれば、子ノードがなくなるまで、子ノードを繰り返し削除できます。
またはinnerHTMLプロパティを使用して、全ての子ノードを削除できます。
<body> <div id="element"> <p>paragraph</p> </div> <button id="btn" onclick="removeChildElement()"> <script> function removeChildElement(){ document.getElementById("element").innerHTML = ''; } </script> </body>
textContentプロパティでも同様に空を渡す事によって削除できます。
function removeChildElement(){ document.getElementById("element").textContent = ''; }
全ての子ノードを削除する最も簡単な手順はinnerHTMLとtextContentプロパティによる削除です。
初心者がメソッドを使用する際の注意点
まずは下記の間違いの確認をお願いします。
getElementByTagName()
getElementByClassName
初心者様の開発者の多くは( s )の付け忘れが多くいらっしゃいます。
getElementsByTagName()
getElementsByClassName
これは『getElementById』が( s )が含まれない為、間違える方がいらっしゃいます。
getElementById()は単一の要素を返すので( s )は含まれません。
一方でgetElementsByClassName()などは、要素のコレクションを返すので( s )が含まれます。
付け忘れますと機能しなくなるので、タイピングミスには十分に注意して下さい。
要素を取得する際によくあるミスが、下記になります。
let li = document.getElementsByTagName('li').innerHTML = 1;
これはsではなさそうです。
前述したように、上記のメソッドは要素のコレクションを返します、この場合では要素ではなく値を割り当てているために機能しなくなっています。
しっかりと機能させるには、コレクションをループ処理させる、またはインデックスで要素を取得してから割り当てて下さい。
document.getElementsByTagName('li')[0].innerHTML = 1;
HTMLのDOM要素にアクセスし、JavaScriptを介してそれらをインタラクティブにすることは、フロントエンド開発者の作業の最も基本的でありながら不可欠な部分でもあります。
ここでは、DOM要素にアクセスするためにJavaScriptで使用される最も一般的なメソッドを初学者様向けに紹介致しました。
これで、あなたはもうDOMを介してJavaScriptを使用してドキュメント内のHTML要素にアクセスできるようになりました。
本日は以上となります。
最後までこの記事を読んで頂きありがとうございます。