JavaScriptによるスライドショー作成 その1

こんにちは。
今回はJavaScriptを使ってスライドショーを作っていきます。

## 完成版
完成版のイメージはこちらになります。
![animegif01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478298/9596fb59-61e4-46c1-83e3-fd53366b3bd3.gif)

サムネイルの画像をクリックしたらメイン画像が切り替わり、「<」、「>」ボタンをクリッタしたらその画像を、そして「Play」を押したら自動再生し、「Stop」ボタンで止まるという仕様です。
メイン画像の上には、画像の色の名前を、下にはカラーコードが入ります。

## HTML
いつも通り、細かいCSSとかは飛ばして、HTMLタグはこちらになります。

```HTML:HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>スライドショー</title>
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div class="container">
    <main>
    <p class="name"></p> <!-- 色の名前表示エリア -->
      <img> <!-- メイン画像 -->
    <p class="color"></p> <!-- カラーコード表示エリア -->
    </main>

    <nav>
      <ul>
        <li id="play">Play</li> <!-- Playボタン -->
        <li id="pause" class="hidden">Pause</li> <!-- Stopボタン -->
        <li id="prev">&lt;</li> <!-- 前へボタン -->
        <li id="next">&gt;</li> <!-- 次へボタン -->
      </ul>
    </nav>

    <ul class="thumbnails"></ul> <!-- サムネイル表示エリア -->
  </div>
  <script src="js/main.js"></script>
</body>
</html>

```

ではJavaScriptを書いていきます。

## 配列を作ってメイン画像を表示する
ではまず表示させる画像を配列にします。
各画像には、画像のURLと色の名前、カラーコードを持っています。
配列名は`images`にでもしておきましょう。

```JavaScript:JavaScript
  let images = [
    {url: 'img/pic00.jpg', txt: {name: '紺瑠璃', color: '#164a84'},},
    {url: 'img/pic01.jpg', txt: {name: '天色', color: '#2ca9e1'},},
    {url: 'img/pic02.jpg', txt: {name: '翡翠色', color: '#38b48b'},},
    {url: 'img/pic03.jpg', txt: {name: '浅緑', color: '#88cb7f'},},
    {url: 'img/pic04.jpg', txt: {name: '萌黄', color: '#aacf53'},},
    {url: 'img/pic05.jpg', txt: {name: '山吹茶', color: '#c89932'},},
    {url: 'img/pic06.jpg', txt: {name: '一斤染', color: '#f5b199'},},
    {url: 'img/pic07.jpg', txt: {name: '浅蘇芳', color: '#a25768'},},

  ]
```

そして今何番目の画像を表示しているかを管理するため、`currentNum`を用意し、デフォルトを0にしておきましょう。
そしてとりあえず0番をメインに表示させます。

```JavaScript:JavaScript
  let currentNum = 0; // 今何番目の画像を表示しているか

  ddocument.querySelector('main img').src = images[currentNum].url; // メイン画像を表示
```
はい、では次はサムネイルです。

## サムネイルを表示する

サムネイルはメイン画像の下、`<ul class="thumbnails">`の中に`<li>`要素ごと作って並べます。
まずは要素の取得です。

```JavaScript:JavaScript
  const thumbnails = document.querySelector('.thumbnails'); // thumbnails要素の取得
```
そして、これに対し配列`images`の数だけループを回して要素を生成していきます。
生成する要素は`<li>`と`<img>`です。

```JavaScript:JavaScript
  const thumbnails = document.querySelector('.thumbnails');

  images.forEach(image => { // 配列のループ
    const li = document.createElement('li'); // <li>要素を生成
    const img = document.createElement('img'); // <img>要素を生成
    img.src = image.url; // 生成した<img>のsrc属性に、各要素の値をセットする
    li.appendChild(img); // その<img>を<li>の子要素として
    thumbnails.appendChild(li); // その<li>をthumbnailsnの子要素として追加する
  });
```
ひとまずこれでサムネイルが表示されます。
そして、今何番の画像を表示しているかというのをわかりやすくするため、currentクラスを`<li>`につけていくために、forEachの引数にindexを追加します。

それを使って、**もしindexがcurrrentNumと同じだったら、<li>要素にcurrentクラスを追加する**というif文も書きましょう。

```JavaScript:JavaScript
  const thumbnails = document.querySelector('.thumbnails');

  images.forEach((image, index) => { // インデックスを追加
    const li = document.createElement('li');
    if (index === currentNum) { // indexがcurrrentNumと同じだったら
      li.classList.add('current'); // currentクラスを追加する
    }
    const img = document.createElement('img');
    img.src = image.url;
    li.appendChild(img);
    thumbnails.appendChild(li);
  });
```
これでひとまずOKです。


## サムネイルをクリックしたらメイン画像も切り替える

生成した`<li>`要素にクリックイベントを追加して、メイン画像を切り替えます。
その処理は`setMainImage`として別の関数としてまとめましょう。
その際の引数は`image`として渡します。

```JavaScript:JavaScript
  images.forEach((image, index) => {
    const li = document.createElement('li');
    if (index === currentNum) {
      li.classList.add('current');
    }

    li.addEventListener('click', () => {
      setMainImage(image); // メイン画像切り替え関数呼び出し
    });

    const img = document.createElement('img');
    img.src = image.url;
    li.appendChild(img);
    thumbnails.appendChild(li);
  });
```

`setMainImage`関数は上記より上に書きましょう。

```JavaScript:JavaScript
  function setMainImage(image) { // メイン画像切り替え関数
    document.querySelector('main img').src = image.url; // 受け取ったimageで書き換える
  });

  document.querySelector('main img').src = images[currentNum].url;
```

