## 0. はじめに
### 0-1. 経緯
6冊目ぐらいのJavaScript入門書。全部合わせて4回目ぐらいの挑戦。if文、for文、関数などが終わったあと、「DOM」「オブジェクト」「プロパティ」「メソッド」「ノード」みたいな言葉が出てくるあたりで、例外なく辞めてきました。
日本語につまずくというか、「今まで使ってきた関数は実はメソッドだった!つまり、グローバルオブジェクトであるウィンドウオブジェクトのプロパティの関数=ほら、それってオブジェクトのメソッドだ!」とか「これはブラウザオブジェクトとしてのDocumentオブジェクトだが、DOMのDOMオブジェクトでDocumentオブジェクトを…」みたいな話が出てくるたびに、小さな「?」が積み重なって、言葉と言葉の関係性がごちゃごちゃになってゆき、最終的には「DOM=DOMオブジェクト=Documentオブジェクト=ドキュメントツリーからのタグ=要素=ノード=文書=テキスト」みたいな錯乱状態に陥るパターンです。
今回も危なかったのですが、いろんな入門サイトや記事を読み比べながら、なんとかDOMの入門部分を最後まで読み進めることができましたので、頭の整理と備忘録をかねて、まとめることにしました。間違っていたらすみませんm(__)m
### 0-2. DOMまわりの、ざっくりとした全体像
- ブラウザの画面は、大枠のウィンドウ、アドレスバー、進む戻るボタン、ページの表示領域など、さまざまなパーツで構成されているが、多くはJavaScriptを通して操作できるようになっている。
- そして、JavaScriptで操作できるブラウザ画面のパーツには、それぞれ、メソッドやプロパティを持ったオブジェクトが用意されていて、ウィンドウ部分はWindowオブジェクト、アドレスバー部分はLocationオブジェクト、進む戻るボタンはHistoryオブジェクト、ページの表示領域はDocumentオブジェクトのように対応している。
- こういった、"ブラウザを操作するために用意されたオブジェクト"を「ブラウザオブジェクト」と呼ぶ。
- ブラウザオブジェクトは階層型になっていて、Windowオブジェクトを頂点として、直下にDocumentオブジェクト、Locationオブジェクト、Historyオブジェクト、Screenオブジェクト、Navigatorオブジェクトがある。さらにその下もある。
- 各オブジェクトへのアクセスは、それぞれのオブジェクトが持っている、"自分自身のオブジェクトへアクセスするためのプロパティ(小文字のオブジェクト名)"を利用する。
- たとえば、Windowオブジェクトのメソッドが使いたければ、"window.メソッド名"のように、Windowオブジェクトが持っているwindowプロパティを使って、まずWindowオブジェクトにアクセスしてから、メソッドを呼び出す。
- Windowオブジェクトを第一階層とすると、第二階層以下のオブジェクトへのアクセスは"window.document.〜"や、"window.location.〜"のように、Windowオブジェクトから数珠つなぎにしてアクセスできる。
- ただ、先頭に書いたWindowオブジェクトへのアクセス部分、"window."は省略できるので、"window.location.href"を"location.href"と書いても同じ意味になり、通例では"window."を省略した形で書かれる。逆に、Windowオブジェクトのメソッドを呼び出すときは、"alert()"ではなく、"window.alert()"のように、"window."を省略せずに書くのが通例。
- ブラウザオブジェクトは、標準の規格がなく、各メーカーが独自に実装したため、ブラウザごとの仕様の違いが原因で、互換性の問題が多発した。
- この互換性の問題を解決するため、"HTMLドキュメントに対応する「Documentオブジェクト」を扱うための標準仕様"として、DOMが登場した。
- このDOMの仕様を勧告したのが、Web技術の標準化をおこなう「W3C」という団体。
- JavaScriptやJqueryを勉強する中で頻出する「Domオブジェクト」なるものは、Documentオブジェクトを扱うため、DOMの仕様に基づいて、Documentオブジェクト配下に生成されたオブジェクト(群)のこと。
- 現在、各メーカーがDOMをサポートして、このDOMオブジェクトを利用できるようになったため、ほぼ標準化した。ただ、メーカーが独自に実装した、Documentオブジェクトを扱うためのオブジェクト(ブラウザオブジェクト)も依然として残っている。
- また、DOMのような標準仕様はないものの、Documentオブジェクト以外のブラウザオブジェクト(Windowオブジェクト、Locationオブジェクト、Historyオブジェクトなど)についても、過去の反省から共通化が進み、互換性の問題はなくなりつつある。
- HTMLドキュメントがブラウザに読み込まれると、前述の、「各メーカーが独自に実装したDocumentオブジェクトを含むブラウザオブジェクト(互換性の問題はなくなりつつある)」、「DOMの仕様に沿ってDocumentオブジェクト配下にDOMオブジェクト」、そして、「プログラムの基本的な処理ができる『ビルトインオブジェクト』」が自動的に生成される。
- ビルトインオブジェクトは、JavaScriptの核となるオブジェクトで、文字列を扱うためのStringオブジェクト、配列を扱うためのArrayオブジェクトなどが、このオブジェクトに含まれ、プログラムの基本的な処理をするメソッドやプロパティを持っている。
- こういったオブジェクトを使うことによって、さまざまな操作が可能になる。
### 0-3. もう少し深堀り
#### 0-3-1. DOM
DOMは「Document Object Model(ドキュメント オブジェクト モデル)」の略で、Web技術の標準化をおこなうW3Cという団体が勧告している「プログラムでHTMLを扱うための仕様」で定義されている。
HTMLドキュメントが、DOMをサポートしているブラウザ(すべての主要ブラウザはサポート済み)に読み込まれると、このDOMの仕様に基づいて、HTMLドキュメントに含まれるタグ、属性や値、テキストなどの部品1つひとつが、プログラムで利用できるもの「DOMオブジェクト」として自動的に生成される。
そして生成されたDOMオブジェクトは、HTMLドキュメントに書かれているタグの親子関係、兄弟関係に基づいて、「ドキュメントツリー」と呼ばれる"ツリー型のデータ構造の中でリンク(参照)"される。
このプロセスの結果として、読み込まれたページのDOMが構築され、各DOMオブジェクトが持っているメソッドやプロパティを使ってHTMLドキュメントを操作できるようになる。
#### 0-3-2. HTMLドキュメントを構成する部品「Node(ノード)」
HTMLドキュメントがブラウザに読み込まれたときに、自動的に生成されるドキュメントツリー上で、枝分かれしている1つひとつのDOMオブジェクトのことを「ノード」と呼ぶ。ノードは全部で12種類あり、HTMLドキュメントを構成する「タグ」「属性と値」「文書」は、それぞれ「要素ノード」「属性ノード」「テキストノード」と呼ばれ、これにツリーの頂点に存在するHTMLドキュメント全体を管理するための機能がまとめられた「ドキュメントノード」を合わせた4種類のノードをよく使う。
#### 0-3-3. DOMの仕様で定められた、特定の機能を持つプログラム部品「インターフェース」
DOMの仕様では「〜に関するインターフェース」、「〜に関するインターフェース」、といった具合に、DOMオブジェクトを扱うために必要な様々な機能が定義されている。
ただ、DOMの仕様はJavaScriptで扱うことだけを対象としていないため、JavaScriptで書かれているわけではない。DOMの仕様では定数やメソッドの骨格部分(メソッド名、戻り値、パラメーター)だけが定義されていて、具体的な処理内容は各ブラウザが用意している。それでも、仕様にそって用意(インターフェースの実装という)されているので、DOMオブジェクトのメソッドやプロパティを指定すれば目的の結果が得られる。こういった中身がからっぽ(骨格部分だけが定義されている)のオブジェクトのことを「インターフェース」と呼ぶ。よく耳にする「API」も「Application Program Interface」の略でインターフェースのことを指す。
## 1. 特定のノードを取得する方法
### 1-1. getElementById()メソッド-id名を指定して要素ノード(タグ要素)を取得!
#### 1-1-1. メソッドの基本
書き方 | document.getElementById("id名") |
---|---|
戻り値 | 指定したid名の要素ノード。該当する要素ノードがない場合はnullが返る。 |
例)id="hoge"の要素ノードを取得する場合
var elm = document.getElementById("hoge");
console.log(elm);
### 1-2. getElementsByTagName()メソッド-タグ名を指定して要素ノード(タグ要素)を取得!
#### 1-2-1. メソッドの基本
書き方 | document.getElementsByTagName("タグ名") |
---|---|
戻り値 | 指定した要素ノードのNodeListオブジェクト(配列もどき)。該当する要素ノードがない場合はカラのNodeListオブジェクトが返る。 |
例)span要素ノードを取得する場合
var elm = document.getElementsByTagName("span");
console.log(elm);
#### 1-2-2. 戻り値であるNodeListオブジェクトについて
##### 配列もどきのNodeListオブジェクト
戻り値のNodeListオブジェクトは配列と同じようにインデックスを指定することで対象のノードを取り出せる配列型のオブジェクト。ただ、Arrayオブジェクトを継承していないため、Arrayオブジェクトのメソッドが使えず、itemメソッドとlengthプロパティの2つしか持っていない。DOMの仕様で定義されているインターフェースの1つ。
##### NodeListオブジェクトが持つプロパティとメソッド
###### 該当するノードの数を調べるlengthプロパティ
書き方 | NodeList.length |
---|---|
戻り値 | NodeListオブジェクトに含まれるノードの数。 |
例)取得したspan要素ノードの数を取得する場合
var elm = document.getElementsByTagName("span");
console.log(elm.length);
###### NodeListの中から特定のノードを取り出すitemメソッド
書き方① | NodeList.item(i) |
---|---|
書き方② | NodeList[i] |
戻り値 | NodeListオブジェクトに含まれるi番目のノード。iが範囲外ならnullが返る。 |
例)取得したspan要素ノードの中から、1つめを取得する場合
var elm = document.getElementsByTagName("span");
console.log(elm.item(0));//書き方①
console.log(elm[0]);//書き方②
##### 該当するノードの有無で条件分岐したいときは、NodeListオブジェクトのlengthプロパティを使う
該当するノードがない場合でも、戻り値としてカラのNodeListオブジェクトが返る(nullではないため)ため、"if(NodeListオブジェクト)"といったかたちで、該当するノードの有無を判別できない。該当するノードの有無で処理をわけたいときはlengthプロパティを使う。(if文において0==falseになるから)
例)span要素ノードがあるときに処理を加えたい場合
var elm = document.getElementsByTagName("span");
// span要素ノードがないときはfalse(0==false)になるので、該当する要素ノードの有無で処理をわけたいときはlengthプロパティを使う
if(elm.length) {
// 処理
}
// これだとspan要素ノードがなくてもnullではないため(カラのオブジェクトが存在するため)、常にtrueになってしまう
if(elm){
// 処理
}
##### NodeListオブジェクトとHTMLドキュメントは連動している
NodeListオブジェクトを取得後にHTMLドキュメントを変更した場合、連動して中身が変わる。1-7-2 で出てくるNodeListオブジェクトは連動しないので注意。
例)
<!-- html -->
<div>1つ目のdiv要素ノードです。</div>
<div>2つ目のdiv要素ノードです。</div>
<div>3つ目のdiv要素ノードです。</div>
<!-- script -->
var elm = document.getElementsByTagName("div");
console.log(elm);
// elm[0]:<div>1つ目のdiv要素ノードです。</div>
// elm[1]:<div>2つ目のdiv要素ノードです。</div>
// elm[2]:<div>3つ目のdiv要素ノードです。</div>
//-----------------------//
// 2つ目のdiv要素ノードを削除する処理 //
//-----------------------//
console.log(elm);//もう一度確認するとNodeListオブジェクトが入っている変数elmの中身もHTMLに合わせて変わっている
// elm[0]:<div>1つ目のdiv要素ノードです。</div>
// elm[1]:<div>3つ目のdiv要素ノードです。</div>
#### 1-2-3. 取得した全てのノードに処理をする
取得したすべての要素に処理をしたい場合は、for文を使ってループ処理をする。
例)すべてのp要素ノードを取得、コンソールに表示する場合
var elm = document.getElementsByTagName("p");
for(var i = 0; i < elm.length; i++ ) {
console.log(elm.item(i));
}
### 1-3. getElementsByClassName()メソッド-クラス名を指定して要素ノード(タグ要素)を取得!
#### 1-3-1. メソッドの基本
書き方 | document.getElementsByClassName("対象クラス名") |
---|---|
戻り値 | 指定したクラス名を持つ要素ノードのNodeListオブジェクト(配列もどき)。該当する要素ノードがない場合はカラのNodeListオブジェクトが返る。 |
例)class="hoge"の要素を取得する場合
var elm = document.getElementsByClassName("hoge");
console.log(elm);
#### 1-3-2. 戻り値はNodeListオブジェクト
1-2-2を参照。
#### 1-3-3. 取得した全てのノードに処理をする
1-2-3を参照。
#### 1-3-4. クラス名を複数指定できる
半角スペースを挟んで、複数のクラス名を指定することで、指定したクラスすべてを持つ要素ノードを取得できる。クラス名の順番は無視される。
例)class="hoge fuga piyo"の要素ノードを取得する場合
var elm = document.getElementsByClassName("hoge fuga piyo");
console.log(elm);
### 1-4a. childNodesプロパティ-ツリーをたどって子ノードを取得!
1-4b記載のchildrenプロパティと同じく「子ノードのまとまり」を取得するプロパティ。
HTML内で使っているスペースや改行、タブなどもノードとして取得するので注意。また、スペースや改行などのノードはホワイトノードと呼ばれている。ブラウザの種類やバージョンにもよるが、Chrome、Firefoxはホワイトノードを取得する。
#### 1-4a-1. プロパティの基本
書き方 | 親.childNodes |
---|---|
戻り値 | 該当する子ノードのNodeListオブジェクト(配列もどき)。該当するノードがない場合はカラのNodeListオブジェクトが返る。 |
例)id="oyayouso"の要素ノードの、子ノードを取得する場合
var elm = document.getElementsById("oyayouso");
console.log(elm.childNodes);
#### 1-4a-2. 戻り値はNodeListオブジェクト
1-2-2を参照。
#### 1-4a-3. 取得した全てのノードに処理をする
1-2-3を参照。
#### 1-4a-4. NodeインターフェースのnodeTypeプロパティを使って、スペースや改行などのホワイトノードを省く
##### NodeインターフェースとnodeTypeプロパティについて
すべてのDOMオブジェクトが共通して利用できる基本的な機能を定めたインターフェース。
###### Nodeインターフェースで利用可能なプロパティ
| プロパティ名 | 説明 |
|---|---|---|
| nodeType | ノードの種類を取得する。取得したノードは要素ノードなのか、属性ノードなのか、テキストノードなのかといった判別に使う。 |
| nodeName | ノード名を取得する。要素ノードであればタグ名、テキストノードであれば"#text"といったかたちで取得できる。 |
| nodeValue | ノードの値を取得•設定する。属性ノードやテキストノードなどに使える。属性ノードであれば属性の値、テキストノードであれば、テキストが取得•設定できる。要素ノードに使うとnullが返るので、innerHTML()みたいな使い方はできない。 |
| parentNode | 親の要素ノードを取得する。1-5参照。 |
| childNodes | ノードリストに含まれるすべての子ノードを取得する。1-4a参照。 |
| firstChild | ノードリストの最初の子ノードを取得する。1-4c参照。 |
| lastChild | ノードリストの最後の子ノードを取得する。1-4c参照。 |
| previousSibling | 隣接する、直前の兄ノードを取得する。1-6参照。 |
| nextSibling | 隣接する、直後の弟ノードを取得する。1-6参照。 |
| attributes | 属性をまとめて取得する。2-3参照。 |
| textContent | 対象ノードやすべての子ノードのテキスト内容を取得したり設定する。3-3-2参照。 |
###### nodeTypeプロパティの概要と使い方
ノードの種類を判定するためのプロパティ。
書き方 | 対象.nodeType |
---|
戻り値(number) | ノードの種類 |
---|---|
1 | 要素ノード |
2 | 属性ノード |
3 | テキストノード |
すべてのノードの種類(12種類)ある | 各番号に対応したノード |
例)childNodesプロパティとnodeTypeプロパティを使い、id="oyayouso"の要素ノードの、子の要素ノードだけを処理する場合
var koyousotachi = document.getElementsByID("hoge").childNodes;
for(var i = 0; i < koyousotachi; i++){
var koyouso = koyousotachi.item(i);
//要素ノードかどうかの判定
if(koyouso.nodeType == 1){
console.log(koyouso);
}
}
### 1-4b. childrenプロパティ-ツリーをたどって子ノードを取得!
1-4a記載のchildNodesプロパティと同じく「子ノードのまとまり」を取得するプロパティ。
テキストや改行は無視して要素ノードのみを取得する。
#### 1-4b-1. プロパティの基本
書き方 | 親.children |
---|---|
戻り値 | 該当する子ノードのHTMLCollectionオブジェクト(配列もどき)。該当するノードがない場合はカラのHTMLCollectionオブジェクトが返る。 |
例)id="oyayouso"の要素ノードの、子の要素ノードを取得する場合
var elm = document.getElementsById("oyayouso");
console.log(elm.children);
#### 1-4b-2. 戻り値であるHTMLCollectionオブジェクトの概要
1-2-2のNodeListオブジェクトの関する項目を参照。
テキストや改行は無視して、要素ノードのみを取得することと、メソッドが
NodeListオブジェクトより1つ多いだけで、利用の目的や方法は同じ。
また、JavaScriptの新しい仕様で両者は配列を継承したElementsに一本化されるので、初心者のうちは深く考えなくてよい。
#### 1-4b-3. 取得した全ての要素ノードに処理をする
1-2-3を参照。
### 1-4c. firstChild/lastChildプロパティ-ツリーをたどって最初/最後の子ノードを取得!
ドキュメントツリー上にある、最初の子ノードや、最後の子ノードを取得するときに使う。
HTML内で使っているスペースや改行、タブなどもノードとして取得するので注意。また、スペースや改行などのノードはホワイトノードと呼ばれている。ブラウザの種類やバージョンにもよるが、Chrome、Firefoxはホワイトノードを取得する。
#### 1-4c-1. プロパティの基本
##### 最初の子ノードを取得したいときはfirstChild
書き方 | 親.firstChild |
---|---|
戻り値 | 最初の子ノード。該当するノードがない(子ノードが1つも存在しない場合)はnullが返る。 |
##### 最後の子ノードを取得したいときはlastChild |
書き方 | 親.lastChild |
---|---|
戻り値 | 最後の子ノード。該当するノードがない(子ノードが1つも存在しない場合)はnullが返る。 |
例)id="oyayouso"の要素ノードの最初の子ノードと最後の子ノードを取得したい場合
var elm = document.getElementsById("oyayouso");
console.log(elm.firstChild);
console.log(elm.lastChild);
#### 1-4c-2. NodeインターフェースのnodeTypeプロパティを使って、スペースや改行などのホワイトノードを省く
1-4a-4を参照。
### 1-5. parentNodeプロパティ-ツリーをたどって親の要素ノード(タグ要素)を取得!
ドキュメントツリー上にある、親の要素ノードを取得するプロパティ。
#### 1-5-1. プロパティの基本
書き方 | 子.parentNode |
---|---|
戻り値 | 該当する親の要素ノード。該当するノードが取得できない場合はnullが返る。 |
例)id="koyouso"の要素ノードの、親の要素ノードを取得したい場合
var elm = document.getElementsById("koyouso");
console.log(elm.parentNode);
### 1-6. previousSibling/nextSiblingプロパティ-ツリーをたどって兄弟ノードを取得!
ドキュメントツリー上にある、隣接する兄弟ノードを取得するときに使う。
HTML内で使っているスペースや改行、タブなどもノードとして取得するので注意。また、スペースや改行などのノードはホワイトノードと呼ばれている。ブラウザの種類やバージョンにもよるが、Chrome、Firefoxはホワイトノードを取得する。
#### 1-6-1. プロパティの基本
##### 直前の兄ノードを取得したいときはpreviousSibling
書き方 | Node.previousSibling |
---|---|
戻り値 | 直前の兄ノード。該当するノードがない(隣が存在しない場合や、自身が最先頭に位置している場合)はnullが返る。 |
##### 直後の弟ノードを取得したいときはnextSibling
書き方 | Node.nextSibling |
---|---|
戻り値 | 直後の弟ノード。該当するノードがない(隣が存在しない場合や、自身が最後尾に位置している場合)はnullが返る。 |
例)id="jibun"の要素ノードの、兄弟ノードを取得したい場合
var elm = document.getElementsById("jibun");
console.log(elm.previousSibling);
console.log(elm.nextSibling);
#### 1-6-2. NodeインターフェースのnodeTypeプロパティを使って、スペースや改行などのホワイトノードを省く
1-4a-4を参照。
### 1-7. querySelector()/querySelectorAll()メソッド-jQueryっぽい!CSSセレクタを使って要素ノード(タグ要素)を取得!
CSSセレクタで取得したい要素ノードを指定できるメソッド。
#### 1-7-1. メソッドの基本
##### 1つだけ取得したいときはquerySelector()
id名、クラス名、どちらも指定できるが、指定された要素ノードを1つ見つけるとそこで検索処理が終了するので、クラス名を指定して該当する要素ノードを複数取得したい場合は使えない。
書き方 | document.querySelector("CSSセレクタ") |
---|---|
戻り値 | 指定したCSSセレクタに1番最初に該当した要素ノード。該当する要素ノードがない場合はnullが返る。 |
例)id="hoge"の要素ノードを取得する場合
var elm = document.querySelector("#hoge");
console.log(elm);
##### まとめて取得したいときはquerySelectorAll()
id名、クラス名、どちらも指定でき、指定された要素ノードのまとまりを取得できる。
書き方 | document.querySelectorAll("CSSセレクタ") |
---|---|
戻り値 | 指定したCSSセレクタに該当するノードのNodeListオブジェクト(配列もどき)。該当する要素ノードがない場合はカラのNodeListオブジェクトが返る。 |
例)class="hoge"の要素ノードを取得する場合
var elm = document.querySelectorAll(".hoge");
console.log(elm);
#### 1-7-2. querySelectorAll()メソッドの戻り値であるNodeListオブジェクトについて
基本的に1-2-2を参照。
ただ、1-2-2で出たNodeListオブジェクトと違い、HTMLドキュメントの構造が変化しても、その変化がNodeListオブジェクトに反映されないという特徴がある。この"HTMLドキュメントの変化が反映されないNodeListオブジェクト"のことを「Static NodeList」と呼ぶ。また、1-2-2で出たNodeListオブジェクトのように"HTMLドキュメントの変化が反映されるNodeListオブジェクト"のことを「Live NodeList」と呼ぶ。
今のところ、この2種類のNodeListオブジェクトが存在する理由や、必要性、使いどころなどは、まったくわかっていない(初心者のため)。
##### Static NodeListオブジェクトはHTMLドキュメントと連動しない
例)
<!-- html -->
<div>1つ目のdiv要素ノードです。</div>
<div>2つ目のdiv要素ノードです。</div>
<div>3つ目のdiv要素ノードです。</div>
<!-- script -->
var elm = document.querySelectorAll("div");
console.log(elm);
// elm[0]:<div>1つ目のdiv要素ノードです。</div>
// elm[1]:<div>2つ目のdiv要素ノードです。</div>
// elm[2]:<div>3つ目のdiv要素ノードです。</div>
//-----------------------//
// 2つ目のdiv要素ノードを削除する処理 //
//-----------------------//
console.log(elm);//HTMLドキュメントからはなくなったが、NodeListオブジェクトに変化なし
// elm[0]:<div>1つ目のdiv要素ノードです。</div>
// elm[1]:<div>2つ目のdiv要素ノードです。</div>
// elm[2]:<div>3つ目のdiv要素ノードです。</div>
#### 1-7-3. querySelector()/querySelectorAll()メソッドは複雑な検索にもってこい
これらのメソッドを使えばCSSセレクタの記法で指定できるので、とても便利だが、処理速度がgetElementById()やgetElementsByClassName()に比べて遅いという問題がある。
例)id名検索はgetElementById()メソッドを使った方が早い。
var elm = document.querySelectorAll("#hoge");//これより
var elm = document.getElementById("hoge");//これの方が早い
例)単発のクラス名検索の場合もgetElementsByClassName()メソッドを使った方が早い。
var elm = document.querySelectorAll(".hoge");//これより
var elm = document.getElementsByClassName("hoge");//これの方が早い
ただ、querySelector()/querySelectorAll()は、対象セレクタが流動的だったり、隣接セレクタなどによるコンビネーションセレクタでの複雑な検索の場合に、とても力を発揮する。
例)対象セレクタが流動的だったり、複雑な場合にとても便利。
var elm = document.querySelectorAll("div.hoge > div > p.fuga+div > *");//こんなときはめちゃめちゃ便利!!
console.log(elm);
## 2. 要素ノード(タグ要素)の属性を取得•設定する方法
### 2-1. DOMオブジェクトのプロパティ名を指定して属性値を取得•設定!
要素ノードのDOMオブジェクト(ノードの種類がテキストノードでもドキュメントノードでもなく、"要素ノード"のDOMオブジェクト)に用意されている、属性と同じ名前のプロパティを使って、要素ノードの属性値を取得•設定できる。
たとえば、div要素ノードのDOMオブジェクトには、"id属性値を取得する「idプロパティ」"が用意されている。
同じように、img要素ノードのDOMオブジェクトには、idプロパティはもちろんのこと、"src属性値を取得•設定する「srcプロパティ」"が用意されているし、input要素ノードのDOMオブジェクトには、"value属性値を取得•設定する「valueプロパティ」"や、"type属性値を取得•設定する「typeプロパティ」"が用意されている。
このように、img、div、form、input...など、すべての要素ノードのDOMオブジェクトには、それぞれが持ちうる属性にアクセスするための、属性と同名のプロパティが用意されている。
ただ、プログラム言語で「class」は別の意味で使われているので、class属性値を取得•設定するプロパティは、"class"ではなくて"className"、といった例外もあるで注意する。
#### 2-1-1. プロパティ名を指定して属性値を取得
例)すべてのa要素ノードのhref属性の値を取得する場合
var elm = document.getElementsByTagName("a");
for(var i = 0; i < elm.length; i++ ) {
console.log(elm.item(i).href);
}
#### 2-1-2. プロパティ名を指定して属性値を設定
例)idが"mylink"の要素ノードにclass属性の値"blockLink"を設定する場合
var elm = document.getElementById("mylink");
elm.className = 'blockLink';
console.log(elm);
### 2-2. getAttribute()/setAttribute()/removeAttribute()/hasAttribute() メソッド-属性名を指定(引数に直書き)して属性値を取得•設定!
#### 2-2-1. メソッドの基本
Elementインターフェース(要素ノードのみに使える)によって実装されたgetAttribute()/setAttribute()/removeAttribute()/hasAttribute()メソッドを使って、属性(値)の取得•設定ができる。
##### 属性値を取得したいときは getAttribute()メソッド
指定した属性の属性値を取得する。該当する属性がない場合、DOM仕様では「空文字列」が返るのが正解だが、現状、多くのブラウザでnullが返るため、要素に指定の属性が存在しない可能性があるなら、後述のhasAttribute()も合わせて使って、getAttribute() を呼ぶ前に属性の有無をチェックした方が良い。
書き方 | element.getAttribute(属性名) |
---|---|
戻り値 | 該当する属性がない場合は、空文字列(ブラウザによってはnull)が返る。 |
例)すべてのa要素ノードのhref属性の値を取得する場合
var elm = document.getElementsByTagName("a");
for(var i = 0; i < elm.length; i++ ) {
console.log(elm[i].getAttribute('href'));
}
##### 属性の追加や、属性値を変更したいときは setAttribute()メソッド
要素ノードに、指定した属性名や属性値を追加する。
同名の属性がある場合は上書される。
書き方 | element.setAttribute(属性名,値) |
---|---|
戻り値 | なし。 |
例)すべてのa要素ノードのclass属性に「link(数字)」という属性値を設定して、その属性値を取得する場合
var elm = document.getElementsByTagName("a");
for(var i = 0; i < elm.length; i++ ) {
elm[i].setAttribute('class','link' + i); console.log(elm[i].getAttribute('class'));
}
##### 属性を削除したいときは removeAttribute()メソッド
要素ノードから、指定した属性を削除する。指定した属性がない場合は、何も起きない。
書き方 | element.removeAttribute(属性名) |
---|---|
戻り値 | なし。 |
例)すべてのa要素ノードのclass属性を削除する場合
var elm = document.getElementsByTagName("a");
for(var i = 0; i < elm.length; i++ ) {
elm[i].removeAttribute('class');
console.log(elm[i].getAttribute('class'));
}
##### 属性の有無を調べたいときは hasAttribute()メソッド
要素ノードが、指定の属性を持っているかどうか真偽値を返す。
書き方 | element.hasAttribute(属性名) |
---|---|
戻り値 | 真偽値。true か falseが返る。 |
例)すべてのa要素ノードのtarget属性を調べて何も設定されてない場合のみ、「_black」を設定する場合
<a target="_blank" href="1.html">1</a>
<a target="_parent" href="2.html">2</a>
<a target="_parent" href="3.html">3</a>
<a href="4.html">4</a>//ここに設定される
<a href="5.html">5</a>//ここに設定される
var elm = document.getElementsByTagName("a");
for(var i = 0; i < elm.length; i++ ) {
if(!elm[i].hasAttribute('target')){
elm[i].setAttribute('target','_blank');
}
console.log(elm[i].getAttribute('target'));
}
### 2-3. attributesプロパティ-要素ノード(タグ要素)に設定されている属性名と属性値をまとめて取得!
要素ノードに設定されている属性を、まとめて取得したい場合に、attributesプロパティを使うと便利。attributesプロパティは、Nodeインターフェースによって実装されているので(1-4a-4参照)、すべてのノードで、attributesプロパティを指定できるが、実際に有効な値を得られるのは要素ノード(element)のみなので注意する。なぜそんな仕様になっているのかは、まったくわかっていない(初心者のため)。また、attributesプロパティは読み取り専用。
#### 2-3-1. プロパティの基本
書き方 | Node.attributes |
---|---|
戻り値 | 指定したノード(すべてのノードで指定できるが、要素ノードしか有効な値は得られない)のNamedNodeMapオブジェクト。該当する属性がない場合はカラのNamedNodeMapオブジェクトが返る。 |
例)最初に出てくるp要素ノードの、属性をまとめて取得したい場合
var test = document.getElementsByTagName('p');
console.log(test[0].attributes);
#### 2-3-2. 戻り値であるNamedNodeMapオブジェクトの概要
attributesプロパティで得られるインデックス•属性名•属性値などを持ったAttrオブジェクト(後述)のまとまり。
attributesプロパティそのものは読み取り専用のプロパティなので、属性に変更を加えたい場合は、attributesプロパティを指定することで得られる「NamedNodeMapオブジェクト」が持っているメソッドや、「NamedNodeMapオブジェクト」に格納されている「Attrオブジェクト」、が、持っているプロパティを使う。
NamedNodeMapオブジェクトに格納されている各Attrオブジェクトには、名前やインデックスによってアクセスできる。
1-2-2で出てくるNodeListと同様、NamedNodeMapオブジェクトとHTMLドキュメントは連動している。ただ、インデックスに関して、NamedNodeMapは順番の保証が無いので、属性の取得に関しては、単にすべての項目を取り出すといった作業に限定するなどして使うのが良い。
また、NamedNodeMapには配列のような機能があるが、Arrayを継承していないのでjoin()やsplit()といったメソッドは持っていない。DOMの仕様で定義されているインターフェースの1つ。
##### まずはNamedNodeMapオブジェクトに格納されるAttrオブジェクトの概要
Nodeインターフェースを継承した、インデックス•属性名•属性値などを持ったオブジェクト。
Attrオブジェクト独自のnameプロパティやvalueプロパティを持っている。
###### 属性の名前を取得•設定したいときは nameプロパティ
書き方 | Attr.name |
---|---|
戻り値 | 属性名を取得•設定する。該当する属性名がない場合はAttrオブジェクトを指定した時点でnull、nameプロパティまで指定した場合と設定できない場合は例外が発生する。 |
###### 属性の値を取得•設定したいときは valueプロパティ
書き方 | Attr.value |
---|---|
戻り値 | 属性値を取得•設定する。該当する属性名がない場合はAttrオブジェクトを指定した時点でnull、valueプロパティまで指定した場合と設定できない場合は例外が発生する。 |
例)最初に出てくるp要素ノードの、属性をまとめて取得し、その属性値を調べる場合
※ サンプルに出てくる属性名を指定してAttrオブジェクトを取得する attributes.getNamedItem()メソッドは後述。
<p class="hogeClass">test</p>
var hoge = document.getElementsByTagName('p');
console.log(hoge[0].attributes.getNamedItem("class").name);//あたりまえだが属性名の「class」が表示される
console.log(hoge[0].attributes.getNamedItem("class").value);//hogeClassと表示
##### つづいてNamedNodeMapオブジェクトが持つプロパティとメソッド
NamedNodeMapオブジェクトは、属性を扱うための4つのメソッドと1つのプロパティを持っている。
###### NamedNodeMapオブジェクトに格納されたAttrオブジェクトの数(=属性の数)を取得したいときは NamedNodeMap.lengthプロパティ
書き方 | NamedNodeMap.length |
---|---|
戻り値 | NamedNodeMapオブジェクトに含まれるノード(Attrオブジェクト)の数。 |
例)最初に出てくるp要素ノードの、属性をまとめて取得し、その数を調べる場合
<p>test</p>
var test = document.getElementsByTagName('p');
console.log(test[0].attributes.length);
###### 属性名を指定して該当するAttrオブジェクトを取得したいときは getNamedItem()メソッド
引数に属性名を指定するので、なんとなく属性値が取得できそうなものだが、取得できるのはあくまで、「インデックス•属性名•属性値などを持ったAttrオブジェクト」なので注意。属性値を取得したければ、前述のAttrオブジェクトが持っている valueプロパティや、継承元のNodeインターフェースが持っている nodeValueプロパティ(1-4a-4を参照)を使う。
書き方 | NamedNodeMap.getNamedItem(属性名) |
---|---|
戻り値 | 該当するノード(インデックスや属性値などを持つAttrオブジェクト)。該当するノードがない場合はnullが返る。 |
例)id="hoge"のp要素ノードのNamedNodeMapオブジェクトを取得し、その中から、属性名「class」のAttrオブジェクトを取得、そのAttrオブジェクトから属性値を調べる場合
※ ややこしいが、「id="hoge"のp要素ノードのclass属性の値を調べる場合」ってこと
<p id="hoge" class="hogeClass">test</p>
var hoge = document.getElementById('hoge');
console.log(hoge.attributes.getNamedItem('class'));//この時点では、属性名「class」、属性値「hoge」、インデックス「0もしくは1(順番が保証されていないため)」などの情報を持つAttrオブジェクトが取得できている
console.log(hoge.attributes.getNamedItem('class').value);//Attrオブジェクトが持つvalueプロパティを使って、属性値を取り出せる
console.log(hoge.attributes.getNamedItem('class').nodeValue);//Attrオブジェクトの継承元のNodeオブジェクトが持つnodeValueプロパティを使っても、属性値を取り出せる
###### 属性名を指定してAttrオブジェクトを追加したいときは setNamedItem()メソッド
引数で指定された名前の属性ノード(Attrオブジェクト)を追加するメソッド。引数に渡すのは属性ノード(Attrオブジェクト)でないとだめで、文字列を渡してもエラーが発生するので注意。
書き方 | NamedNodeMap.setNamedItem(属性ノード) |
---|---|
戻り値 | 引数で指定した名前のノードが存在している場合には、ノードを置き換え、戻り値には置換え前の該当ノードが返る。その他の場合には nullが返る。 |
###### 属性名を指定して該当するAttrオブジェクトを削除したいときは removeNamedItem()メソッド
引数で指定された名前の属性ノード(Attrオブジェクト)を削除して、削除したノードを返すメソッド。
書き方 | NamedNodeMap.removeNamedItem(属性名) |
---|---|
戻り値 | 該当するノード(インデックスや属性値などを持つAttrオブジェクト)。該当するノードがない場合はnullが返る。 |
###### インデックスを指定して該当するAttrオブジェクトを取得したいとき item()メソッド
引数で指定されたインデックスに該当するノード(Attrオブジェクト)を取得するメソッド。ただ、NodeListのitemのような順番が保証されない。NodeListなどと同じように、NamedNodeMap[インデックス]のかたちで書ける。
書き方 | NamedNodeMap.item(インデックス) |
---|---|
戻り値 | 該当するノード(インデックスや属性値などを持つAttrオブジェクト)。該当するノードがない(インデックスにノードの数以上の数値を指定した)場合はnullが返る。 |
#### 2-3-3. attributesプロパティやNamedNodeMapオブジェクトを使ってimg要素に設定されたすべての属性と属性値を取得する
流れとしては、attributesプロパティを使って、id="hoge"のimg要素ノードのNamedNodeMapオブジェクトを取得し、そのNamedNodeMapオブジェクト(Attrオブジェクトのまとまり)をfor文で回して、各Attrオブジェクトの中から属性名と属性値を取得するという感じ。
例)img要素に設定されたすべての属性と属性値を取得する場合
<img id="hoge" class="hogeClass" width="100" height="50" alt="hogeイメージ">
var hoge = document.getElementById('hoge');
var attrs = hoge.attributes;
for( var i = 0; i < attrs.length; i++){
var attr = attrs.item(i);//attrs[i]でも同じ
console.log('属性名=' + attr.name + '、属性値=' + attr.value + 'の属性');//attr.nodeName、attr.nodeValueでも同じ
}
#### 2-3-4. まとめ-同じ値を得るために複数の方法があるので混乱する
まとめながら思ったのは、同じ値を得るために複数の方法があるので混乱するということ。使い分けがわからない、各オブジェクトの所属がわからないのでプロパティやメソッドがまざって(?)動かない、などなど、初心者である自分がくだける要素がもりだくさんだった。
例)同じ値を取得するためにアプローチの方法が複数ある。
<p id="hoge" class="hogeClass">アプローチの方法が複数ある</p>
var hogeV1 = document.getElementById('hoge').className;
var hogeV2 = document.getElementById('hoge').getAttribute('class');
var hogeV3 = document.getElementById('hoge').attributes.getNamedItem('class').value;
var hogeV4 = document.getElementById('hoge').attributes.getNamedItem('class').nodeValue;
console.log(hogeV1);//hogeClass
console.log(hogeV2);//hogeClass
console.log(hogeV3);//hogeClass
console.log(hogeV4);//hogeClass
サンプルのソースをしつこい言葉にすると
• hogeV1は、2-1記載の、「Elementインターフェースによって実装されたElementオブジェクト」、つまり、「要素ノード(タグ要素)」が持っている「属性と同じ名前のプロパティ」を使って取得。※classはclassNameというプロパティ名が割り当てられている。
• hogeV2は、2-2記載の、「Elementインターフェースによって実装されたElementオブジェクト」、つまり、「要素ノード(タグ要素)」が持っているメソッド「getAttribute()」を使って取得。
• hogeV3とhogeV4は、2-3記載の、「Nodeインターフェースによって実装された、すべてのDOMオブジェクトが共通して利用できる基本的な機能を持ったオブジェクト(0-3-2、1-4a-4参照)」、つまり、「全ノード(要素ノードも属性ノードもテキストノードもすべて)」が持っているプロパティ「attributes」を使って返される「NamedNodeMapオブジェクト(インデックス•属性名•属性値などを持ったAttrオブジェクトのまとまり)」を使用する方法。まずは、「attributesプロパティによって得たNamedNodeMapオブジェクト」が持っているメソッド「getNamedItem()」を使って、該当する「Attrオブジェクト」を取得、その「Attrオブジェクト」から、hogeV3の場合は「Attrオブジェクト独自が持っている属性値を取得するvalueプロパティ」、hogeV4は「Attrオブジェクトの継承元『Nodeインターフェースによって実装されたすべてのオブジェクト』が持っている属性値を取得するnodeValueプロパティ」を使って取得。
ということのようだ。
### 2-4. classList-jQueryっぽく要素ノード(タグ要素)のクラス属性を操作!
要素ノードのclass属性を扱うためのプロパティ。
jQueryでいうところのaddClass()、removeClass()、toggleClass()みたいなことができるので便利。
「Elementインターフェースによって実装されたElementオブジェクト」、つまり、「要素ノード(タグ要素)」が持っているプロパティで、読み取り専用。
タイトルからするとclassListのプロパティやメソッドを使って、要素ノードのクラス属性を操作するような感じがするが、実際はclassListそのものは読み取り専用のプロパティで、classListプロパティを指定することで得られる「class属性の文字列リストを含んだ『DOMTokenListオブジェクト』」、が、持っているメソッドやプロパティを使って要素ノードのclass属性を扱うということみたい。
ややこしいが、1-2-2で出たNodeListも、1-4b-2で出たHTMLCollectionも、2-3-2で出たNamedNodeMapもそうだが、
「『なにかのプロパティやメソッドで得られたオブジェクト』、が、持っている『プロパティやメソッド』」
を使って、本来自分が欲しかった情報を取得したり、設定したりすることが、結構あるらしい。
#### 2-4-1. プロパティの基本
書き方 | Element.classList |
---|---|
戻り値 | 指定した要素ノードのclass属性の文字列リストを含んだDOMTokenListオブジェクト。属性がない場合はカラのDOMTokenListオブジェクトが返る。 |
例)最初に出てくるp要素ノードの、クラス属性をまとめて取得したい場合
<p class="hogeClass fugaClass piyoClass">テスト</p>
var hoge = document.getElementsByTagName('p');
console.log(hoge[0].classList);
#### 2-4-2. 戻り値であるDOMTokenListオブジェクトの概要
検索しても理解力が足らず、よくわからなかったが、
https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList
「空白(半角スペース)を区切りとしてクラス属性の値(クラス名)を並べた文字列」をvalueに持ち、「各クラス属性の値にインデックスでアクセスしたり、追加•削除ができるメソッドを持ったオブジェクト」という感じがした。
また、上記URLのサイトで、「This interface doesn't inherit any property.」「This interface doesn't inherit any method.」と書かれているので、Nodeインターフェース含め、何も継承していないオブジェクトだと思う。
(注) 以下、頭の整理のために【属性】としているところがあるが、ここで出てくるプロパティやメソッドは、classListのものではなく、classListによって得られるDOMTokenListのプロパティやメソッドなので、classList以外にもDOMTokenListを返すものがあれば、その場合は、得られるものが【属性】とは限らないことに注意する。
##### DOMTokenListオブジェクトが持つプロパティとメソッド
1-2-2のNodeList、1-4b-2のHTMLCollectionも、2-3-2のNamedNodeMap、と同様に、DOMTokenListにもlengthプロパティやitemメソッドがある。この2つ(lengthプロパティとitemメソッド)は、いろんなオブジェクトが持っているようだ。
###### 該当する【属性】の数を調べるlengthプロパティ
書き方 | DOMTokenList.length |
---|---|
戻り値 | DOMTokenListオブジェクトに含まれる【属性】の数。 |
例)最初に出てくるp要素ノードの、クラス属性の数を取得する場合
<p class="hogeClass fugaClass piyoClass">テスト</p>
var hoge = document.getElementsByTagName('p');
console.log(hoge[0].classList.length);//3と表示
###### DOMTokenListの中から特定の【属性】を取り出すitemメソッド
書き方① | DOMTokenList.item(i) |
---|---|
書き方② | DOMTokenList[i] |
戻り値 | DOMTokenListオブジェクトに含まれるi番目の【属性】。iが範囲外ならnullが返る。 |
例)最初に出てくるp要素ノードの、クラス属性の1つめを取得する場合
<p class="hogeClass fugaClass piyoClass">テスト</p>
var hoge = document.getElementsByTagName('p');
console.log(hoge[0].classList.item(0));//書き方①
console.log(hoge[0].classList[0]);//書き方②
console.log(hoge[0].classList[5]);//この場合は範囲外でnull
###### 指定した【属性】があるかどうか調べるcontainsメソッド
書き方 | DOMTokenList.contains(【属性】) |
---|---|
戻り値 | 真偽値。あればtrue、なければfalseを返す。引数にカラ文字が含まれたりするとエラー。 |
例)最初に出てくるp要素ノードの、クラス属性に"piyoClass"が含まれているか、"hogehogeClass"が含まれているか調べる場合
<p class="hogeClass fugaClass piyoClass">テスト</p>
var hoge = document.getElementsByTagName('p');
console.log(hoge[0].classList.contains('piyoClass'));//true
console.log(hoge[0].classList.contains('hogehogeClass'));//false
###### 指定した【属性】を追加するaddメソッド
書き方 | DOMTokenList.add(【属性1】,【属性2】,【属性3】...) |
---|---|
戻り値 | なし。引数にカラ文字が含まれたりするとエラー。 |
例)最初に出てくるp要素ノードの、クラス属性を追加する場合
<p class="hogeClass fugaClass piyoClass">テスト</p>
var hoge = document.getElementsByTagName('p');
hoge[0].classList.add('fooClass');//fooClassが追加される
console.log(hoge[0].classList);
hoge[0].classList.add('mooClass','booClass');//mooClassとbooClassが追加される
console.log(hoge[0].classList);
###### 指定した【属性】を削除するremoveメソッド
書き方 | DOMTokenList.remove(【属性1】,【属性2】,【属性3】...) |
---|---|
戻り値 | なし。引数にカラ文字が含まれたりするとエラー。 |
例)最初に出てくるp要素ノードの、クラス属性を削除する場合
<p class="hogeClass fugaClass piyoClass fooClass mooClass booClass">テスト</p>
var hoge = document.getElementsByTagName('p');
console.log(hoge[0].classList);
hoge[0].classList.remove('fooClass');//fooClassが削除される
console.log(hoge[0].classList);
hoge[0].classList.remove('mooClass','booClass');//mooClassとbooClassが削除される
console.log(hoge[0].classList);
###### 指定した【属性】の有無を切り替えるtoggleメソッド
第一引数に指定した【属性】があれば削除し、なければ追加するメソッド。
書き方 | DOMTokenList.toggle(【属性】) |
---|---|
戻り値 | なし。引数にカラ文字が含まれたりするとエラー。 |
例)最初に出てくるp要素ノードの、クラス属性に"fugaClass"があれば削除、なければ追加する場合
<p class="hogeClass fugaClass piyoClass">テスト</p>
var hoge = document.getElementsByTagName('p');
console.log(hoge[0].classList);
hoge[0].classList.toggle('fugaClass');//fugaClassが削除される
console.log(hoge[0].classList);
hoge[0].classList.toggle('fugaClass');//fugaClassが追加される
console.log(hoge[0].classList);
## 3. ノードを生成•設定する方法
### 3-1. createElement()メソッド-引数に指定した要素ノード(タグ要素)を生成!
Documentインターフェースによって実装された指定した要素名の要素ノード(Elementオブジェクト)を生成するメソッド。ただ、生成された要素ノードは、後述のNodeインターフェースが持っているappendChild()メソッド(4-1参照)などで追加しないとHTMLドキュメント上には反映されないので注意。
#### 3-1-1. メソッドの基本
書き方 | document.createElement("タグ名") |
---|---|
戻り値 | 指定したタグ名の要素ノード(Elementオブジェクト)。 |
例)p要素ノードを生成する場合
var elm = document.createElement("p");
console.log(elm);
#### 3-1-2. 生成した要素ノードに属性を設定する
生成した要素ノードに属性を設定する場合は、2-1〜2-4(2-4はクラス属性に関してのみ有効)で出てきた方法で設定する。
##### 要素ノードに用意されている、属性と同じ名前のプロパティを使う方法
2-1参照。
例)2-1の方法で、生成したp要素ノードにクラス属性"hogeClass"を設定する場合
var elm = document.createElement("p");
elm.className = "hogeClass";
console.log(elm);
##### 要素ノードに用意されている、属性を設定するsetAttribute()メソッドを使う方法
2-2参照。
例)2-2の方法で、生成したp要素ノードにクラス属性"hogeClass"を設定する場合
var elm = document.createElement("p");
elm.setAttribute("class","hogeClass");
console.log(elm);
##### 全ノードに用意されている(要素ノードのみ有効な値が得られる)、属性をまるごと取得するatributesプロパティと、Documentインータフェースによって実装された属性ノードを生成するメソッドcreateAttribute()メソッドを使う方法
atributesプロパティについては2-3参照。
createAttribute()メソッドについては3-2参照。
例)2-3と3-2の方法で、生成したp要素ノードにクラス属性"hogeClass"を設定する場合
var elm = document.createElement("p");
var zokuseiNode = document.createAttribute("class");//3-2参照
zokuseiNode.value = "hogeClass";//3-2参照
elm.attributes.setNamedItem(zokuseiNode);//2-3参照
console.log(elm);
##### Documentインータフェースによって実装された属性ノードを生成するメソッドcreateAttribute()メソッドと、要素ノードが持っている、要素ノードに属性ノードを設定するsetAttributeNode()メソッドを使う方法
3-2参照。
###### 要素ノードが持っている、要素ノードに属性ノードを設定するsetAttributeNode()メソッド
引数に指定した属性ノードを要素ノードに設定するメソッド。
書き方 | element.setAttributeNode(属性ノード) |
---|---|
戻り値 | なし。 |
例)3-2の方法で、生成したp要素ノードにクラス属性"hogeClass"を設定する場合
var elm = document.createElement("p");
var zokuseiNode = document.createAttribute("class");//3-2参照
zokuseiNode.value = "hogeClass";//3-2参照
elm.setAttributeNode(zokuseiNode);
console.log(elm);
##### 要素ノードに用意されている、要素ノードのクラス属性を扱うためのclassListプロパティを使う方法
例)2-4の方法で、生成したp要素ノードにクラス属性"hogeClass"を設定する場合
2-4参照。
var elm = document.createElement("p");
elm.classList.add("hogeClass");
console.log(elm);
#### 3-1-3. たくさんあるが、その使い分けとは
方法がたくさんあって正直混乱しているが、そもそも属性を取得したり設定したいときは、要素ノード(タグ要素)とセットだと考えると、2-1(属性と同じ名前のプロパティを使う方法)の方法で、だいたい大丈夫だと思う。自分でカスタム属性(たまに見かける「data-="*"」みたいなやつ)を、設定したい場合や、属性を頻繁に扱う場合は2-2だろうか。クラス属性を扱うときは2-4のclassListが便利なのは理解できた。ただ、2-3のatributesプロパティみたいな方法はどこで使うのか想像がついていない(初心者のため)。
### 3-2. createAttribute()メソッド-引数に指定した属性ノードを生成!
Documentインターフェースによって実装された指定した属性名の属性ノード(Attrオブジェクト)を生成するメソッド。Attrオブジェクトについては2-3-2参照。
#### 3-2-1. メソッドの基本
書き方 | document.createAttribute("属性名") |
---|---|
戻り値 | 指定したタグ名の属性ノード(Attrオブジェクト)。 |
例)属性ノード"href"を生成する場合
var elm = document.createAttribute("href");
console.log(elm);
#### 3-2-2. 生成した属性ノードに属性値を設定する
生成した属性ノードに属性値を設定する場合は、createAttribute()によって返されるAttrオブジェクト、が、持っている valueプロパティ(2-3-2参照)や、継承元のNodeインターフェースが持っている nodeValueプロパティ(1-4a-4参照)を使う。
例)生成した属性ノード"href"に属性値"index.html"を設定する場合
var elm = document.createAttribute("href");
elm.value = 'index.html';
console.log(elm);
console.log(elm.value);
var elm2 = document.createAttribute("href");
elm2.nodeValue = 'index2.html';
console.log(elm2);
console.log(elm2.nodeValue);
### 3-3. createTextNode()メソッド-引数に指定したテキストノードを生成!
Documentインターフェースによって実装された指定したテキストノード(Textインターフェースによって実装)を生成するメソッド。空白、タブ、改行などもテキストノード。子を持てないので、1-4a-4のNodeインターフェースで利用可能なプロパティでもchildNodesみたいなプロパティは使えない。また、3-1のcreateElement()、3-2のcreateAttribute()と同様に、ノードを作ってもHTMLドキュメントに追加したりしないと反映されないので注意。
#### 3-3-1. メソッドの基本
書き方 | document.createTextNode("テキスト") |
---|---|
戻り値 | 引数に指定したテキストノード。 |
例)テキストノード"テストです"を生成する場合
var elm = document.createTextNode("テストです");
console.log(elm);
#### 3-3-2. 生成したテキストノードの値を変更する
生成したテキストノードの値を変更する場合は、継承元のNodeインターフェースが持っている nodeValueプロパティやtextContentプロパティ(1-4a-4参照)を使う。
##### nodeValueプロパティを使う方法
例)生成したテキストノード"テストです"を"テスト2です"に変更する場合
var elm = document.createTextNode("テストです");
elm.nodeValue = "テスト2です";
console.log(elm);
##### textContentプロパティを使う方法
Nodeインターフェースによって実装された、対象ノードやすべての子ノードのテキスト内容を取得したり設定するプロパティ。
書き方 | Node.textContent |
---|---|
戻り値 | テキストノードの場合(よくわからないが、CDATAセクション、コメントノード、処理命令ノードの場合も)は、textContentはノードの内側のテキスト(nodeValue)を返す。documentやDocumentTypeオブジェクトなどの場合はnull。 |
※ CDATAとは「Character Data」の略で文字データのこと。
【要素ノード<script>や<style>の中身がCDATAとされており、「&」と書けば、「&」ではなく、そのまま「&」という文字列として、文字参照は展開されずに扱われる。また、タグの記号「<」「>」なども単なる文字として扱われる。コメントタグ「」も同じ。逆に、属性ノードの属性値の中では、文字参照が展開されて扱われるので、「onclick='alert("押すなよ")'」ではなく、「onclick="alert("押すなよ")"」と書く方がよい。】といった話らしいが、このtextContentプロパティの中での扱いというか、話の繋がりは理解できなかった。
###### 取得する場合
例)p#hoge要素ノードの中のテキストを取得する場合
<p id="hoge">p#hoge要素ノード直下のテキストです。<span>さらにその中のspanタグのテキストです。</span></p>
var elm = document.getElementById("hoge");
console.log(elm.textContent);//「p#hogeタグ直下のテキストです。さらにその中のspanタグのテキストです。」とspanタグを無視して表示
ちなみに、取得に関して「<」は「<」のように変換された。
例)p#hoge要素ノードの中のテキストを取得する場合
<p id="hoge">p#hogeタグ直下のテキストです。<span>さらにその中の<span>タグのテキストです。</span></p>
var elm = document.getElementById("hoge");
console.log(elm.textContent);//「p#hogeタグ直下のテキストです。さらにその中のspanタグのテキストです。」とspanタグを無視して表示し、「<」が「<」に変換されている。
window.alert(elm.textContent);//アラートを使っても一緒だった。
文書全体のテキストを取得したい場合は、「document.documentElement」から取得する。
例)文書全体のテキストを取得する場合
console.log(document.documentElement.textContent);
###### 設定する場合
対象ノードのtextContentプロパティに値をセットすると、ノードのすべての子供が取り除かれて、セットしたテキストノードに置き換わる。
例)生成したテキストノード"テストです"を"テスト2です"に変更する場合
var elm = document.createTextNode("テストです");
elm.textContent = "テスト2です";
console.log(elm);
ちなみに、設定に関しては「<」は「<」と変換されずに出た。
例)生成したカラのテキストノードに"<p>テスト2です"と設定する場合
var elm = document.createTextNode("");
elm.textContent = "<p>テスト2です";
console.log(elm.textContent);//「<p>テスト2です」と表示された
window.alert(elm.textContent);//アラートを使っても「<p>テスト2です」と表示された
document.body.appendChild(elm);//HTMLドキュメントに追加しても「<p>テスト2です」と表示された。appendChildに関しては4-1参照
## 4. ノードをHTMLドキュメントに反映(追加•挿入•削除)する方法
1-4a-4で記載したNodeインターフェースの"プロパティ"と同様、Nodeインターフェースには"メソッド"も用意されている。3-1のcreateElement()などで生成したノードをHTMLドキュメントに反映させる場合、このNodeインターフェースによって実装された"メソッド"を使う。
### 4-1. appendChild()メソッド-引数に指定したノードをHTMLドキュメントに追加!
Nodeインターフェースによって実装された、特定の親ノードに対して、引数に指定したノードを子ノードとして追加するメソッド。末尾に追加されるので、それ以外の場所に追加したい場合は、insertBefore()メソッド(4-2参照)を使う。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。
また、追加したいノード(引数に指定したノード)が、すでにHTMLドキュメントにある場合は、 __現在の親ノードから削除され、新しい親ノードに追加、つまり、「複製して追加する」のではなく、「削除して移動する」__ので注意する。追加される前の親ノードから削除する必要はない。
#### 4-1-1. メソッドの基本
書き方 | Node.appendChild(ノード) |
---|---|
戻り値 | 追加されたノード。引数で指定したノードがない場合や、正常に処理が出来ない場合は例外が発生。 |
例)p要素ノードを生成、"テスト"というテキストを入れてdiv#p-wrap要素ノードに追加する場合
<div id="p-wrap"></div>
パターン1
「createTextNode()メソッドで作ったnodeVlueが"テスト"のテキストノード【textn】」を、「createElement()メソッドで作ったp要素ノード【elm】」に、appendChild()メソッドを使って追加する。そして、「nodeVlueが"テスト"のテキストノード【textn】が追加されたp要素ノード【elm】」を、そのままdiv#p-wrap要素ノードにappendChild()メソッドを使って追加する。
var pWrap = document.getElementById("p-wrap");//div#p-wrap要素ノードを取得
var elm = document.createElement("p");//p要素ノードを生成
var textn = document.createTextNode("テスト");//nodeVlueが"テスト"のテキストノードを生成
elm.appendChild(textn);//p要素ノードにテキストノードを追加
pWrap.appendChild(elm);//div#p-wrapにp要素ノードを追加
パターン2
あとからテキストノードのnodeVlaueを設定してもできる。
var pWrap = document.getElementById("p-wrap");//div#p-wrap要素ノードを取得
var elm = document.createElement("p");//p要素ノードを生成
var textn = document.createTextNode("");//カラのテキストノードを生成
textn.textContent = "テスト";//テキストノードのnodeVlaueに"テスト"を設定。「textn.nodeValue」を使っても同じ
elm.appendChild(textn);//p要素ノードにテキストノードを追加
pWrap.appendChild(elm);//div#p-wrap要素ノードにp要素ノードを追加
パターン3
__要素ノードに対して、textContentプロパティを設定すると(textContentプロパティはNodeインターフェースによって実装されているので全ノードで呼び出せる)、テキストノードの生成と追加を一緒にしてくれる__みたい。「一旦テキストノードを生成すると便利なとき」が、わかっていないため、初心者のうちはこれを使ってみることにした。
var pWrap = document.getElementById("p-wrap");//div#p-wrap要素ノードを取得
var elm = document.createElement("p");//p要素ノードを生成
elm.textContent = "テスト";//p要素ノードのtextContentプロパティを指定して、テキストノードの生成と追加を一緒にする
pWrap.appendChild(elm);//div#p-wrap要素ノードにp要素ノードを追加
#### 4-1-2. 追加したいノードが、すでにHTMLドキュメントにある場合は、現在の親ノードから削除され、新しい親ノードに追加される
引数に指定した「追加したいノード」が、すでにHTMLドキュメントにある場合は、現在の親ノードから削除され、新しい親ノードに追加されるので、追加される前に親であったノードから削除する必要はない。
これは、appendChild()だけに限らず、1つのノードが、同じドキュメント上に、"同時に2つ以上現れない"ことを意味している。
##### クローンが生成されるのではなく、削除して移動する
まずは通常の追加、この時点では想像通り。
<div id="p-wrap01"></div>
<div id="p-wrap02"></div>
var pWrap01 = document.getElementById("p-wrap01");//div#p-wrap01要素ノードを取得
var pWrap02 = document.getElementById("p-wrap02");//div#p-wrap02要素ノードを取得
var text = document.createTextNode("テキスト");//nodeValueが"テキスト"のテキストノードを生成
pWrap01.appendChild(text);//テキストノードをdiv#p-wrap01要素ノードに追加
<div id="p-wrap01">テキスト</div><!-- 追加される -->
<div id="p-wrap02"></div>
このあと、div#p-wrap02要素ノードにも、作ったテキストノード【text】を追加しようとしても、引数に指定した「追加したいノード【text】」が、すでにHTMLドキュメントにあるため、現在の親ノード「div#p-wrap01要素ノード」から削除され、新しい親ノード「div#p-wrap02要素ノード」に追加される。結果、移動したみたいになる。
<div id="p-wrap01"></div>
<div id="p-wrap02"></div>
var pWrap01 = document.getElementById("p-wrap01");//div#p-wrap01要素ノードを取得
var pWrap02 = document.getElementById("p-wrap02");//div#p-wrap02要素ノードを取得
var text = document.createTextNode("テキスト");//nodeValueが"テキスト"のテキストノードを生成
pWrap01.appendChild(text);//テキストノードをdiv#p-wrap01要素ノードに追加
pWrap02.appendChild(text);//テキストノードをdiv#p-wrap02要素ノードに追加(この時点でdiv#p-wrap01要素ノードから削除される)
<div id="p-wrap01"></div><!-- 一旦テキストノードが追加された後で削除される -->
<div id="p-wrap02">テキスト</div><!-- 追加される -->
#### 4-1-3. 複製して追加したい場合は、NodeインターフェースのcloneNode()メソッドを使う
複製して追加したい場合は、NodeインターフェースのcloneNode()メソッドを使うのだが、cloneNode()メソッドやappendChild()メソッド以外にも、Nodeインターフェースで利用可能なメソッドは複数あるので、いったんまとめる。
Nodeインターフェースで利用可能なプロパティについては1-4a-4を参照。
##### Nodeインターフェースで利用可能なメソッド
| メソッド名 | 説明 |
|---|---|---|
| appendChild | 特定の親ノードに対して、引数に指定したノードを子ノードとして末尾に追加する。4-1参照。 |
| cloneNode | ノードを複製して返す。4-1-3参照(この項)。 |
| compareDocumentPosition | ノード同士の位置を比較し、位置関係を表したビットマスクを返す。前にあるよ、うしろにあるよ、子孫だよ、祖先だよ、といった情報が得られる。この記事では扱わない(よくわからなかったため)。 |
| contains | 引数に指定したノードが、対象ノードの子孫であるか調べる。真偽値を返す。4-1-3参照(この項)。 |
| hasChildNodes | 対象ノードが子ノードを持っているか調べて真偽値を返す。4-1-3参照(この項)。 |
| insertBefore | 対象ノードは親ノードで、第2引数に指定した子ノードの直前に、第1引数に指定したノードを子ノードとして挿入する。4-2参照。 |
| isEqualNode | ふたつのノードが同一ノードかどうか調べる。真偽値を返す。4-1-3参照(この項)。 |
| normalize | 対象ノードの、子孫にあるカラのテキストノードを削除したうえで、連続するテキストノードをひとつにまとめる。4-1-3参照(この項)。 |
| removeChild | 対象ノードから、引数に指定した子ノードを削除する。4-3参照。 |
| replaceChild | 対象ノードは親ノードで、第2引数に指定した子ノードを、第1引数に指定したノードに置き換える。4-4参照。 |
##### 今回使うcloneNode()メソッドの概要と使い方
###### cloneNode()メソッドの概要と使い方
対象ノードを複製するメソッド。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。引数にはtrueかfalseを指定。対象ノードの子孫ノードも複製する場合はtrue、対象ノードのみを複製する場合はfalseを指定する。
また、ノードを複製すると、そのノードのすべての属性とその値がコピーされるので、idが重複したり、HTML属性に設定されたイベント(<div onClick="myClick()">クリック</div>←みたいなもの)も複製されるので注意。
書き方 | Node.cloneNode(deep) |
---|---|
戻り値 | 複製されたノード。引数にtrueを指定した場合は、対象ノードの子孫ノードも複製して返す。falseを指定した場合は、対象ノードのみを複製して返す。 |
例)"テスト"というテキストノードをいれたp要素ノードを生成•複製して、div#p-wrap01要素ノードとdiv#p-wrap02要素ノードに、それぞれ追加する場合
<div id="p-wrap01"></div>
<div id="p-wrap02"></div>
var pWrap01 = document.getElementById("p-wrap01");
var pWrap02 = document.getElementById("p-wrap02");
var ptext = document.createElement("p");//p要素ノードを生成する
ptext.textContent = ("テスト");//p要素ノードのtextContentプロパティを指定して、テキストノードの生成と追加を一緒にする
var copyPtext = ptext.cloneNode(true);//テキストノードを含んだp要素ノードの複製を作る
pWrap01.appendChild(ptext);//div#p-wrap01には、はじめに生成したp要素ノードを追加する
pWrap02.appendChild(copyPtext);//div#p-wrap02には複製したp要素ノードを追加する
<div id="p-wrap01"><p>テスト</p></div><!-- 追加される -->
<div id="p-wrap02"><p>テスト</p></div><!-- 追加される -->
たとえば、このcloneNode()の引数にfalseを設定すると、p要素ノードの子ノードであるテキストノードは複製されないので注意。
var pWrap01 = document.getElementById("p-wrap01");
var pWrap02 = document.getElementById("p-wrap02");
var ptext = document.createElement("p");
ptext.textContent = ("テスト");
var copyPtext = ptext.cloneNode(false);//引数にfalseを設定すると子ノードであるテキストノードを含まないp要素ノードのみの複製が作られる
pWrap01.appendChild(ptext);
pWrap02.appendChild(copyPtext);
<div id="p-wrap01"><p>テスト</p></div><!-- 追加される -->
<div id="p-wrap02"><p></p></div><!-- 追加されるが、テキストノードは複製されていないので、カラのp要素ノードのみ -->
##### その他のメソッドの概要と使い方
###### hasChildNodes()メソッドの概要と使い方
対象ノードが子ノードを持つかどうかの真偽値を返すメソッド。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。
書き方 | Node.hasChildNodes() |
---|---|
戻り値 | 真偽値を返す。子ノードを持っている場合はtrueを返す。持っていない場合はfalse返す。 |
例)div#p-wrap要素ノードが子ノードを持っていたら、その子ノードの中の1つめを取得する場合
<!-- 改行もテキストノード(div#p-wrap要素ノードの子ノード)なので、改行を消しておく -->
<div id="p-wrap"><p id="pBlock01">pBlock01です</p><p id="pBlock02">pBlock02です</p></div>
var parentElm = document.getElementById("p-wrap");
if(parentElm.hasChildNodes()){
console.log(parentElm.firstChild);//p#pBlock01要素ノードが表示
}
###### contains()メソッドの概要と使い方
引数に指定したノードが、対象ノードの子孫ノードであるかどうかの真偽値を返すメソッド。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。
書き方 | Node.contains(ノード) |
---|---|
戻り値 | 真偽値を返す。対象ノードの子孫ノード、もしくは、自分自身(対象ノードそのもの)の場合はtrueを返す。そうでない場合はfalse返す。 |
例)p#pBlock01要素ノードがbody要素ノードに含まれているかどうか調べる場合
<body>
<!-- ↑他の要素 -->
<div id="p-wrap">
<p id="pBlock01">pBlock01です</p>
<p id="pBlock02">pBlock02です</p>
</div>
<!-- ↓他の要素 -->
</body>
var targetP = document.getElementById("pBlock01");
console.log(document.body.contains(targetP));//trueが表示
ただ、contains()メソッドは「自分自身」の場合もtrueが返るので、上サンプルの場合だと、引数に指定したノードがbodyだった場合にtrueになるので注意する。
次の例は、contains()メソッドの引数に指定したノードが、body要素に "含まれて" いるかどうかを調べる関数。
例)引数に指定したノードが、body要素に含まれているかどうかを調べる関数
function checkBodyNoKoyouso(node){
if(node === document.body){//body要素ノードそのものか判定
//body要素ノードそのものの場合
return false;
}else{
//body要素ノードではない場合
return document.body.contains(node);//含まれているかどうかの判定結果を返す
}
}
###### normalize()メソッドの概要と使い方
対象ノードの、子孫にあるカラのテキストノードを削除したうえで、連続するテキストノードをひとつにまとめるメソッド。プログラムの中で、無意味にテキストノードが乱立すると、それらのノードの処理が複雑になってしまうため、必要に応じて連続するテキストノードをまとめる場合に使える。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。
書き方 | Node.normalize() |
---|---|
戻り値 | なし。 |
例)別々に作ったテキストノードを、作ったp要素ノードに入れたうえで、テキストノードを1つにまとめる場合
var text01 = document.createTextNode("テキスト01");
var text02 = document.createTextNode("テキスト02");
var text03 = document.createTextNode("テキスト03");
var textWrap = document.createElement("p");
textWrap.appendChild(text01);
textWrap.appendChild(text02);
textWrap.appendChild(text03);
console.log(textWrap.childNodes.length);//3が表示(この時点ではテキストノードが3つ入っている)
textWrap.normalize();
console.log(textWrap.childNodes.length);//1が表示(normalizeによってテキストノードが1つにまとまった)
###### isEqualNode()メソッドの概要と使い方
対象ノードと引数に指定したノードを比較して、同一ノードの場合はtrueを、異なる場合はfalseを返すメソッド。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。
===(イコール3つ)でも大丈夫そうだが、使いどころがあるのだろう。今のところわかっていないが、まとめておく。
書き方 | Node.isEqualNode(比較するノード) |
---|---|
戻り値 | 真偽値を返す。同一ノードの場合はtrueを、異なる場合はfalseを返す。 |
例)div#p-wrap要素ノードの最初の子ノードと、p#pBlock01要素ノードテキストノードが一致しているか調べる場合
<!-- 改行もテキストノード(div#p-wrap要素ノードの子ノード)なので、改行を消しておく -->
<div id="p-wrap"><p id="pBlock01">pBlock01です</p></div>
var node01 = document.getElementById("p-wrap").firstChild;
var node02 = document.getElementById("pBlock01");
console.log(node01.isEqualNode(node02));trueが表示
if(node01===node02){//これでも大丈夫だった
console.log("true");
}else{
console.log("false");
}
### 4-2. insertBefore()メソッド-対象ノードをHTMLドキュメント上の指定した場所に追加!
Nodeインターフェースによって実装された、対象ノードは親ノードで、第2引数に指定した子ノードの直前に、第1引数に指定したノードを子ノードとして挿入するメソッド。第2引数に指定した子ノードがnullの場合、子ノードのリストの末尾に挿入される。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。
また、追加したいノード(第1引数に指定したノード)が、すでにHTMLドキュメントにある場合は、 __現在の親ノードから削除され、新しい親ノードに追加、つまり、「複製して追加する」のではなく、「削除して移動する」__ので注意する。
#### 4-2-1. メソッドの基本
書き方 | Node.insertBefore(追加するノード,位置を指定するノード) |
---|---|
戻り値 | 追加されたノード。引数で指定したノードがない場合や、正常に処理が出来ない場合は例外が発生。 |
例)p要素ノードを生成、"追加したp要素ノードです"というテキストを入れてdiv#p-wrap要素ノードの中の、p#pBlock03要素ノードの前(p#pBlock01要素ノードとp#pBlock03要素ノードの間)に追加する場合
<div id="p-wrap">
<p id="pBlock01">pBlock01です</p>
<p id="pBlock03">pBlock03です</p>
</div>
var pWrap = document.getElementById("p-wrap");
var targetP = document.getElementById("pBlock03");
var newP = document.createElement("p");
newP.textContent = "追加したp要素ノードです";
pWrap.insertBefore(newP, targetP);
<div id="p-wrap">
<p id="pBlock01">pBlock01です</p>
<p>追加したp要素ノードです</p><!-- 追加される -->
<p id="pBlock03">pBlock03です</p>
</div>
#### 4-2-2. insertBefore()メソッドとnextSiblingプロパティを組み合わせて、insertAfter()メソッド??
jQueryのように、insertAfterというメソッドはないが、insertBefore()メソッドとnextSiblingプロパティ(1-4a-4、1-6参照)を組み合わせて、第1引数に指定する「追加するノード」を、第2引数に指定する「位置を指定するノード」の "あと" に挿入できる。
例)p要素ノードを生成、"追加したp要素ノードです"というテキストを入れてdiv#p-wrap要素ノードの中の、p#pBlock03要素ノードの前(p#pBlock01要素ノードとp#pBlock03要素ノードの間)に追加する場合
<div id="p-wrap">
<p id="pBlock01">pBlock01です</p>
<p id="pBlock03">pBlock03です</p>
</div>
var pWrap = document.getElementById("p-wrap");
var targetP = document.getElementById("pBlock01");
console.log(targetP.nextSibling);//「#text」と表示、つまり今回は改行ノードをとってきている。
var newP = document.createElement("p");
newP.textContent = "追加したp要素ノードです";
pWrap.insertBefore(newP, targetP.nextSibling);//第2引数にノードのnextSiblingプロパティを指定する
<div id="p-wrap">
<p id="pBlock01">pBlock01です</p>
<p>追加したp要素ノードです</p><!-- 追加される -->
<p id="pBlock03">pBlock03です</p>
</div>
※上のhtmlサンプルソースは、改行しているため、【targetP.nextSibling】に「#text(改行のテキストノード)」が入っている。なので、正確にはp#pBlock01要素ノードとその直後にある"改行"テキストノードの間に挿入している。p#pBlock01要素ノードとp#pBlock03要素ノードの間の改行を消せば【targetP.nextSibling】に、p#pBlock03要素ノードが入り、見た目は一緒だが、文字通り"p#pBlock01要素ノードとp#pBlock03要素ノードの間"に追加したことになる。
もし、第2引数に指定したノードに、隣り合うノード(うしろのノード)がない=末尾の子ノードであった場合も、nullが返ってくれば、子ノードのリストの末尾に挿入されるので便利。
<!-- 改行をとってきてnullにならないので、改行を消しておく -->
<div id="p-wrap"><p id="pBlock01">pBlock01です</p></div>
var pWrap = document.getElementById("p-wrap");
var targetP = document.getElementById("pBlock01");
console.log(targetP.nextSibling);//nullが表示
var newP = document.createElement("p");
newP.textContent = "追加したp要素ノードです";
pWrap.insertBefore(newP, targetP.nextSibling);//第2引数がnullになっても末尾に挿入される
<div id="p-wrap">
<p id="pBlock01">pBlock01です</p>
<p>追加したp要素ノードです</p><!-- ちゃんと追加される -->
</div>
#### 4-2-3. firstChildプロパティを使用すれば、最初の子要素の前に要素を追加できる
jQueryのprepend()メソッドのような、一番前に挿入するようなメソッドはないが、firstChildプロパティ(1-4a-4、1-4c参照)を使って、最初の子要素の前に要素を追加できる。
※ 改行もテキストノードなので、今回ははじめからとっておく。
<div id="p-wrap"><p id="pBlock01">pBlock01です</p><p id="pBlock03">pBlock03です</p></div>
var pWrap = document.getElementById("p-wrap");
var newP = document.createElement("p");
newP.textContent = "追加したp要素ノードです";
var target = pWrap.firstChild;
console.log(target);//<p id="pBlock01">pBlock01です</p>が表示
pWrap.insertBefore(newP, target);
<div id="p-wrap">
<p>追加したp要素ノードです</p><!-- 追加される -->
<p id="pBlock01">pBlock01です</p>
<p id="pBlock03">pBlock03です</p>
</div>
4-2-2と同様に、第2引数に指定したノードに、nullが入った場合も、唯一の子ノードとして挿入されるので便利。
<div id="p-wrap"></div>
var pWrap = document.getElementById("p-wrap");
var newP = document.createElement("p");
newP.textContent = "追加したp要素ノードです";
var target = pWrap.firstChild;
console.log(target);//nullと表示
pWrap.insertBefore(newP, target);
<div id="p-wrap">
<p>追加したp要素ノードです</p><!-- ちゃんと追加される -->
</div>
### 4-3. removeChild()メソッド-指定したノードをHTMLドキュメント上から削除!
Nodeインターフェースによって実装された、親ノードから、引数に指定した子ノードを削除するメソッド。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。
また、戻り値として削除したノードへの参照が返ってくるので、変数に入れてプログラムの中で再利用できる。
#### 4-3-1. メソッドの基本
書き方 | Node.removeChild(削除したい子ノード) |
---|---|
戻り値 | 削除されたノード。引数で指定したノードが子ノードでない(親子になっていない)場合は例外が発生。 |
例)親ノードdiv#p-wrap要素ノードの中の、p#pBlock01要素ノードを削除する場合
<div id="p-wrap">
<p id="pBlock01">pBlock01です</p>
<p id="pBlock02">pBlock02です</p>
</div>
var pWrap = document.getElementById("p-wrap");
var targetP = document.getElementById("pBlock01");
pWrap.removeChild(targetP);
<div id="p-wrap">
<p id="pBlock02">pBlock02です</p>
</div>
#### 4-3-2. parentNodeプロパティを使って、親要素が不明、不定の場合でも削除できる
parentNodeプロパティ(1-4a-4、1-5参照)を使って、親ノードを見つけてしまえば、親要素が決まってない場合でも削除できる。
親の要素ノードの中の、p#pBlock01要素ノードを削除する場合
<div>
<p id="pBlock01">pBlock01です</p>
<p id="pBlock02">pBlock02です</p>
</div>
var targetP = document.getElementById("pBlock01");
var parentElm = targetP.parentNode;//親ノードを見つける
parentElm.removeChild(targetP);//あらためて見つけた親ノードから削除する
<div>
<p id="pBlock02">pBlock02です</p>
</div>
#### 4-3-3. while文を使って親ノードから子ノードをすべて削除する
例)親ノードdiv#wrap要素ノードの中の、子ノードを全て削除する場合
<div id="wrap">
<p>pです</p>
<p>pです</p>
<div>divです</div>
テキストです
</div>
var parentElm = document.getElementById("wrap");
while(parentElm.firstChild){//nullだった場合false判定になる
parentElm.removeChild(parentElm.firstChild);
}
<div id="wrap"></div>
上のサンプルは、firstChildプロパティとwhile文を使って、"最初の子ノードがあるかぎり、最初の子ノードを削除し続ける"という内容になっている。条件式の部分は、ノードが返ってくればtrue(オブジェクトが存在すればtrue)、ノードがなくてnullが返ってくればfalseになるという決まりを使っている。最初の子ノードには、要素ノードだけではなく、"改行"を含めたテキストノードも入ってくる。それを1つ消しては、子ノードがあるかどうかの判定をする、の繰り返し。
### 4-4. replaceChild()メソッド-指定したノードを別のノードに置き換える!
Nodeインターフェースによって実装された、第2引数に指定した子ノードを、第1引数に指定した別のノードに置き換えるメソッド。第2引数に指定した置き換えられる古いノードは、"子ノード"でないと例外が発生する。Nodeインターフェースによって実装されているので、すべてのノードで呼び出せる。
また、戻り値として削除したノード(置き換えられた古いノード)への参照が返ってくる。
#### 4-4-1. メソッドの基本
書き方 | Node.replaceChild(新しいノード,古い"子"ノード) |
---|---|
戻り値 | 置き換えられた古いノード。古いノードが子ノードでない(親子になっていない)場合は例外が発生。 |
例)親ノードdiv#p-wrap要素ノードの中の、p#pBlock01要素ノードを、p#pBlock02要素ノードに置き換える場合
<div id="p-wrap">
<p id="pBlock01">pBlock01です</p>
</div>
<p id="pBlock02">pBlock02です</p><!-- 置き換える新しいノードはどこにあっても大丈夫 -->
var parentElm = document.getElementById("p-wrap");
var oldP = document.getElementById("pBlock01");
var newP = document.getElementById("pBlock02");
parentElm.replaceChild(newP, oldP);
<div id="p-wrap">
<p id="pBlock02">pBlock02です</p><!-- 置き換えられる -->
</div>
## 5. CSSを取得•操作する方法
### 5-1. styleプロパティ-インライン(スタイル属性)で要素ノードにCSSを適用する!
DOMのHTMLElementインターフェースによって、要素ノードの"style"属性に相当するオブジェクト(CSSStyleDeclarationオブジェクト)が用意されているので、そのオブジェクトを使って動的にCSS操作ができる。
#### 5-1-1. プロパティの基本
書き方 | element.style |
---|---|
戻り値 | 要素ノードの"style"属性に相当するオブジェクト(CSSStyleDeclarationオブジェクト)を返す。 |
例)p#p01要素ノードのスタイル属性を取得する場合
<p id="p01" style="color:red;font-size:50px;">p01です</p>
var p01 = document.getElementById("p01");
console.log(p01.style);
#### 5-1-2. スタイルを設定する場合は、戻り値であるCSSStyleDeclarationオブジェクト、が持っているプロパティを使う
CSSStyleDeclarationオブジェクトには、CSSのプロパティと同名のプロパティが用意されていて、そのプロパティに値を設定することで、文字サイズや色など、個別のスタイルを適用できる。
「『なにかのプロパティやメソッドで得られたオブジェクト』、が、持っている『プロパティやメソッド』」という意味で、1-2-2のNodeList、1-4b-2のHTMLCollection、2-3-2のNamedNodeMap、2-4-2のDOMTokenListとかと近いイメージだと思う。
プロパティ名は「background-color」は「backgroundColor」のようにハイフンがあるものは、ハイフンをとったうえで、次の文字を大文字にするので注意。
また、インラインのスタイル属性でスタイルを扱う場合は、2-2で出てくるsetAttributeより、この方法を使う方がよい。
例)p#p01要素ノードにスタイル「background-color:black;」を追加する場合
<p id="p01" style="color:red;font-size:50px;">p01です</p>
var p01 = document.getElementById("p01");
p01.style.backgroundColor = "black";//ハイフンをとって大文字にする
console.log(p01.style.backgroundColor);//blackと表示
<p id="p01" style="color:red;font-size:50px;background-color:black;">p01です</p><!-- 追加される -->
### 5-2. クラス属性を操作してCSSを適用する!
cssのスタイルを用意しておいて、クラスをふることによってスタイルを適用する。初心者の自分はこの方法だと思う。
例)classList(2-4参照)を使って要素ノードにクラスを追加、用意していたスタイルを適用させる場合
<p id="p01">p01です</p>
<p id="p02">p02です</p>
<p id="p03">p03です</p>
.red{
color:red;
}
.green{
color:green;
}
.blue{
color:blue;
}
.big-font{
font-size: 50px;
}
.normal-font{
font-size: 25px;
}
.small-font{
font-size: 15px;
}
var p01 = document.getElementById("p01");
var p02 = document.getElementById("p02");
var p03 = document.getElementById("p03");
p01.classList.add("red","big-font");
p02.classList.add("green","normal-font");
p03.classList.add("blue","small-font");
## 6. 最後に
見直し中です