DOM操作は JavaScript に欠かせない要素です。
Web サイトにおいて HTML が骨、CSS が皮膚・肉だとすれば、歩いたり走ったりの動作を追加するのが JavaScript。
つまりユーザーがボタンをクリックしたらどうするのか、input タグに入力したらどういうプログラムが動くのかなど、動きの部分を司っています。(他にもアニメーションなどの役割がありますが今回は DOM 操作にフォーカスしましょう)。
私は DOM 操作が JavaScript の面白い部分だと思っていますが、初めて遭遇したときは全く意味が分からず逃走しました。操作方法以前に Element とか Node とか似たような言葉が多くて意味が混乱するんですよね。
ということで今日は一旦実際の操作を置いておいて、DOM にまつわる以下の言葉についてなるべく分かりやすく解説していこうと思います。
この記事で扱う語彙
- DOM
- Element(要素)
- Node
- Event
- イベントハンドラー
- イベントリスナー
この6つさえ知っておけばいざ実装したいときに大体どんなドキュメントにも立ち向かえるはずです!
DOM
DOM 操作って言いますが、そもそもの「DOM」の意味ってなんでしょう。
ドキュメントオブジェクトモデル (Document Object Model, DOM) は、— ウェブページを表す HTML のように — 文書の構造をメモリー内に表現することで、ウェブページとスクリプトやプログラミング言語を接続するものです。ふつうは JavaScript を使用しますが、 HTML、 SVG、 XML などの文書をオブジェクトとしてモデリングすることはコア JavaScript 言語の一部ではありません。
MDN の説明ですが、すでに分かりにくい言葉が山盛りですね。勝手に意訳したいと思います。
意訳:
DOM は HTML などの文書の構造を 表現 しているもので、Webページとプログラミング言語を接続してくれます。プログラミング言語としては主に JavaScript が使用されます。
DOM = HTML ではありません。
DOM は HTML を JavaScript から操作できる形にしてくれているインターフェイス、接続ポイントのようなものです。こんなイメージでしょうか。
では MDN の続きを読んでみましょう。
DOM は文書を論理的なツリーで表現します。ツリーのそれぞれの枝はノードで終わっており、それぞれのノードがオブジェクトを含んでいます。 DOM のメソッドでプログラム的にツリーにアクセスできます。これにより、文書構造やスタイルやコンテンツを変更することができます。
ドキュメントオブジェクトモデル (DOM) - Web API | MDN
意訳
DOM はツリー構造になっており、要素同士に親子や兄弟の関係がある。ツリーのそれぞれの枝はノードで終わり、ノードは JavaScript のデータ構造であるオブジェクトを含んでいる。DOM はメソッドを持っており、メソッドを使うとページの内容や見た目を変更できる
ツリー構造とはこのような構造です。
引用: ツリー構造とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
DOM の場合はこんな形になっています。
引用: Document Object Model - Wikipedia
そしてDOM を学習しているとよく出てくる「ノード」という言葉。詳細は後で解説しますが、DOM ツリーのそれぞれの枝はノードで終わっています。ノードをはじめとする DOM の仲間たちはオブジェクトの形になっており JavaScript で操作可能です。
まとめ
- DOM とは HTML を JavaScript から操作できる形にしてくれているインターフェイスであり、オブジェクトの形で提供されている
- DOM はツリー構造であり、ツリーのそれぞれの枝はノードで終わっている
Node
お次は Node について見ていきましょう。
先ほどのおさらいをすると、Node は DOM ツリーのパーツであり、オブジェクトとして JavaScript から操作可能です。
しかしよく似た言葉として Element = 要素があるのが混乱ポイントではないでしょうか。
また MDN を引用していきましょう。
DOM の Node インターフェイスは、他の多くの DOM API オブジェクトのベースとなる抽象的な基底クラスです。したがって、これらのオブジェクト型と類似しており、しばしば交換して使用することができます。抽象クラスであるため、単なる Node オブジェクトというものは存在しません。 Node の機能を実装しているオブジェクトはすべて、何れかのサブクラスに基づいています。最も注目すべきものは、 Document, Element, DocumentFragment です。
それに加えて、あらゆる種類の DOM ノードが Node を基底とするインターフェイスで表現されます。これには、 Attr, CharacterData (Text, Comment, CDATASection, ProcessingInstruction がすべて基底とするもの), DocumentType があります。
Node - Web API | MDN
意訳
Node は単に Node として使用されるわけではなく、他の DOM オブジェクトたちのベースであり、継承源である。Document, Element などをはじめとする DOM オブジェクトはすべて Node をもとにして作られている。
Node と Element は混同されることも多いですが、実際には Node をベースにしてElement が作成されているんですね。
▼ ここで深く関わっている継承の考え方についてはこちらの記事で解説しています。よければご覧ください
場合によっては、ベースとなる Node インターフェイスの特定の機能が子インターフェイスに適用されないことがあります。この場合、継承するノードは状況に応じて null を返したり、例外を投げたりします。例えば、子を持てないノード型に子を追加しようとすると、例外が発生します。
Node - Web API | MDN
Node をもとにして他の DOM オブジェクトが作られていますが、Node が持っている機能を持っていないオブジェクトもあります。
上の図のようなイメージです。
メソッド3、プロパティ1が継承先では消え、独自メソッド1と独自プロパティが追加されています。
ちなみに Node自体は EventTarget を継承しています。
まとめ
- Node はすべての DOM オブジェクトのもと
Element(要素)
次は Node と混ざりがちな Element についてみていきましょう。
おさらいすると、Element は Node をもととして作成されているオブジェクトですね。
Element は Document が継承するオブジェクトの中にあるすべての要素オブジェクト(すなわち、要素を表現するオブジェクト)が継承する、もっとも一般的な基底クラスです。すべての種類の要素の共通するメソッドとプロパティのみを持ちます。もっと具体的なクラスが Element を継承しています。
例えば HTMLElement インターフェイスは HTML 要素の基本インターフェイスであり、 SVGElement インターフェイスはすべての SVG 要素の基本になります。ほとんどの機能は、クラスの階層を下りると具体化していきます。
Element - Web API | MDN
意訳
Elementは要素を表現します。これは HTML 以外の文書でも使われる広い意味の要素ですが、Element を元にしてさらに HTMLElement が作られています。 HTMLElement は HTML 要素(div タグや h1タグ)を操作するためのオブジェクトです。
ちょっと複雑になってきましたが、以下の図のような感じです。
Element を継承している HTMLElement から、div や img, h1, p といったHTML のタグにアクセスできます。
まとめ
- HTML タグを操作するときには HTMLElement を操作している
- HTML Element のもとは Element であり、Element のもとは Node
Event
DOM 操作において特に大切なのが「イベント」ですね。
イベントとはその名の通り「出来事」です。ユーザーの操作もあるし、「充電が減った」などユーザ操作でないものもあります。
- ユーザーがある要素の上をマウスでクリックしたり、ある要素の上にカーソルを持ってくる
- ユーザーがキーボードのキーを押す
- ユーザーがブラウザー画面をリサイズしたり閉じたりする
- ウェブページのロードの完了
- フォームの送信
- ビデオが再生中、停止中、再生が終わった
- エラーの発生
イベントへの入門 - ウェブ開発を学ぶ | MDN
などなどたくさんあります。
まとめ
- イベント = 出来事。ユーザーの操作に限らない
ではイベントが発生したときにどんな動作をするかはどう実装するでしょう?
イベントハンドラー
ノードにはイベントハンドラーを割り当てることができます。イベントが発生すると、イベントハンドラーが実行されます。
ドキュメントオブジェクトモデル (DOM) - Web API | MDN
意訳: ノードには EventTarget.addEventListner メソッドを使ってイベントハンドラーを追加することができる。イベントが発生するとイベントハンドラーが実行される
イベントハンドラーとは、onClick
, onInput
などのイベントの種類と、イベントを処理するために関連づけられた関数のことです。
handle という英単語には「制御する、操縦する」の他に「対処する」という意味もあるようなのでそちらの意味でしょうか。
イベントの種類(イベントハンドラープロパティ)と関数は、「このイベントが起こったらこう動作する」というふうにセットで設定されます。
ちなみにイベントハンドラーとよく似た言葉である「イベントリスナー」はなんでしょうか?
イベントリスナーはイベントの発生を監視し、イベントハンドラーは発生したイベントの応答として動作するコードです。
イベントへの入門 - ウェブ開発を学ぶ | MDN
イベントリスナーは監視カメラ、イベントハンドラーが事件に対処するお巡りさんという感じでしょうか。
まとめ
- イベントハンドラーとは、onClick, onInput などのイベントの種類と、イベントを処理するために関連づけられた関数のこと
では、お次は監視カメラ部分の イベントリスナー を見ていきましょう。
イベントリスナー
ここまでの振り返りになりますが、イベントリスナーはイベントの発生を監視し待ち受けてくれます。addEventListner
というメソッドを使って実装します。
addEventListener() は EventTarget インターフェイスのメソッドで、ターゲットに特定のイベントが配信されるたびに呼び出される関数を設定します。
対象としてよくあるものは Element, Document, Window ですが、イベントに対応したあらゆるオブジェクトが対象になることができます (XMLHttpRequest など)。
EventTarget.addEventListener() - Web API | MDN
EventTarget.addEventListener()
という項目になっていることからも分かるように、 イベントの対象.addEventListner(イベントの種類, 関数)
の形で使用します。
まとめ
- イベントリスナーはイベントの発生を待ち受け、発生と共にイベントハンドラを動かしてくれる
-
イベントの対象.addEventListner(イベントの種類, 関数)
の形でメソッドを使って実装可能
この記事のまとめ
- DOM とは HTML を JavaScript から操作できる形にしてくれているインターフェイスであり、オブジェクトの形で提供されている
- DOM はツリー構造であり、ツリーのそれぞれの枝はノードで終わっている
- Node はすべての DOM オブジェクトのもと
- HTML タグを操作するときには HTMLElement を操作している
- HTML Element のもとは Element であり、Element のもとは Node
- イベント = 出来事。ユーザーの操作に限らない
- イベントハンドラーとは、onClick, onInput などのイベントの種類と、イベントを処理するために関連づけられた関数のこと
- イベントリスナーはイベントの発生を待ち受け、発生と共にイベントハンドラを動かしてくれる
- イベントの対象.addEventListner(イベントの種類, 関数)` の形でメソッドを使って実装可能