「JavaScript/DOM」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
編集の要約なし
Ef3 (トーク | 投稿記録)
getElementByIdメソッドからquerySelectorメソッドへ書換え
2 行
'''[[w:Document Object Model|DOM]]'''(ドム、'''''D'''ocument '''O'''bject '''M'''odel''、ドキュメント・オブジェクト・モデル)とは、プログラミング言語から[[HTML]]ドキュメントなどを扱うために標準化された仕様です<ref>かつてはW3CがDOMの標準化を行っていましたが、2021年6月現在では[[w:WHATWG|WHATWG]]の策定する DOM
Living Standard が標準です。 https://dom.spec.whatwg.org/</ref>。DOMをサポートするのはウェブブラウザ上のJavaScriptだけではありません。
JavaとDOMによるXML文書の操作や [[w:Node.js|Node.js]] と [https://github.com/jsdom/jsdom jsdom] の組み合わせの様なウェブブラウザ上のJavaScript以外の DOM 実装は存在します<ref>元来、DOMは「プログラミングを言語に依存しない」オブジェクトモデリングシステムなので驚くに値しません</ref><ref>Abstract. DOM defines a platform-neutral model for events, aborting activities, and node trees. [https://dom.spec.whatwg.org/ DOM Living Standard.]</ref>。ウェブブラウザ上のJavaScriptにはDOM操作のためのDocumentオブジェクトが組み込まれています。
 
注意<div style="font-size:9pt; border: 3px solid #f007;border-radius: 4pt;padding: 4pt;margin:4pt">以前、このパラグラフでwindow.alertメソッドがDOMの一部であるとの記述が有りましたいのは、ウェブブラウザ上に警告ダイアログを表示する<code>window.alert</code>メソッドは Web API の一部ですが'''DOMの一部ではありません'''<ref>window.alert() [[https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-alert HTML Living Standard::8.8.1 Simple dialogs]]で定義されています。[[https://dom.spec.whatwg.org/ DOM Living Standard]]ではありません。</ref>。</div>
 
== 概要 ==
19 行
<div id="output"></div>
<scrip>
const output = document.getElementByIdquerySelector("#output");
output.innerHTML = "Hello, world!";
</script>
30 行
<code>document.getElementById</code>メソッドはDOMの一部で<ref>https://dom.spec.whatwg.org/#dom-nonelementparentnode-getelementbyid</ref>、this(この場合は document)の子孫の中でIDが与えられたIdと一致する最初の要素をツリー順に返し、位置する要素がない場合はnullを返します。ここでは "output" というIDを持つ要素、すなわち<code><nowiki><div id="output"></div></nowiki></code>という<code>div</code>要素を参照し、要素に対応するElementオブジェクトを<code>output</code>という変数に代入しています。
 
<code>output.innerHTML</code>プロパティを使用すると<code>div</code>要素の中身を取得したり設定したりすることができます。ここでは<code>output.innerHTML</code>に <code>"Hello, world!"</code> という文字列を代入しているので、<code>div</code>要素の中身は "Hello, world!" という文字列になります。
 
== 動的なWebページの操作 ==
 
JavaScriptを学びたいと言う人間の多くは、おそらくよりダイナミックなWebページを製作したいという方だと思われる。
 
39 ⟶ 38行目:
 
=== Document Object Model の解説 ===
 
Document Object Model (以下、DOM)とは、HTML文書やXML文書をオブジェクトの木構造モデルで表現することで、文章をスクリプトやプログラムから操作することを実現するインターフェースである。
 
黎明期はJavaで実装・規格化されたため、XMLを扱うならJava一択という認識があった時期もあったが、現在ではほとんどの言語でDOMのプログラムインターフェースが整備されておりどの言語を選んだとしてもHTML文書やXML文書を扱えるようになっている(代表的な言語でDOMが標準でバンドルされていないものはRubyくらいであるが、こちらはREXMLという、よりリッチなライブラリを積んでいる)。
 
DOMは、基本的にはオブジェクト指向的な扱いを考えながらも、Java以外にも多くの言語で動作することを期待して規格化されており、文法的には堅くやや面倒くさい記述法をしているが、Webブラウザ側でHTML文書やXML文書を扱うための、ほぼ唯一の方法なので慣れる様努力して欲しい<ref>過去には、SAXをJavaScriptで実装しようとしたり、ECMAScript for XML(E4X)のように言語仕様にXML操作を組み込む試みも有りました。</ref>
 
なお、DOMは現在では主流のブラウザほとんどで利用が出来るが、古いブラウザに関しては動かないものが多くある事を注意しておく(例としてはMicrosoftのInternetExplolerでは5.0以降で対応している)。
 
=== サンプル ===
 
HTML文書やXML文書は、文書を要素で囲い込んでいるが、タグは必ず入れ子になるように書かれないといけないため必然的に囲っているタグと囲われているタグとの間に親子関係がある。
そして、複数の要素を子として取ることが出来るため、要素はツリー状に整理することが出来る。
DOMとはXML文書がツリー構造になる事を強く意識して作成されているライブラリ群である。
 
DOMは内部の動作原理が最初は想像をしにくいライブラリであるので、これを習得する際には実際にHTML文書やXML文書を読み込んで、それを操作しながら、動作とプログラムとの対応関係を頭の中に焼き付けてしまうのが一番良い方法だと思われる。
 
まずは、次のサンプルを打ち込んでほしい。
69 ⟶ 62行目:
</div>
<script>
alert(document.getElementsByTagName("body")[0].getElementsByTagNamequerySelector("p")[0].firstChild.nodeValue);
</script>
</body>
</html>
</syntaxhighlight>
 
この文書では、HTML文書中のbodyタグ内部に、divタグが埋め込まれており、さらにその中にpタグ。その中にテキストが埋め込まれている。
ここから「DOM TEST」の文字列を読み出したい場合には、サンプルコードの様に記述をすればよい。
82 ⟶ 74行目:
documentはDocumentインターフェイスのオブジェクトで、特別に宣言を行わなくても存在し、
これにはwebページでのhtml要素をrootとする木構造として文書本体が格納されている。
document.querySelector("p")は、DOMツリーの頂点からセレクタ "p"(パラグラフ要素)を探し最初に見つかった要素を返す。
文書への操作は、ツリーの枝葉に当たる要素に降下することで行われる。
探したP要素の.firstChildプロパティで「内容」を得て、nodeValueプロパティで値(テキスト文字列)「DOM TEST」を得ている。
html要素の下にはhead要素とbody要素があるので、まずbody要素を取得するためにgetElementsByTagNameメソッドでbody要素をHTMLCollectionに入れて返す。
そしてbody要素は1つしか存在しないので、取得できたbody要素のHTMLCollectionの最初の要素を取得する。
ここまでくればあとの動作は簡単なので、同じようにdiv要素、p要素の中身をgetElementsByTagNameメソッドを使って手繰って行き、最後にp要素の中身の最初の中身、つまりは「DOM TEST」のテキストを取得している。
 
それぞれのメソッドとプロパティの解説を行うと、
 
; Document.querySelector(CSSセレクタ)
; getElementsByTagName("タグ名")
: 子要素から、"CSSセレクグ名" と一致する要素を探してHTMLCollectionElementとして返す
; item(n)
: HTMLCollectionからn番目の要素を取り出す
; firstChild()
: 最初の子要素を返す
98 ⟶ 86行目:
: 要素内のデータを取り出す
 
この様に、ツリーを降下していくこCSSセレクタにより、目標の要素に辿り着いて、その後にそこElementオブジェクトプロパティを組み合わせ情報を読み出したり変更したりする。
そのため、DOMプログラムでは目的の1つあるいは複数の要素をCSSセレクタでどの様に表すかが重要になり、これは丁度CSSでスタイルシートを記述する時にCSSでプロパティを適用する要素を適切なCSSセレクタで記述する行為と対応している(CSSで書いたセレクタはそのまま/querySelector(All)?/で使えるので、スタイルシートでセレクタの意味を背景色を変えてみるなどの方法で確認できる)。
そのため、DOMプログラムでは、自分がいま文書内のどのNodeを操作しているかをイメージ出来る様になる事が重要である。
 
=== 基本的単語の解説 ===
 
DOMはその名の中にある「ドキュメント」「オブジェクト」「モデル」の名の通り、XMLの各部分をオブジェクト(モノ)として分割して、それぞれを参照して扱える様にする方法である。XML内部には、タグで区切られた数々のデータがあり、それぞれを種類分けしてプログラムで扱っている。その中でも特によく使うDOMのデータ型は次の3種類である。
 
113 ⟶ 100行目:
: DOM 要素の属性へのインターフェース
 
JavaScriptによるWebプログラミングでは、目的と成る成分を指定し、値を取り出したり変更して希望する処理を実現することとなり。
最終的には、これらのデータのある、場所まで辿りついて、その部分のデータを加工する事を続けるのがJavaScriptによるWebプログラミングになる。
 
=== DOM-HTML拡張 ===
 
DOMは、XMLを広くカバーする仕様となっているが、特にHTMLに関しての特別の拡張が行われており、簡潔な書式でHTMLの機能を呼び出せるようになっている。この拡張の中でよく使うのが次の2つである。
 
=== document.getElementByIdquerySelector ===
document.getElementByIdquerySelectorはDOMプログラミングを実際に行う際に最もよく使う機能で、指定したIDCSSセレクタのHTML要素を参照することが出来る。
 
document.getElementByIdはDOMプログラミングを実際に行う際に最もよく使う機能で、指定したIDのHTML要素を参照することが出来る。
具体的には、
 
<syntaxhighlight lang="js">
var elem = document.getElementByIdquerySelector("#sample");
elem.firstChild.nodeValue = "てすと";
</syntaxhighlight>
とする事で、sampleというidを打ったHTML要素の内部のテキスト表示を置き換える事が出来る。
 
=== document.bodyquerySelectorAll ===
とする事で、sampleとidを打ったHTML要素の内部のテキスト表示を置き換える事が出来る。
document.querySelectorはDOMプログラミングを実際に行う際に最もよく使う機能で、指定したCSSセレクタに合致するHTML要素をすべて返す。
 
=== document.body ===
 
これは、実際に使用する際には、
 
'''コード例'''
<syntaxhighlight lang="js">
const elms = document.getElementsByTagNamequerySelectorAll("bodyli")[0];
elms.forEach(el => el.style.color="red");
</syntaxhighlight>
発見されたLI要素の文字色を赤にします。
 
{{コラム|DOMとCSSセレクタの影響|2=
HTML+CSS+JavaScriptの技術基盤に基づくウェブコンテンツ制作においてHTML要素を指定する方法がCSS=[[CSS/記述#セレクタ|CSSセレクタ]]とDOM=getElementsBy*系メソッドと2つの異なる記法になってしましました。
このことは実装を複雑にし、誤解からバグの入り込む余地がでてきました。
 
この様な状況で、要素をCSSセレクタで指定出来るjQueryなどのフレームワークがもてはやされてきました。
と等価である。
 
実際のコードを見てみましょう
{{コラム|CSSセレクタの影響|
2021年6月現在のHTML5+CSS3+JavaScript(ES6+)に基づくウェブフロントエンド技術では、
CSSとDOMで要素を指定する方法が、CSSセレクタとgetElementsBy*系メソッドと2種類あるのは実装を複雑にし、誤解からバグの入り込む余地が増えます。
この様な状況で、jQueryなどのフレームワークがもてはやされてきました。
<source lang="js">
document.getElementById("sample");
</source>
jQueryでは、
<source lang="js">
$("#sample");
</source>
とCSSセレクタの書式で要素(へのラッパー)を得る等価な処理ができます。<br>
ただこの方法では、ラッパーが間に入る続けるので冗長です<ref>このおかげでメソッドチェーンが使えるのですが。</ref>。
 
DOMもこの状況をに対し、CSSセレクタで要素を返すメソッド Document.querySelector() を用意しました<ref>[https://dom.spec.whatwg.org/#dom-parentnode-queryselector DOM
この状況を憂慮して、DOMにもCSSセレクタで要素を返すメソッドDocument.querySelector()とDocument.querySelectorAll()が追加されました<ref>[https://dom.spec.whatwg.org/#dom-parentnode-queryselector DOM Living Standard::4.2.6. Mixin ParentNode -- The querySelector(selectors) method steps are to return the first result of running scope-match a selectors string selectors against this, if the result is not an empty list; otherwise null.] </ref>。
<source lang="js">
document.querySelector("#sample");
</source>
Document.querySelectorは、Document.getElementByIdと同じくElementオブジェクトを返します。
 
同様に、<code>document.body</code>プロパティは、<code>document.querySelector("body")</code>と同値です。
 
いままで、DOMを理解することはTree構造から特定の要素(または要素コレクション)を「濾し取る」事が主でしたが、Document.querySelectorメソッド及びDocument.querySelectorAllメソッドの登場で、CSSと同じセレクタで記述することができるようになり「スタイルシートとスクリプトで同じ要素を指定する手段が異なる」という捻じれ構造を是正することができました。
----
 
また、従来
<source lang="js">
;const li = document.getElementsByTagName("タグ名li");
for (let i = 0, len = li.length; i < len; i++) {
// li[i]に対する処理
}
</source>
を、Arrayイテレータを使い
<source lang="js">
const li = document.querySelectorAll("li");
li.forEach(el => /* elに対する処理 */)
</source>
と簡素に反復処理を行うことが可能となりました。
}}
*ノードの概念
203 ⟶ 206行目:
{{コラム|メモリ内部でのDOMデータ|
DOMを正しく使おうと思えば最終的には何故DOMのオブジェクトシステムはこの様に出来ているのか?
ということを理解する必要がある。DOMはXML文書を解析してその内容をメモリ上に展開するときコレクション同士がツリー状に繋がっている。既にJava等でデザインパターンを修得している上級者には[[w:Composite パターン|Composite パターン]]を取っていると言えば分かっていただけるであろう(より平易言葉で言うとデータがRoot(幹)から枝・葉の様につながった[[w:木構造_(データ構造)|木構造]]です)。DOMに存在する種々の「データ型」というのは、これの先にある様々な枝が何処でどう繋がれるのかを想像しながら使うものである。使っていく内に実感が追いついて慣れていくと思うが、初学者にはそこまでが単純ではないので頑張って欲しい。
}}