要素を取得する
このレッスンで分かること
querySelectorで要素を 1 つ取り出す書き方querySelectorAllが返す NodeList の扱い方- 取れなかったときに返る
nullの見分け方
要素を取得する とは
DOM の中からほしい要素を掴む操作です。CSS で書いてきたセレクタをそのまま使って、
documentから 1 つ、あるいは全部を取り出します。
まず掴まないと何も始まらない
DOM の操作は、いつも同じ 2 段階でできています。掴む、そして変える。文字を変えるにも色を変えるにも、先に「どれを」を決めなければいけません。その「どれを」を決めるのが querySelector です。
const pageTitle = document.querySelector("h1");document はページ全体でした。そこから h1 に当たるものを探して、最初に見つかった 1 つを返します。返ってきたものは要素オブジェクトで、変数に入れておけば何度でも使えます。
うれしいのは、丸かっこの中がそのまま CSS のセレクタだということです。CSS で .work-card と書けば作品カードに当たったように、JavaScript でも .work-card で当たります。新しい記法を覚え直す必要はありません。
document.querySelector("h1"); // タグ名
document.querySelector(".tagline"); // クラス
document.querySelector("#works"); // id
document.querySelector("#works .section-title"); // 子孫をたどる
document.querySelector('input[type="email"]'); // 属性セレクタは文字列なので、必ず引用符で囲みます。
document.querySelector(.tagline)のようにクォートを忘れると構文エラーになります。属性セレクタのように中で二重引用符を使うときは、外側を単引用符にすると読みやすくなります。
1 つ取るか、全部取るか
querySelector は最初の 1 つしか返しません。プロフィールサイトには .work-card が 3 つありますが、次の書き方で返るのは 1 枚目だけです。
const one = document.querySelector(".work-card"); // 1 枚目だけ3 枚とも欲しいときは querySelectorAll を使います。返ってくるのは NodeList という、当たった要素が順番に並んだものです。
const cards = document.querySelectorAll(".work-card");
console.log(cards.length); // 3
cards.forEach((card) => {
console.log(card);
});NodeList は配列によく似ています。length があり、cards[0] で番号を指定でき、forEach もまわせます。ただし配列そのものではないので、map や filter は使えません。第6章で練習した forEach がそのまま効くので、この章ではそれで足ります。
| 書き方 | 返るもの | 見つからないとき |
|---|---|---|
querySelector(sel) | 最初に当たった要素 1 つ | null |
querySelectorAll(sel) | NodeList (0 個以上) | 空の NodeList |
getElementById(id) | id が一致する要素 1 つ | null |
getElementsByClassName(cls) | HTMLCollection | 空の HTMLCollection |
getElementById は id 専用の古くからある書き方です。# を付けずに document.getElementById("works") と書きます。速さの差は今のページの規模ではまず体感できないので、どちらを使っても構いません。ただし querySelector は id もクラスも子孫も 1 つの書き方で扱えるので、迷ったらこちらにそろえるのが楽です。
取れなかったときは null が返る
つまずきどころはここです。当たらなかったとき、querySelector はエラーを出さずに null を返します。エラーが出るのは、その null を使おうとした次の行です。
// #work という id はサイトに無い
const gallery = document.querySelector("#work");
console.log(gallery); // null
gallery.setAttribute("x", "1"); // TypeError になるコンソールには Cannot read properties of null と出ます。この文言を見たら、セレクタの綴りが違うか、そもそも存在しないと考えてください。第1章でエラーの読み方を練習したのはこのためです。
// 確かめてから使う
const gallery = document.querySelector("#works");
if (gallery === null) {
console.log("見つかりませんでした");
} else {
gallery.setAttribute("data-found", "1");
}
nullは第2章で出てきた「意図して空っぽ」を表す値でした。DOM の世界では「探したけれど無かった」という返事に使われます。第7章の?.を使ってgallery?.setAttribute(...)と書けば、無いときは何もしないという書き方もできます。
掴めたことを目に見える形にする
今回は、掴めたかどうかを画面から確かめられるように、掴んだ要素へ属性を 1 つ付けます。使うのが setAttribute です。
element.setAttribute("属性名", "値");setAttribute("data-found", "1") と書くと、その要素に data-found="1" が付きます。data- で始まる属性はデータ属性と呼ばれ、開発者が自由に付けてよい決まりになっています。見た目は何も変わりませんが、検証ツールの Elements タブを開けば、狙った要素にだけ印が付いているのが分かります。
const tagline = document.querySelector(".tagline");
tagline.setAttribute("data-found", "1");
// <p class="tagline" data-found="1">…</p> になる複数の要素に付けたいときは、querySelectorAll と forEach を組み合わせます。
const cards = document.querySelectorAll(".work-card");
cards.forEach((card) => {
card.setAttribute("data-found", "1");
});よくある間違い
セレクタの記号を忘れる
クラスなら .、id なら # が要ります。付け忘れるとタグ名として探しにいくので、当然見つかりません。
document.querySelector("tagline"); // <tagline> タグを探してしまう。null
document.querySelector(".tagline"); // 正しい逆に getElementById では # を付けません。document.getElementById("#works") は当たらないので注意します。
querySelectorAll の結果に直接プロパティを書く
NodeList は要素の入れ物であって、要素そのものではありません。まとめて設定はできません。
const cards = document.querySelectorAll(".work-card");
cards.setAttribute("data-found", "1"); // TypeError
cards.forEach((card) => card.setAttribute("data-found", "1")); // 正しい1 つしか無いのに querySelectorAll を使う
間違いではありませんが、cards[0] と書くところが増えて読みにくくなります。1 つに決まっているなら querySelector、複数を相手にするなら querySelectorAll、と使い分けます。
課題
document.querySelector("h1")で見出しを掴み、setAttributeでdata-foundを"1"にする.taglineをquerySelectorで掴み、同じようにdata-foundを"1"にするdocument.getElementById("works")で作品セクションを掴み、data-foundを"1"にするquerySelectorAll(".work-card")で 3 枚のカードを掴み、forEachで 1 枚ずつdata-foundを"1"にする