DOMナビゲーションプロパティは、要素が互いに近い場合に最適です。そうでない場合はどうでしょうか?ページの任意の要素を取得するにはどうすればよいでしょうか?
そのためには、追加の検索方法があります。
document.getElementById または単に id
要素に id
属性がある場合、その場所に関わらず、document.getElementById(id)
メソッドを使用して要素を取得できます。
例えば
<div id="elem">
<div id="elem-content">Element</div>
</div>
<script>
// get the element
let elem = document.getElementById('elem');
// make its background red
elem.style.background = 'red';
</script>
また、要素を参照する id
という名前のグローバル変数もあります。
<div id="elem">
<div id="elem-content">Element</div>
</div>
<script>
// elem is a reference to DOM-element with id="elem"
elem.style.background = 'red';
// id="elem-content" has a hyphen inside, so it can't be a variable name
// ...but we can access it using square brackets: window['elem-content']
</script>
…ただし、同じ名前のJavaScript変数を宣言した場合、それが優先されます。
<div id="elem"></div>
<script>
let elem = 5; // now elem is 5, not a reference to <div id="elem">
alert(elem); // 5
</script>
この動作は仕様書に記載されていますが、主に互換性のためにサポートされています。
ブラウザはJSとDOMの名前空間を混在させることで私たちを助けようとしています。これはHTMLにインライン化された単純なスクリプトには適していますが、一般的には良いことではありません。名前の競合が発生する可能性があります。また、JSコードを読んでHTMLが表示されていない場合、変数がどこから来たのか明らかではありません。
このチュートリアルでは、要素の出所が明らかな場合、簡潔にするために id
を使用して要素を直接参照します。
実際には document.getElementById
が推奨される方法です。
id
は一意である必要がありますid
は一意である必要があります。ドキュメント内に同じ id
を持つ要素は1つだけ存在できます。
同じ id
を持つ要素が複数ある場合、それを使用するメソッドの動作は予測できません。たとえば、document.getElementById
はそのような要素のいずれかをランダムに返す可能性があります。そのため、ルールを守り、id
を一意にしてください。
document.getElementById
のみ、anyElem.getElementById
は不可getElementById
メソッドは、document
オブジェクトに対してのみ呼び出すことができます。ドキュメント全体で指定された id
を検索します。
querySelectorAll
最も汎用性の高いメソッドである elem.querySelectorAll(css)
は、指定された CSS セレクターに一致する elem
内のすべての要素を返します。
ここでは、最後のchilsであるすべての <li>
要素を探します
<ul>
<li>The</li>
<li>test</li>
</ul>
<ul>
<li>has</li>
<li>passed</li>
</ul>
<script>
let elements = document.querySelectorAll('ul > li:last-child');
for (let elem of elements) {
alert(elem.innerHTML); // "test", "passed"
}
</script>
このメソッドは、あらゆる CSS セレクターを使用できるため、非常に強力です。
CSS セレクターの ` :hover ` や `:active` のような疑似クラスもサポートされています。例えば、`document.querySelectorAll(':hover')` は、ポインターが現在上にある要素のコレクションを返します(ネスト順:最も外側の `` から最もネストされたものまで)。
querySelector
elem.querySelector(css)
の呼び出しは、指定された CSS セレクターの最初の要素を返します。
言い換えれば、結果は `elem.querySelectorAll(css)[0]` と同じですが、後者は*すべて*の要素を探して1つを選んでいますが、`elem.querySelector` は1つだけを探します。そのため、高速で、書くのも短くなります。
matches
以前のメソッドはDOMを検索していました。
elem.matches(css) は何も探しませんが、単に `elem` が指定された CSS セレクターに一致するかどうかをチェックします。`true` または `false` を返します。
このメソッドは、要素を反復処理し(配列など)、関心のある要素をフィルタリングする場合に便利です。
例えば
<a href="http://example.com/file.zip">...</a>
<a href="http://ya.ru">...</a>
<script>
// can be any collection instead of document.body.children
for (let elem of document.body.children) {
if (elem.matches('a[href$="zip"]')) {
alert("The archive reference: " + elem.href );
}
}
</script>
closest
要素の*祖先*は、親、親の親、その親などです。祖先はまとめて、要素から最上位までの親のチェーンを形成します。
メソッド `elem.closest(css)` は、CSS セレクターに一致する最も近い祖先を探します。`elem` 自体も検索に含まれます。
言い換えれば、`closest` メソッドは要素から上に移動し、各親をチェックします。セレクターに一致する場合、検索は停止し、祖先が返されます。
例えば
<h1>Contents</h1>
<div class="contents">
<ul class="book">
<li class="chapter">Chapter 1</li>
<li class="chapter">Chapter 2</li>
</ul>
</div>
<script>
let chapter = document.querySelector('.chapter'); // LI
alert(chapter.closest('.book')); // UL
alert(chapter.closest('.contents')); // DIV
alert(chapter.closest('h1')); // null (because h1 is not an ancestor)
</script>
getElementsBy*
タグ、クラスなどでノードを検索する他の方法もあります.
今日では、`querySelector` の方が強力で書くのが短いため、ほとんどが歴史的なものです。
そのため、ここでは主に完全性のために説明しますが、古いスクリプトではまだ見つけることができます.
- `elem.getElementsByTagName(tag)` は、指定されたタグを持つ要素を探し、それらのコレクションを返します。`tag` パラメータは、「任意のタグ」を表すアスタリスク `"*"` にすることもできます。
- `elem.getElementsByClassName(className)` は、指定された CSS クラスを持つ要素を返します。
- `document.getElementsByName(name)` は、指定された `name` 属性を持つ要素をドキュメント全体で返します。めったに使用されません。
例えば
// get all divs in the document
let divs = document.getElementsByTagName('div');
テーブル内のすべての `input` タグを見つけましょう
<table id="table">
<tr>
<td>Your age:</td>
<td>
<label>
<input type="radio" name="age" value="young" checked> less than 18
</label>
<label>
<input type="radio" name="age" value="mature"> from 18 to 50
</label>
<label>
<input type="radio" name="age" value="senior"> more than 60
</label>
</td>
</tr>
</table>
<script>
let inputs = table.getElementsByTagName('input');
for (let input of inputs) {
alert( input.value + ': ' + input.checked );
}
</script>
初心者の開発者は、`s` の文字を忘れることがあります。つまり、`getElementsByTagName` の代わりに `getElementByTagName` を呼び出そうとします.
`getElementById` には `s` の文字がありません。これは、単一の要素を返すためです。しかし、`getElementsByTagName` は要素のコレクションを返すため、内部に `s` があります.
もう1つの広く見られる初心者の間違いは、次のように書くことです.
// doesn't work
document.getElementsByTagName('input').value = 5;
これは機能しません。*コレクション* の入力を取得し、内部の要素ではなく、それに値を割り当てるためです.
コレクションを反復処理するか、インデックスで要素を取得してから、次のように割り当てる必要があります.
// should work (if there's an input)
document.getElementsByTagName('input')[0].value = 5;
`.article` 要素を探す
<form name="my-form">
<div class="article">Article</div>
<div class="long article">Long article</div>
</form>
<script>
// find by name attribute
let form = document.getElementsByName('my-form')[0];
// find by class inside the form
let articles = form.getElementsByClassName('article');
alert(articles.length); // 2, found two elements with class "article"
</script>
ライブコレクション
すべてのメソッド `getElementsBy*` は、*ライブ* コレクションを返します。このようなコレクションは、常にドキュメントの現在の状態を反映し、変更があると「自動更新」されます。
以下の例では、2つのスクリプトがあります。
- 最初のスクリプトは、`<div>` のコレクションへの参照を作成します。現在のところ、その長さは `1` です。
- 2番目のスクリプトは、ブラウザがもう1つの `<div>` に出会った後に実行されるため、その長さは `2` です。
<div>First div</div>
<script>
let divs = document.getElementsByTagName('div');
alert(divs.length); // 1
</script>
<div>Second div</div>
<script>
alert(divs.length); // 2
</script>
対照的に、`querySelectorAll` は*静的* コレクションを返します。要素の固定配列のようなものです.
代わりにそれを使用すると、両方のスクリプトは `1` を出力します.
<div>First div</div>
<script>
let divs = document.querySelectorAll('div');
alert(divs.length); // 1
</script>
<div>Second div</div>
<script>
alert(divs.length); // 1
</script>
これで違いがはっきりとわかります。ドキュメントに新しい `div` が出現した後も、静的コレクションは増加しませんでした。
まとめ
DOM でノードを検索するための主なメソッドは 6 つあります。
メソッド | 検索対象... | 要素で呼び出すことができますか? | ライブ? |
querySelector |
CSS セレクター | ✔ | - |
querySelectorAll |
CSS セレクター | ✔ | - |
getElementById |
id |
- | - |
getElementsByName |
name |
- | ✔ |
getElementsByTagName |
タグまたは `'*'` | ✔ | ✔ |
getElementsByClassName |
クラス | ✔ | ✔ |
最もよく使用されるのは `querySelector` と `querySelectorAll` ですが、`getElement(s)By*` は散発的に役立つ場合や、古いスクリプトで見つかる場合があります.
そのほかに
- `elem` が指定された CSS セレクターに一致するかどうかを確認するための `elem.matches(css)` があります。
- 指定された CSS セレクターに一致する最も近い祖先を探すための `elem.closest(css)` があります。`elem` 自体もチェックされます.
また、子と親の関係を確認するもう1つのメソッドをここで紹介します。これは時々役立つためです.
- `elemA.contains(elemB)` は、`elemB` が `elemA` 内にある(`elemA` の子孫である)場合、または `elemA==elemB` の場合に true を返します。
コメント