1つのモーダルの中身を、クリック元の要素によって変える方法[JavaScript]

モーダルの中身を、クリック元の要素によって変える方法[JavaScript]

はじめに

モーダルウィンドウ。Webサイトにおいて、ユーザーが特定のアクションを実行した際(たとえばトリガーとなる要素をクリック、あるいは一定のスクロール位置に達した時など)に、ポップアップウインドウの様に表示されるUIパーツです。

・ユーザーに何らかの通知を伝える時
・中にボタンや選択肢を置いておき、ユーザーに何らかの選択をしてほしいとき(選択してもらうことで次に進ませたい時)
・ユーザーがページを閲覧中「さらに詳しく知りたい」、と思った情報を、能動的にクリックして見てもらう時

などでよく見かけますよね。
さて、今回の記事はその「モーダルの中身を、クリック元によって変更する」ということについて書いていきたいと思います。

モーダルの中身を、クリック元によって変えてみる


モーダルウィンドウは、ご存知のとおり、実際のWeb制作の案件でもよく見かけるUIパーツのひとつです。
コンテンツが多いWebサイトでは、1ページ内に複数のモーダルが設置されているケースもよく見かけますね。

「このページには、複数のモーダルを設置する必要がある」という、そんな時。
何も考えないで実装する場合だと
「モーダルの見た目とその中身のコンテンツを、必要な数の分だけ配置する」ことになるかと思います。

これからご紹介するのは
「見た目として置くのは1個だけのモーダル」「その中身は、クリック元によって変更する」
と言うことを実現してみる、という内容になります。

ではhtml, css, JavaScriptの順に書いていきたいと思います。

htmlサンプル

まずは、トリガー側のhtml。「もっと詳しく」をクリックすると、モーダルが開く様なイメージです。

<section>
  <h2>モーダルの中身をクリック元によって変えてみる</h2>
  <div class="my-container">
    <h3>1. WordPressについて</h3>
    <span class="modal-trigger" data-key="1">もっと詳しく</span>
  </div>

  <div class="my-container">
    <h3>2. CSSについて</h3>
    <span class="modal-trigger" data-key="2">もっと詳しく</span>
  </div>

  <div class="my-container">
    <h3>3. デスクトップ整頓のコツ</h3>
    <span class="modal-trigger" data-key="3">もっと詳しく</span>
  </div>
</section>

続いて、モーダル本体のhtmlです。いたってシンプル。ここに、後ほどJavaScriptを使って
各トリガーに対応した内容を入れていく仕組みを書いていきます。

<div class="modal-container">
  <h2 class="modal-heading">テキスト</h2>
  <img class="modal-thumbnail" src="" alt="画像の説明" />
  <p class="modal-description">本文</p>
</div>
<div class="modal-background"></div>

cssサンプル

続いて、cssサンプルになります。サンプルということで、必要最低限のスタイルを当てています。
(.is-active というclass以外のcssは、お好みで調整しても動きます。余力しだいで編集してみてください)

.modal-background {
  background: rgba(0, 0, 0, 0.7);
  display: none;
  height: 100%;
  left: 0;
  overflow: hidden;
  position: fixed;
  top: 0;
  width: 100%;
  z-index: 10;
}
.modal-background.is-active {
  display: block;
}
.modal-container {
  background: #fff;
  border-radius: 0.5rem;
  display: none;
  left: 50%;
  min-height: 600px;
  padding: 1.25rem 2rem;
  position: fixed;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 800px;
  z-index: 20;
}
@media screen and (max-width: 500px) {
  .modal-container {
    min-height: initial;
    width: calc(100% - 1rem);
  }
  .modal-description {
    font-size: 0.75rem;
  }
}
.modal-container.is-active {
  display: block;
}
.modal-heading {
  display: block;
  margin: 0 auto 1.25rem;
  text-align: left;
}
.modal-thumbnail {
  aspect-ratio: 108/50;
  background: #e1e1e1;
  display: block;
  height: auto;
  margin: 0 auto 1rem;
  width: 100%;
}
.modal-trigger {
  align-items: center;
  background: #727272;
  border-radius: 999px;
  color: #fff;
  cursor: pointer;
  display: flex;
  height: 48px;
  justify-content: center;
  margin: 0 auto 3rem;
  padding: 0 2rem;
  transition: opacity 0.3s;
  width: fit-content;
}
.modal-trigger:hover {
  opacity: 0.7;
}

JavaScriptサンプル

これが本題、モーダル操作のJavaScript部分です。詳しい内容はコメントアウトで記載しました。

/**
 * NOTE: 要素取得 
 */
// [1].ページ内のクリック元の要素をすべて取得
const targetModalTrigger = document.querySelectorAll(".modal-trigger");

// [2].モーダル本体を取得( is-active というclassを着脱して表示/非表示させるため)
const targetModalElement = document.querySelector(".modal-container");

// [3].モーダル背景を取得(クリックで閉じるために取得しておく)
const targetModalBackground = document.querySelector(".modal-background");

// [4].モーダル内の各要素を取得(クリック元によってこれら各要素のコンテンツを更新する。上から見出し、サムネイル、本文)
const targetModalHeading = document.querySelector(".modal-heading");
const targetModalThumbnail = document.querySelector(".modal-thumbnail");
const targetModalDescription = document.querySelector(".modal-description");

/**
 * NOTE: 上記[1].で取得したクリック元に対してclickイベント監視。data属性と照合してコンテンツ用の配列から値を取得する
 */
