🐱

ポートフォリオを作りながら学んだJavaScriptでポケモン画像を表示させるまで(超初心者)

に公開

はじめに

ポートフォリオにポケモンの画像を並べるセクションを作ろうとしたとき、
「画像が表示されない!」という壁にぶつかりました。
原因を調べる過程で学んだことをまとめます。


やりたかったこと

PokeAPIの画像URLを使って、1番〜9番のポケモンを横並びで表示させたい。

[ 🖼 ][ 🖼 ][ 🖼 ][ 🖼 ][ 🖼 ][ 🖼 ][ 🖼 ][ 🖼 ][ 🖼 ]
  1番   2番   3番   4番   5番   6番   7番   8番   9番

最初のコード(動かなかった)

for (let i = 1; i <= 9; i++) {
  const pokemon = document.createElement('div');
  pokemon.classList.add('pokemon');

  const newImg = document.createElement('img');
  newImg.src = 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png'
}

このコードには2つのミスがありました。


ミスポイント① 画像のURLが固定になっていた

URLの末尾が 1.png のまま固定になっていたので、9回ループしても全部1番のポケモンになってしまいます。

// ❌ before:ずっと1番のポケモン
newImg.src = 'https://.../pokemon/1.png'

// ✅ after:iの数字をURLに埋め込む
newImg.src = `https://.../pokemon/${i}.png`

バッククォートと${}について

通常のクォート('")の代わりに**バッククォート(`)**を使うと、
${} の中に変数を入れて文字列に埋め込むことができます。

let i = 3;
console.log(`pokemon/${i}.png`); // → "pokemon/3.png"
console.log('pokemon/' + i + '.png'); // 同じ意味だけど長い

バッククォートを使う書き方をテンプレートリテラルといいます。


ミスポイント② 作った要素をHTMLに追加していなかった

createElement で要素を作っても、appendChild でHTMLに追加する命令を書かないと画面に表示されません。

「部品を作る」だけでは画面には出てこない、というイメージです。

// ❌ before:作るだけで追加していない
const pokemon = document.createElement('div');
const newImg = document.createElement('img');
// → 画面には何も表示されない!

// ✅ after:appendChildで追加する
pokemon.appendChild(newImg);   // divの中にimgを入れる
section.appendChild(pokemon);  // sectionの中にdivを入れる

修正後の完成コード

// ①HTMLから id="pokemon" のセクションを取得して、sectionという名前で呼べるようにする
const section = document.getElementById('pokemon');

// ②1〜9までループする
for (let i = 1; i <= 9; i++) {

  // ③<div>タグを新しく作る(まだ画面には表示されていない)
  const pokemon = document.createElement('div');

  // ④作ったdivに class="pokemon" をつける(CSSを当てるための準備)
  pokemon.classList.add('pokemon');

  // ⑤<img>タグを新しく作る(まだ画面には表示されていない)
  const newImg = document.createElement('img');

  // ⑥imgのsrc(画像URL)をセット。${i}にループの番号が入る
  //   i=1のとき → 1.png、i=2のとき → 2.png… と変わる
  newImg.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${i}.png`;

  // ⑦divの中にimgを入れる → <div><img></div> という形になる
  pokemon.appendChild(newImg);

  // ⑧sectionの中にdivを追加する → ここで初めて画面に表示される!
  section.appendChild(pokemon);
}

1回のループでやっていること

① <div> を作る
② <div> に class をつける(CSS用)
③ <img> を作る
④ <img> に i番のポケモンのURLをセット
⑤ <div> の中に <img> を入れる
⑥ セクションに <div> を追加 → 画面に表示!

これを i = 1〜9 の9回繰り返す

なぜdivが必要なの?

実はdivがなくてもimgだけで画像は表示できます。

// divなしでも動く
const newImg = document.createElement('img');
newImg.src = `.../${i}.png`;
section.appendChild(newImg);

divを使う理由は、CSSでスタイルを当てやすくするためです。
たとえば将来ポケモンの名前を追加したくなったとき、divがあるとimgpをまとめて管理できます。

// divがあると画像と名前をひとまとめにできる
pokemon.appendChild(newImg);

const name = document.createElement('p');
name.textContent = `No.${i}`;
pokemon.appendChild(name);
【divあり】           【divなし】
┌─────────┐          🖼 🖼 🖼 🖼 🖼
│  🖼     │          No.1 No.2 ...
│  No.1  │          ← imgとテキストがバラバラになりやすい
└─────────┘
┌─────────┐
│  🖼     │
│  No.2  │
└─────────┘

今回みたいに画像だけでいいならdivなしでもOK。
将来的に情報を追加するかもしれないときはdivでまとめておくと便利です。


CSSのタイポも直した

/* ❌ before:コロンが2つになっていた */
.pokemon img {
  display: :block;
}

/* ✅ after */
.pokemon img {
  display: block;
}

コロンが2つ(: :)になっていてCSSが効いていなかった。
こういう小さなタイポがバグの原因になるので注意!


まとめ

  • createElement で要素を作るappendChild追加するの2ステップが基本
  • URLに変数を埋め込むときはバッククォート(`)と ${} を使う(テンプレートリテラル)
  • createElement しただけでは画面に表示されない、appendChild を忘れずに!
  • divは「まとめて管理するための箱」、画像だけならなくてもOK
  • CSSのタイポ(: が2つなど)はバグの原因になるので注意

Discussion