【もりけん塾 @JS課題18】Vanilla JSでスライドショー作成③ auto機能を追加する編

JavaScript
管理人
管理人

こんにちは、さえと申します👩‍💻
現在 フロントエンドエンジニアになるために 日々勉強をしています
このブログは その勉強の記録と アウトプットのために運営をしています✨

現在、もりけん塾で
マークアップエンジニアの方がフロントエンドエンジニアになる為の課題に取り組んでいます。
今回は課題18の実装で学んだことをブログへまとめます

前回に引き続きスライドショーの作成です

課題18

3秒毎に次のスライドに自動で切り替わるauto機能を提供してください

制作物

Image from Gyazo
JS_lesson18 part2 - CodeSandbox
JS_lesson18 part2 by sae-code using parcel-bundler

表示中の要素

前回までは 以下の関数を使用して、表示されているスライドのindexを取得していました

const findIndexOfDisplayedItem = () => {
  // スライドを全て取得
  const slideItemArray = [...document.querySelectorAll(".slide-item")];
  // is-displayingクラスを持つ要素のindexを返す
  return slideItemArray.findIndex(el => el.classList.contains("is-displaying"));
}

ですが今回からは 変数で表示中のindexを管理し、状況応じて 値を変更する方法に変更しました
例 ) nexボタンが押された場合は、+1する

/**
 * index of the element being displayed.
 * @type {Number}
 */

let currentIndex = 0;

理由としては、一つの変数で管理した方が明示的になると考えたからです

auto機能

3秒ごとに次のスライドへ切り替えるauto機能を追加しました

let autoPlayerId;
const autoPlay = {
  start: function () {
    autoPlayerId = setInterval(() => {
      // スライドを全て取得
      const slideItems = [...document.querySelectorAll(".slide-item")];
        // 表示中のスライドが最後の要素ではない場合、インクリメントした値を代入、それ以外は0を代入
      currentIndex < slideItems.length - 1 ? ++currentIndex : currentIndex = 0;
     // スライドショー実行
      playOfSlideshow();
    }, 3000);
  },
  reset: function () {
    clearInterval(autoPlayerId);
    this.start();
  }
}

const playOfSlideshow = () => {
// ページネーション切り替え
  switchIndicator(currentIndex);
// スライド切り替え
  switchSlideImg(currentIndex);
//  カウンター更新
  updateOfCounter(currentIndex);
// disabled切り替え
  toggleTheDisabled();
}

autoPlayという変数にオブジェクトを格納しました
オブジェクト内でstratとresetというキーにそれぞれの仕事を紐付けています
startはauto機能を開始し、resetは一度止め、再開させます
アローボタンや、ページネーションがクリックされた場合に、resetを実行しています。

気になる点…

auto機能の部分をオブジェクトにした理由は、
start(開始)とreset(一旦止めて、再開)を切り替えたかった為と、
setIntervalの戻り値である idを干渉し合いたかったので この様にしました。

が…よくよく考えるとautoPlayerIdをグローバルに定義していることで
オブジェクトにしたメリットは無いのでは…?と思いました

JavaScript best practicesを読んでみると、グローバル変数・関数の回避方法が載っていました

JavaScript best practices - W3C Wiki
const autoPlay = function () {
  let autoPlayerId;
  const start = () => {
    autoPlayerId = setInterval(() => {
      const slideItems = [...document.querySelectorAll(".slide-item")];
      currentIndex < slideItems.length - 1 ? ++currentIndex : currentIndex = 0;
      playOfSlideshow();
    }, 3000)
  }
  const reset = () => {
    clearInterval(autoPlayerId);
    start();
  }
  return {
    start,
    reset
  }
}();

この様に 即時関数を使用して書くことを学びました

文字列をNumber型へ変換する

ページネーションがクリックされた場合 currentIndex(表示中のスライドのindex)に data属性で指定した数字を代入します
データ属性へのアクセスは datasetプロパティを使用して行い、値は文字列として取得されます

const setClickEventInIndicator = () => {
  const indicators = document.querySelectorAll(".indicator-item");
  indicators.forEach((indicator) => {
    indicator.addEventListener("click", (e) => {
      autoPlay.reset();
      currentIndex = e.target.dataset.num;  <- ココ
      playOfSlideshow();
    });
  });
};

値が文字列として currentIndexへ格納されるのでカウンターの更新で弊害がありました
以下の関数を実行すると、currentIndex + 1の部分が “文字列 + 1″となり計算がされません

const updateOfCounter = () => {
  /**
   * The counter will display the value of index plus one.
   */
  document.querySelector(".current-number").textContent = currentIndex + 1;
};

currentIndexをNumber型に変え、プラス1した値を表示させたい….

以下の記事を参考に Number型への変換方法を学びました

7 ways to convert a String to Number in JavaScript
1. Using parseInt() parseInt() parses a string and returns a whole number. Spaces are allo...

今回はNumberでラップし 型変換を行いました

const updateOfCounter = () => {
  /**
   * The counter will display the value of index plus one.
   */
  document.querySelector(".current-number").textContent =
    Number(currentIndex) + 1;
};

Missing radix parameter. (radix)

currentIndex = parseInt(e.target.dataset.num);

parseIntを使用すると、codesandboxで警告がでました

該当箇所に波線がひかれ Missing radix parameter. (radix) とあります

下記にまとめた参考記事とドキュメントを読むと
第二引数のradix(基数)を省略した際の挙動が原因とありました


1. 入力した string が “0x” または “0X” (ゼロに続いて小文字または大文字の X) で始まった場合は、radix は 16 と仮定され、残りの文字列が 16 進数として解釈されます。
2. 入力した string がその他の値で始まるときは、基数は 10 (10 進数) となります。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseInt

また以前の仕様では 0 で始まる数字の文字列を 8 進数として解釈していたともありました(現在は廃止されている)
こういった背景もあり、基数を指定することで予期せぬ変換を防ぐための警告だそうです。

この様にすることで、警告は消えました

currentIndex = parseInt(e.target.dataset.num,10);

parseInt() - JavaScript | MDN
parseInt() 関数は、文字列の引数を解析し、指定された基数 (数学的記数法の底) の整数値を返します。

まとめ

課題17~18でスライドショーの作成・機能追加を実装しましたが
機能を後から追加していくことの難しさを感じました。

レビューしてくれた皆さんありがとうございました!
thanks 💛 …. もなかさん(@ruby443n) はるさん(@fuwafuwahappy) yukaさん(@mamuuu08)

また課題19では、以前課題16で実装したタブメニューと、スライドショーを合わせたページを実装しました。

JS_lesson19 - CodeSandbox
JS_lesson19 by sae-code using date-fns, parcel-bundler, vite

それぞれで 命名の統一や、if文の書き方が統一されていなかったり していました
小さなパーツから統一感のあるコーディング、わかりやすい命名をすることが 後々見返す際に大切だと感じました。


コメント

タイトルとURLをコピーしました