要素を取得する

このレッスンで分かること

  • 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 もまわせます。ただし配列そのものではないので、mapfilter は使えません。第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> になる

複数の要素に付けたいときは、querySelectorAllforEach を組み合わせます。

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、と使い分けます。

課題

  1. document.querySelector("h1") で見出しを掴み、setAttributedata-found"1" にする
  2. .taglinequerySelector で掴み、同じように data-found"1" にする
  3. document.getElementById("works") で作品セクションを掴み、data-found"1" にする
  4. querySelectorAll(".work-card") で 3 枚のカードを掴み、forEach で 1 枚ずつ data-found"1" にする

ヒント

index.html
style.css
script.js
プレビュー

できているか

  • h1 に data-found が付く
  • .tagline に data-found が付く
  • #works に data-found が付く
  • 3 枚の作品カード全部に data-found が付く