🐻

【JavaScript】モーダルを作ってclassに入門する

2024/08/13に公開

この記事を書こうと思った理由

  • Web 制作で class を使う、という場合に、具体的で class が使いたくなるような解説や記事があまり無かったため。
  • class のチュートリアルや、記事を読んで、いざ書こうと思ったら何もできなかった過去の自分と同じような人の手助けのため。
  • class の継承を使ってみて、自分自身の理解度を上げるため。

ゴール

  • とにかく class に触れてみる。
  • class 使ってみよう!と思うこと。
  • class のワケワカランから脱出する。

対象者

JS 初学者

class のメリット

なぜ、class を使うのでしょうか?メリットを ChatGPT さんに聞いてみたところ、
明確な構造と可読性と返ってきました。
class を使うとコードの構造が明確なり読みやすくなります。

チーム開発をすると、自分以外の人にもコードを見られる機会が増えるので、
可読性だけでも重要なメリットと言えそうです。

トライしやすいメリットですね!発展的な機能は、慣れたら使えば良いと思います!

まず慣れていきます。

まず従来の書き方で書いてみる

従来の、という言い回しが正しいかは分かりませんが、
class を使う前は下記のように function を使って記述していました。

完成イメージ


シンプルでとてもかっこいいモーダルができています。

HTML

<div class="container">
  <div class="modal">
    <button class="js-openButton" type="button">オープン01</button>
    <div class="modal-content">
      <button class="js-closeButton modal-close-button" type="button">クローズ</button>
      <div class="inner">
        <p class="js-modalText">
          ここはモーダルのテキストや内容が入ります。<br />ここはモーダルのテキストや内容が入ります。<br />ここはモーダルのテキストや内容が入ります。
        </p>
      </div>
    </div>
  </div>
</div>
<!-- /.container -->

CSS

* {
  margin: 0;
  padding: 0;
}

button {
  cursor: pointer;
}

.container {
  width: 100%;
  height: 100vh;
  display: grid;
  place-content: center;
}

.modal-content {
  display: none;
  position: relative;
  width: 480px;
  height: 200px;
  border: 1px solid #333;
  background-color: #fff;
}

.modal-close-button {
  position: absolute;
  top: 10px;
  right: 10px;
}

.inner {
  display: grid;
  place-content: center;
  width: 100%;
  height: 100%;
}

.modal.is-open .modal-content {
  display: block;
}

JS

const body = document.querySelector('body');

const modal = document.querySelector('.modal');
const openButton = document.querySelector('.js-openButton');
const closeButton = document.querySelector('.js-closeButton');

// モーダルを開く関数
const openModal = () => {
  openButton.addEventListener('click', () => {
    modal.classList.add('is-open');
    body.style.backgroundColor = 'rgb(0 0 0 / 0.5)';
  });
};
openModal();

// モーダルを閉じる関数
const closeModal = () => {
  closeButton.addEventListener('click', () => {
    modal.classList.remove('is-open');
    body.style.backgroundColor = '#fff';
  });
};
closeModal();

class をまだ使った事が無い方は、こんな感じの記述になるのでは無いでしょうか?
querySelectorを使って要素を取得し、クリックイベントでis-openクラスや、css の付け外しを行なっています。
では、ここから class を使った記述に変更していきます。
HTML と CSS に変更はありません。

class を使った書き方

JS

class Modal {
  constructor() {
    this.body = document.querySelector('body');
    this.modal = document.querySelector('.modal');

    this.init();
  }

  init() {
    this.openModal();
    this.closeModal();
  }

  // モーダルを開くメソッド
  openModal() {
    const openButton = document.querySelector('.js-openButton');

    openButton.addEventListener('click', () => {
      this.modal.classList.add('is-open');
      this.body.style.backgroundColor = 'rgb(0 0 0 / 0.7)';
    });
  }

  // モーダルを閉じるメソッド
  closeModal() {
    const closeButton = document.querySelector('.js-closeButton');

    closeButton.addEventListener('click', () => {
      this.modal.classList.remove('is-open');
      this.body.style.backgroundColor = '#fff';
    });
  }
}

new Modal();