ここでよく見ると、今作った関数は最初に書いたメイン画像セットの処理にも使えるので以下のようにしましょう。


```JavaScript:JavaScript
  function setMainImage(image) {
    document.querySelector('main img').src = image.url;
  });

  setMainImage(images[currentNum]); // setMainImageを使って書き換える
```


ここで書き換える際につまづいたところを書きます。

#### ミスしたところ
前：`document.querySelector('main img').src = images[currentNum].url;`
なんだから
後：`setMainImage(images[currentNum].url);`
だろうと、何も考えずに`.url`をつけてしまってエラー出てしまいました。

setMainImage関数の中で`.src`に対して`.url`をセットしているので、呼び出す際には必要ないんですよね。
呼び出す側は引数として今何番目のインデックスだけ渡せば、setMainImage関数の中で処理するようになっている。私はこういうミスをしがちなので、気をつけたいです。


## メイン画像に付随した文言を表示させる

配列を見たとおり、画像のURLだけでなく、オブジェクト化されたデータが入っています。
それを表示させましょう。

各要素を取得し、表示させます。

```JavaScript:JavaScript
  const name = document.getElementsByClassName('name'); // name要素を取得
  const color= document.getElementsByClassName('color'); // color要素を取得
  function setMainImage(image) {
    document.querySelector('main img').src = image.url;
    document.querySelector('main .name').textContent = `${image['txt'].name}`; // nameを表示
    document.querySelector('main .color').innerHTML = `カラーコード：<strong>${image['txt'].color}</strong>`; // カラーコードを表示
  }
```
ここで`textContent`と`innerHTML`の違いについて説明します。
簡単に言うと、**htmlタグの処理の違い**です。前者はタグを書いてもそのままテキストとして表示され、後者はhtmlタグとして反映されます。
今回`<strong>`を使いたかったので、カラーコードは`innerHTML`を使いました。

また、`innerText`というものも存在します。これも`textContent`同様、タグをそのまま文言として表示します。
違いはあるのですが、それほど気にせずに使っています。詳しく知りたい方は調べていただけるとたくさん出てくると思います。




## カレントを移動させる
カレントクラスをつけたり外したりする処理を書きます。
では、まずどのようなタイミングでその処理が発生するか考えると、クリックした時になります。
なので、`image.forEach`内のclickイベント内にその処理を追記しましょう。具体的には
1.カレントクラスを外す
2.カレントナンバーを更新する
3.カレントクラスを追加する
です。


```JavaScript:JavaScript
    li.addEventListener('click', () => {
      setMainImage(image);
      removeCurremtClass(); // カレントクラスを外す関数
      currentNum = index; // カレントナンバーを更新する
      addCurremtClass(); // カレントクラスを追加する関数
    });
```
このように書いて、removeCurremtClass関数とaddCurremtClass関数を別に用意しましょう。


```JavaScript:JavaScript
  function removeCurremtClass() { // カレントクラスを外す関数
    document.querySelectorAll('.thumbnails li')[currentNum] // 現在のcurrentNum番目の<li>から
        .classList.remove('current'); // currentクラスを外す
  }
  function addCurremtClass() { // カレントクラスを追加する関数
    document.querySelectorAll('.thumbnails li')[currentNum] // 新しいcurrentNum番目の<li>に
        .classList.add('current'); // currentクラスを追加する
  }
```
以上で、選択されているサムネイルをカレントクラスにすることができました。

少し長くなってきたので、その2に移動します。https://qiita.com/amanomunt/items/79e331764d817ac33638


## ここまでのコード

```JavaScript:JavaScript
'use strict';

{
  let images = [
    {url: 'img/pic00.jpg', txt: {name: '紺瑠璃', color: '#164a84'},},
    {url: 'img/pic01.jpg', txt: {name: '天色', color: '#2ca9e1'},},
    {url: 'img/pic02.jpg', txt: {name: '翡翠色', color: '#38b48b'},},
    {url: 'img/pic03.jpg', txt: {name: '浅緑', color: '#88cb7f'},},
    {url: 'img/pic04.jpg', txt: {name: '萌黄', color: '#aacf53'},},
    {url: 'img/pic05.jpg', txt: {name: '山吹茶', color: '#c89932'},},
    {url: 'img/pic06.jpg', txt: {name: '一斤染', color: '#f5b199'},},
    {url: 'img/pic07.jpg', txt: {name: '浅蘇芳', color: '#a25768'},},

  ]


  let currentNum = 0;

  const name = document.getElementsByClassName('name');
  const color= document.getElementsByClassName('color');
  function setMainImage(image) {
    document.querySelector('main img').src = image.url;
    document.querySelector('main .name').textContent = `${image['txt'].name}`;
    document.querySelector('main .color').innerHTML = `カラーコード：<strong>${image['txt'].color}</strong>`; 
  }

  setMainImage(images[currentNum]);

  function removeCurremtClass() {
    document.querySelectorAll('.thumbnails li')[currentNum].classList.remove('current');
  }
  function addCurremtClass() {
    document.querySelectorAll('.thumbnails li')[currentNum].classList.add('current');
  }
  
  const thumbnails = document.querySelector('.thumbnails');

  images.forEach((image, index) => {
    const li = document.createElement('li');
    if (index === currentNum) {
      li.classList.add('current');
    }
    li.addEventListener('click', () => {
      setMainImage(image);
      removeCurremtClass();
      currentNum = index;
      addCurremtClass();
    });

    const img = document.createElement('img');

    img.src = image.url;
    li.appendChild(img);
    thumbnails.appendChild(li);
  });
}

```