一、DOM#
文書オブジェクトモデル (DOM) は HTML
と XML
文書のプログラミングインターフェースです。
それは文書の構造化された表現を提供し、プログラムからその構造にアクセスして文書の構造、スタイル、内容を変更する方法を定義します。
任意の HTML
または XML
文書は DOM
を使用してノードで構成される階層構造として表現できます。
ノードは多くのタイプに分かれており、それぞれのタイプは文書内の異なる情報や(または)マークアップに対応し、独自の特性、データ、メソッドを持ち、他のタイプとの関係があります。以下のように示されます:
<html>
<head>
<title>ページ</title>
</head>
<body>
<p>こんにちは世界!</p >
</body>
</html>
DOM
は原子が亜原子微粒子を含むように、多くのタイプの DOM
ノードが他のタイプのノードを含んでいます。次に、その中の三つを見てみましょう:
<div>
<p title="タイトル">
コンテンツ
</p >
</div>
上記の構造では、div
と p
は要素ノードであり、コンテンツ
はテキストノードであり、タイトル
は属性ノードです。
二、操作#
日常のフロントエンド開発では、私たちは DOM
操作を欠かすことができません。
以前は、Jquery
、zepto
などのライブラリを使用して DOM
を操作していましたが、その後 vue
、Angular
、React
などのフレームワークが登場し、私たちはデータを操作して DOM
を制御することが多くなり、直接 DOM
を操作することは少なくなりました。
しかし、これはネイティブ操作が重要でないことを意味するわけではありません。逆に、DOM
操作はフレームワークの深層の内容を理解するのに役立ちます。
以下に DOM
の一般的な操作を分析します。主に次のように分かれます:
- ノードの作成
- ノードの取得
- ノードの更新
- ノードの追加
- ノードの削除
ノードの作成#
createElement#
新しい要素を作成し、作成する要素のタグ名を受け取ります。
const divEl = document.createElement("div");
createTextNode#
テキストノードを作成します。
const textEl = document.createTextNode("コンテンツ");
createDocumentFragment#
文書の断片を作成するために使用されます。これは軽量の文書を表し、一時的なノードを格納し、文書の断片の内容を一度に DOM
に追加するために主に使用されます。
const fragment = document.createDocumentFragment();
DocumentFragment
ノードを文書ツリーに挿入しようとすると、挿入されるのは DocumentFragment
自体ではなく、そのすべての子孫ノードです。
createAttribute#
属性ノードを作成し、カスタム属性にすることができます。
const dataAttribute = document.createAttribute('custom');
console.log(dataAttribute);
ノードの取得#
querySelector#
任意の有効な css
セレクタを渡すことで、単一の DOM
要素(最初のもの)を選択できます:
document.querySelector('.element')
document.querySelector('#element')
document.querySelector('div')
document.querySelector('[name="username"]')
document.querySelector('div + p > span')
ページ上に指定された要素がない場合、null
を返します。
querySelectorAll#
ノードの子ツリー内のすべての一致する Element
ノードのリストを返します。一致するものがない場合は、空のノードリストを返します。
const notLive = document.querySelectorAll("p");
注意が必要なのは、このメソッドが返すのは NodeList
の静的インスタンスであり、静的な「スナップショット」であって「リアルタイム」のクエリではないということです。
DOM
要素を取得する方法には以下のようなものもありますが、すべてを述べることはしません。
document.getElementById('id属性値');指定されたidを持つオブジェクトの参照を返します。
document.getElementsByClassName('class属性値');指定されたclassを持つオブジェクトの集合を返します。
document.getElementsByTagName('タグ名');指定されたタグ名を持つオブジェクトの集合を返します。
document.getElementsByName('name属性値');指定された名前を持つオブジェクトの集合を返します。
document/element.querySelector('CSS選択子');最初の一致する要素のみを返します。
document/element.querySelectorAll('CSS選択子');すべての一致する要素を返します。
document.documentElement;ページ内のHTMLタグを取得します。
document.body;ページ内のBODYタグを取得します。
document.all[''];ページ内のすべての要素ノードのオブジェクト集合を取得します。
そのほか、各 DOM
要素には parentNode
、childNodes
、firstChild
、lastChild
、nextSibling
、previousSibling
属性があり、関係図は以下のように示されます。
ノードの更新#
innerHTML#
DOM
ノードのテキスト内容を変更するだけでなく、HTML
フラグメントを介して DOM
ノード内部の子ツリーを直接変更することもできます。
// <p id="p">...</p >を取得
var p = document.getElementById('p');
// テキストをabcに設定:
p.innerHTML = 'ABC'; // <p id="p">ABC</p >
// HTMLを設定:
p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
// <p>...</p >の内部構造が変更されました
innerText、textContent#
文字列を自動的に HTML
エンコードし、HTML
タグを設定できないようにします。
// <p id="p-id">...</p >を取得
var p = document.getElementById('p-id');
// テキストを設定:
p.innerText = '<script>alert("Hi")</script>';
// HTMLが自動的にエンコードされ、<script>ノードを設定できません:
// <p id="p-id"><script>alert("Hi")</script></p >
両者の違いは、属性を読み取る際に innerText
は隠れた要素のテキストを返さず、textContent
はすべてのテキストを返すことです。
style#
DOM
ノードの style
属性はすべての CSS
に対応し、直接取得または設定できます。-
に遭遇した場合はキャメルケースに変換する必要があります。
// <p id="p-id">...</p >を取得
const p = document.getElementById('p-id');
// CSSを設定:
p.style.color = '#ff0000';
p.style.fontSize = '20px'; // キャメルケース
p.style.paddingTop = '2em';
ノードの追加#
innerHTML#
この DOM
ノードが空である場合、例えば <div></div>
の場合、innerHTML = '<span>child</span>'
を直接使用することで DOM
ノードの内容を変更でき、新しい DOM
ノードを追加したことになります。
この DOM
ノードが空でない場合は、そうすることはできません。なぜなら innerHTML
は元のすべての子ノードを直接置き換えてしまうからです。
appendChild#
子ノードを親ノードの最後の子ノードとして追加します。
例を挙げると:
<!-- HTML構造 -->
<p id="js">JavaScript</p >
<div id="list">
<p id="java">Java</p >
<p id="python">Python</p >
<p id="scheme">Scheme</p >
</div>
p
要素を追加します。
const js = document.getElementById('js')
js.innerHTML = "JavaScript"
const list = document.getElementById('list');
list.appendChild(js);
現在の HTML
構造は以下のようになります。
<!-- HTML構造 -->
<div id="list">
<p id="java">Java</p >
<p id="python">Python</p >
<p id="scheme">Scheme</p >
<p id="js">JavaScript</p > <!-- 追加された要素 -->
</div>
上記のコードでは、DOM
要素を取得してから追加操作を行っています。この js
ノードはすでに現在の文書ツリーに存在しているため、このノードはまず元の位置から削除され、新しい位置に挿入されます。
新しいノードを動的に追加する場合は、まず新しいノードを作成し、指定された位置に挿入します。
const list = document.getElementById('list');
const haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.appendChild(haskell);
insertBefore#
子ノードを指定された位置に挿入します。使用方法は以下の通りです:
parentElement.insertBefore(newElement, referenceElement)
子ノードは referenceElement
の前に挿入されます。
setAttribute#
指定された要素に属性ノードを追加し、要素にその属性がすでに存在する場合は属性値を変更します。
const div = document.getElementById('id')
div.setAttribute('class', 'white');//最初のパラメータは属性名、二番目のパラメータは属性値です。
ノードの削除#
ノードを削除するには、まずそのノード自体とその親ノードを取得し、親ノードの removeChild
を呼び出して自分自身を削除します。
// 削除対象のノードを取得:
const self = document.getElementById('to-be-removed');
// 親ノードを取得:
const parent = self.parentElement;
// 削除:
const removed = parent.removeChild(self);
removed === self; // true
削除されたノードは文書ツリーには存在しなくなりますが、実際にはメモリ内に残っており、いつでも別の場所に再度追加できます。