class で書くとこんな感じになります。
先ほどの function の記述と見比べても、書き方が変わっただけなので、書けるような気がしてきます!
class 独自の記述を覚えていきます。

class の記述について

  • class
    class Modal {}
    class を使う場合は class クラス名 {}というように書きます。クラス名は慣習で大文字始まりとなります。
    呼び出す際に、new Modal()とします。

  • constructor
    constructor(){}
    constructor とは、クラスのインスタンスを初期化するためのメソッドです。が、これを理解しようとすると難しいので、
    constructor 内では、
    constではなく、thisを使って定義すること。
    定義したら、openModal()closeModal()のメソッド内で使いまわせること。
    まず、これらを覚えましょう。

  • メソッド
    init()openModal()closeModal()これらはメソッドと呼ばれます。メソッドは class で使う関数です。
    呼び方が変わっただけと思えば、怖く無いです。
    init()内で、openModal()closeModal()が呼ばれています。
    別のメソッド内で呼ばれる場合は、this.を付与します。

  • init()
    その他のメソッドを呼び出すメソッドとして init()が定義される事が多くあります。
    init()内で他のメソッドを呼び出す場合は、thisを使います。

上記が、慣れない書き方や単語ではないでしょうか?
しっかり理解しようとすると、class の沼にハマってしまうので脱出が困難です。

まずは書く回数を増やしてみる。
今まで書いた js の記述を class に直してみたりする事で class に慣れていきましょう!

このままだと、本当に書き換えただけなので class っぽい事をやってみます!

constructor の引数を設定する

constructorの引数には任意のデータ型や式を設定できます。
よく分からないかもしれませんが、完成イメージと JS の記述を見てみて下さい。HTML はモーダルを 1 つ追加しています。

完成イメージ


背景色の違うモーダルを作成します。

HTML

<div class="container">
  <div class="modal modal01">
    <button class="js-openButton" type="button">オープン01</button>
    <div class="modal-content">
      <button class="js-closeButton modal-close-button" type="button">クローズ</button>
      <div class="inner">
        <p class="js-modalText">
          ここはモーダルのテキストや内容が入ります。<br />ここはモーダルのテキストや内容が入ります。<br />ここはモーダルのテキストや内容が入ります。
        </p>
      </div>
    </div>
  </div>

  <div class="modal modal02">
    <button class="js-openButton" type="button">オープン02</button>
    <div class="modal-content">
      <button class="js-closeButton modal-close-button" type="button">クローズ</button>
      <div class="inner">
        <p class="js-modalText">
          ここはモーダルのテキストや内容が入ります。<br />ここはモーダルのテキストや内容が入ります。<br />ここはモーダルのテキストや内容が入ります。
        </p>
      </div>
    </div>
  </div>
</div>
<!-- /.container -->

JS

class Modal {
  // 1. 引数にmodal,backgroundColorを設定
  constructor(modal, backgroundColor) {
    this.body = document.querySelector('body');

    // 2. querySelectorで取得する要素を引数で設定したmodalとする
    this.modal = document.querySelector(modal);
    this.openButton = this.modal.querySelector('.js-openButton');

    // 3. 同様にbackgroundColorを設定
    this.backgroundColor = backgroundColor;

    this.init();
  }

  init() {
    console.log(this.modal);
    this.openModal();
    this.closeModal();
  }

  openModal() {
    this.openButton.addEventListener('click', () => {
      this.modal.classList.add('is-open');

      // 3. 同様にbackgroundColorを設定
      this.body.style.backgroundColor = this.backgroundColor;
    });
  }

  closeModal() {
    const closeButton = this.modal.querySelector('.js-closeButton');

    closeButton.addEventListener('click', () => {
      this.modal.classList.remove('is-open');
      this.body.style.backgroundColor = '#fff';
    });
  }
}

// 呼び出す際にconstructorの引数に設定した値を追加する
new Modal('.modal01', 'rgb(255 0 0 / 0.250)');
new Modal('.modal02', 'rgb(0 21 255 / 0.25)');

確認していきましょう。

  1. constructorの引数に設定した値は、new Modal()として呼び出す際に設定できます。
  2. constructorの第 1 引数には、今回はdocument.querySelector(modal);modalを設定するので、new Modal()として呼び出す際に.modal01を追加します。
  3. constructorの第 2 引数には同様にbackgroundColorを設定します。this を使って定義したものは、メソッド内で使えるのでopenModal()内でthis.backgroundColorを設定します。

先ほどの記述と違いnew Modal()として呼び出す際に、
ターゲット要素やbackgroundColorを設定するため、自由度の高いモーダルを作ることができました!
今回の内容は、css 側での操作でなんとでもなりますが、発想や考え方次第では色々なことが出来そうです!

ここまでで、class ってこんな事が出来るんだ。と何となく理解できれば良いと思います。

何となく慣れてきたところで、class 独自の機能を使ってみます。

継承を使ってみる。

class の機能で、継承というものがあります。
継承って何やねん。ということで実際に使ってみます。
継承は、必要な機能や記述を引き継いて使う事ができる機能。になります。

継承はこんな時に使える。

このモーダルだけ別の機能が必要になった!(今回はアニメーション)
でももう 1 回同じ記述を書くのは冗長になるし、重複する部分も多くてメンテナンス性も良くない。。
どうしよう。。。
そうだ、継承を使おう!!

では、完成イメージと JS の記述を見てみて下さい。

完成イメージ


かっこいいアニメーション付きのモーダルです!

JS

class Modal {
  constructor(modal, backgroundColor) {
    this.body = document.querySelector('body');
    this.modal = document.querySelector(modal);
    this.openButton = this.modal.querySelector('.js-openButton');

    this.backgroundColor = backgroundColor;

    this.init();
  }

  init() {
    this.openModal();
    this.closeModal();
  }

  openModal() {
    this.openButton.addEventListener('click', () => {
      this.modal.classList.add('is-open');
      this.body.style.backgroundColor = this.backgroundColor;
    });
  }

  closeModal() {
    const closeButton = this.modal.querySelector('.js-closeButton');

    closeButton.addEventListener('click', () => {
      this.modal.classList.remove('is-open');
      this.body.style.backgroundColor = '#fff';
    });
  }
}

// 1. 継承を使う場合は、class 新しいclass名 extends 継承するclass と記述する
class AddAnimationModal extends Modal {
  // 2. コンストラクターには、継承するクラスの引数と追加で必要な引数を設定する
  // super()を使って継承するclassのコンストラクターを呼び出す
  constructor(modal, backgroundColor) {
    super(modal, backgroundColor);

    this.animationInit();
  }

  animationInit() {
    this.animation();
  }

  // 3.新しい必要な機能を実装する
  animation() {
    const modalText = this.modal.querySelector('.js-modalText');

    modalText.style.transition = 'all .5s';
    modalText.style.opacity = 0;
    modalText.style.transform = 'translateY(30px)';

    this.openButton.addEventListener('click', () => {
      setTimeout(() => {
        modalText.style.opacity = 1;
        modalText.style.transform = 'translateY(0)';
      }, 100);
    });
  }
}

new Modal('.modal01', 'rgb(255 0 0 / 0.250)');
new AddAnimationModal('.modal02', 'rgb(0 21 255 / 0.25)');

確認していきましょう。
まず、class Modal {}に変更はありません。

  1. 継承を使う場合は、class 新しい class 名 extends 継承する class 名と記述します。
  2. constructorの引数には、継承するクラスの引数と、追加で必要な引数を設定します。今回追加する引数はありません。
    そして、super(modal, backgroundColor);を使って呼び出します。これで継承が完了します。
  3. 新しく必要な機能を実装します。今回はアニメーションです。

どうでしょうか! 継承を使うことで、全く同じモーダルの記述を何度も書かずに済みました!便利ですね!
今回は記述量も多くないですが、長いコードになれば力を発揮しそうです!
何だか少しだけ class を使えるような気がしてきました!

おすすめ勉強法

CodePen

最後に

class は難しいですよね。
今でも勉強中ですが、メソッドを使って機能を切り分ける事も難しいなと感じます。
それでも書き続けていると、何となく感覚がつかめてくるので
今後も JS のレベルアップに力を入れていきたいです。

GitHubで編集を提案

Discussion