targetModalTrigger.forEach((element) => {
  element.addEventListener("click", (event) => {
    const nowClickedElement = event.target;
    const nowClickedKey = event.target.dataset.key;

    // [5].関数を定義。クリックされた対象のデータ属性data-keyの値を比較する。その判定結果をreturn。
    // この関数をfindに与えてあげれば、判定結果により、コンテンツ用の配列内で一致したところの値を取得できると言う仕組み
    function getModalContent(clicked) {
      return clicked.id == nowClickedKey;
    }

    // 上記の関数を find() に渡す。クリック元のdata属性と一致したidをもつコンテンツが取得できる。
    const resultModalContent = targetModalArray.find(getModalContent);

    // 取得したコンテンツを、[4].で取得したモーダル内の各要素に代入する
    targetModalHeading.textContent = resultModalContent.title;
    targetModalThumbnail.setAttribute('src', resultModalContent.thumbnailUrl);
    targetModalThumbnail.setAttribute('alt', resultModalContent.title);
    targetModalDescription.textContent = resultModalContent.description;

    // [2]. と [3]. で取得しておいたモーダル本体と背景に is-active を付与して表示する
    targetModalElement.classList.add("is-active");
    targetModalBackground.classList.add("is-active");
  });
});

// [3]. のモーダル背景がクリックされた場合に is-active をはずしてモーダルをとじる
targetModalBackground.addEventListener("click", () => {
  targetModalElement.classList.remove("is-active");
  targetModalBackground.classList.remove("is-active");
});

モーダルのコンテンツ配列サンプル

続いて、以下がモーダルのコンテンツ用の配列です。(内容の文章自体はダミーなので自由に変更可能です)
上記のJavaScriptにより、クリック元によって一致する部分の各コンテンツを取得。
モーダル内の内容が更新されます。このサンプルではJavaScript内に変数として持たせる想定で書いていますが、
実際の運用ではこの配列はJSONとして外部化して、それを読み込んで使用しても良いかと思います。

const targetModalArray = [
  {
    id: 1,
    title: "1. WordPressについて",
    description:"WordPressは、ウェブサイトを簡単に作成・管理できるオープンソースのプラットフォームです。さまざまなテーマやプラグインを有効活用しながらコードを組み上げていくことで、ブログやビジネスサイトなど、多様なサイトを手軽に構築できます。ビギナーからオフィスユースまで、幅広いユーザーに世界的に支持されてきました。",
    thumbnailUrl: "https://picsum.photos/id/62/800/370",
  },
  {
    id: 2,
    title: "2. CSSについて",
    description:"HTMLがページの骨組みを作るのに対し、CSSはその骨組みに色やレイアウト、フォントなどを施して、視覚的に魅力的なデザインを作り上げます。制作者はCSSを使って、同じHTMLでもまったく異なるデザインを作成できるため、ウェブサイトの個性を引き出すためには欠かせない構成要素です。",
    thumbnailUrl: "https://picsum.photos/id/202/800/370",
  },
  {
    id: 3,
    title: "3. デスクトップ整頓のコツ",
    description:"デスクトップ整頓のコツは、シンプルさを保つことです。まず、重要なファイルや頻繁に使用するアプリケーション以外は、フォルダに整理してしまいましょう。プロジェクトごとにフォルダを作成し、内容に応じた名前を付けて管理すると、後で探しやすくなります。また、デスクトップにあるアイコンが多すぎると作業効率が低下するため、定期的に整理する習慣をつけることも大切です。視覚的な整理とルーチンの維持が、スッキリとしたデスクトップを保つポイントですね!",
    thumbnailUrl: "https://picsum.photos/id/60/800/370",
  },
];

実際に動作するデモページ

実際にこの仕組みが動いているデモページを用意しましたので、次のリンクより確認してみてください。
「もっと詳しく」ボタンを押すとモーダルが開きます。
コンテンツはScript内に配列で管理されていて、クリック元によって内容を切り替えています。リンク先のページを
デベロッパーツールで見てもらうと、モーダルのhtmlとしては次の要素しか入っておらず、開いた時に動的にコンテンツが更新されている事がわかるかと思います。

モーダルの中身を、クリック元の要素によって変えるサンプル

MDNの解説ページ

今回ご紹介した内容で重要になるJavaScriptの find() について、MDN Web Docsでの解説ページは以下になります。
JavaScriptのfindメソッド

↑いつも書いていますが、MDN(旧名称: Mozilla Developer Network)は、Mozillaが運営しているWeb技術情報のリファレンスサイトです。
とても情報が正確で、見る価値がおおいにあります。ぜひ一読をおすすめします。

この記事のまとめ

今回は、Webサイト制作時によく出てくる「モーダルウィンドウ」について、

「見た目のhtmlは1個だけ」を用意して、
「コンテンツはクリック元によってJavaScriptで切り替える」

という方法について記事を書いてみました。

この方法や発想というのは、実は
Vue.js や React などのフロントエンドフレームワークを使ったWeb制作においては、いたって普通に使われている手法になります。

・コンテンツと見た目は分離させて管理する。
・見た目はコンポーネントとして使い回す。再利用する。
・コンテンツはそこに差し込んでいく。分離されているのでメンテナンスが容易。

↑というような概念です。

それをあえて静的なhtmlで実現するなら…という観点で、今回この記事を書きました。

実際の制作現場で、
「Vue.js や React などのフロントエンドフレームワークを使うことができない案件 / 使わせてもらえない案件」
というのは多々存在します。

そんな時に、少しでも効率化が図れるなら…と思いこの記事を書いてみました。

この記事が皆さんのより良いWeb制作体験につながれば、嬉しく思います。

※この記事は内容の品質向上を目的に、随時更新を行う場合があります。

この記事をシェアする: