【jsステップアップ】[4]モーダルを作成する

04/04/2019

スライダーにモーダル機能を追加する

現場で役立つjs実装サンプル。として初心者の方に向けての連載4回目です。
前回作成したスライダーにモーダル機能を追加します。

前回のスライダー機能の実装より一般的で簡単な内容かと思います。
なのでモーダル機能+Zoom要素のレイアウト(モーダルの中身である拡大機能つける要素)
まで一気に進めます。

【拡大機能付きスライダー】javascript実装サンプルの連載一覧

  1. [1]初心者の方向けに作成手順や説明等していきます
  2. [2]ドラッグ値/スワイプ値を取得する
  3. [3]スライダーを作成する
  4. [4]モーダルを作成する
  5. [5]拡大(ズーム)機能を作成する
  6. [6]拡大(ズーム)機能を作成する②

スライダーにモーダル機能を追加したサンプル

下記が今回の実装サンプルです。

html/cssでのレイアウトに関しては今回で全て作成完了します。

モーダル機能に関して

第一回で説明した通りですが要件概要は下記です。

モーダル機能

スライダーで表示中の画像をズームアイコンクリック(タップ)でモーダル表示

closeアイコンクリックで閉じる

冒頭でもお伝えしましたが、今回はhtml/cssでのレイアウトが主な内容となります。
なのでシリーズ内でいうと内容的には多分一番簡単かと思います。
モーダル最初にやっても良かった気もするけど、順序がありますので、どうなんでしょう。

モーダルのHTMLを作成する

ってことでとりあえず下記がモーダル+Zoom要素抜粋のhtmlです。

モーダル部分抜粋したhtml

<div class="modal">
    <nav class="modal__nav">
        <a href="javascript:;" class="modal__close"><i class="fas fa-times"></i></a>
    </nav>
    <div class="modal__elm">
        <div class="zoom">
            <div class="zoom__info">
                <img src="https://nocebo.jp/data/zoomslider/img/01.jpg" alt="images">
                <div class="zoom__origin zoom__origin--02"></div>
                <div class="zoom__area"></div>
                <div class="zoom__data">
                    <p class="zoom__op">origin<span></span></p>
                    <p class="zoom__cp">move<span></span></p>
                    <p class="zoom__scale">scale<span></span></p>
                </div>
            </div>
            <div class="zoom__elm">
                <div class="zoom__origin zoom__origin--01"></div>
                <img src="https://nocebo.jp/data/zoomslider/img/01.jpg" alt="images">
            </div>
        </div>
        <!-- ====================================__  .zoom  ============================= -->
    </div>
</div>
<!-- ====================================__  .modal  ============================= -->

です。

あまり説明する事無い気もしますが、
一応modal__**とかってクラスがついているのがmodalの要素です。

でmodal__elmってのがmodalのメイン要素
でそれに内包されているzoomが拡大要素です。
でzoom__elmがzoomのメイン要素で
zoom__infoがzoom状態の確認用要素です。
って言葉で言うより実際に組んでしまった方が分かりやすいと思います。

BEM modifier

zoom__elm–01,zoom__elm–02の.**__**–**てのはBEMのmodifierです。

BEM最初見た時、何この命名、ヤダ怖い。て思ったけど。

慣れると後から見て意味が分かりやすい。と思う。

モーダル部分のCSSを作成する

続いてCSSでございます。

モーダル部分抜粋したSCSS

.modal
{
    position: fixed;
    z-index: -1;
    top: 0;
    left: 0;

    visibility: hidden;

    width: 100%;
    height: 100%;

    transition: all .2s linear;

    opacity: 0;
    background-color: rgba(0, 0, 0, .9);

    &.active
    {
        z-index: 1000;

        visibility: visible;

        opacity: 1;
    }

    .modal__nav
    {
        position: absolute;
        top: 30px;
        right: 20px;
    }

    .modal__close
    {
        font-size: 50px;

        position: fixed;
        z-index: 10000;
        top: 10px;
        right: 10px;

        width: 80px;
        height: 80px;
        padding: 23px;
        padding-top: 15px;

        color: #000;
        border-radius: 3px;
        border-radius: 100%;
        background-color: #fff;
    }

    .modal__elm
    {
        display: flex;

        height: 100%;

        align-items: center;
    }
}

.zoom
{
    position: relative;

    overflow: hidden;

    width: $baseWidth;
    height: $baseWidth;
    margin: 0 auto;

    border: 1px solid #ccc;

    .zoom__elm
    {
        width: 100%;

        &:hover
        {
            cursor: grab;
        }

        img
        {
            width: 100%;

            vertical-align: bottom;
        }
    }

    .zoom__info
    {
        position: absolute;
        z-index: 10;
        top: 1%;
        left: 1%;

        width: $baseWidth / 5;
        height: $baseWidth / 5;

        border: 1px solid #ccc;
        background-color: rgba(255, 255, 255, .4);

        img
        {
            width: 100%;

            opacity: .5;

            filter: grayscale(50%);
        }
    }

    .zoom__origin
    {
        position: absolute;
        z-index: 100;
        top: 0;
        left: 0;

        width: 20px;
        height: 20px;
        margin-top: -10px;
        margin-left: -10px;

        border-radius: 100%;
        background-color: rgba(255, 0, 0, .5);

        &--02
        {
            width: 10px;
            height: 10px;
            margin-top: -5px;
            margin-left: -5px;
        }
    }

    .zoom__area
    {
        position: absolute;
        top: 0;
        left: 0;

        width: 100%;
        height: 100%;

        transform-origin: 100% 100%;

        border: 1px solid #ccc;
        background-color: rgba(0, 0, 0, .3);
    }

    .zoom__data
    {
        font-size: 15px;

        position: absolute;
        top: -1px;
        left: $baseWidth / 5 + 10;

        width: 200px;

        text-align: left;

        color: #fff;

        p
        {
            line-height: 1.3;

            margin-bottom: 5px;
        }
        span
        {
            display: inline-block;

            margin-left: 5px;
        }
    }
}

SCSSの機能利用した部分の補足

いまさらではあるけどもSCSS使っているので
補足的に所々説明を入れてみます。

SCSS変数

$baseWidthとか
$**みたいなのはSCSS変数です。
各所や複数要素で使う、使いそうな場合は早めに変数化しておくと後々楽です。

あとSCSSは計算とかもできます。

サンプル例にするとモーダル表示した際に
拡大するメイン要素の左上に現在値とかの情報見れるように
小サムネイル+表示エリア+表示位置情報を表示しています。

小サムネイルの大きさをメイン要素の5/1にしたいなって時は

width: $baseWidth / 5;

のような感じで記述する事が出来て便利です。

&.active

これは今回みたいなmodalとかに非常に良く使います。
実際コンパイルされたデータ確認すると

.modal.active{}

みたいな感じになるので、
この.activeクラスをjsで付加したり外したりで表示状態を変える仕組みです。

昔はjqueryのfadein/fadeoutでやってましたが最近はこういうのが主流?だと思う。

&–02

ここがhtmlの部分でも説明しました。
BEMのmodifierです。

.zoom .zoom__origin--02{}

的な感じになるので
一応個人的には狙った通りの表示になります。
書き方規則的にこれで正しいのかは不明だけど

モーダル部分のjavascriptを作成する

あとはjsです。

モーダル部分抜粋したjavascript

// /* ===========================================================
// # Modal
// =========================================================== */
class Modal {
    constructor() {
        if (Modal.instance) return;
        Modal.instance = this;
        // -----------------------------
        this.modal = document.querySelector(".modal");
        this.modal__close = document.querySelector(".modal__close");
        this.delay = 500;
        this.events();
    }

    events() {
        this.modal__close.addEventListener("click", () => {
            this.close();
        }, false);
    }

    open(_id) {
        const id = (`00${_id}`).slice(-2);
        Array.from(document.querySelectorAll(".zoom img"), (e) => {
            e.src = `https://nocebo.jp/data/zoomslider/img/${id}.jpg`;
        });
        this.modal.classList.add("active");
    }

    close() {
        this.modal.classList.remove("active");
        window.setTimeout(() => {
            // Zoom.instance.resetScale();
        }, this.delay);
    }
}

前回までのが実装できてれば難しくは無いかと思います。

open(_id)

呼び出し元は前回コメントしていた。
Sliderクラスのslider__zoom要素からのclickイベントです。
引数としてcurrentIDを受け取っています。

const id = (`00${_id}`).slice(-2);

上記は受け取ったIDを文字列化&ゼロ埋めしています。

受け取ったcurrentIDによって画像のsrcを切り替えています。

Array.fromはjqueryでいう所の$.eachみたいな感じです。
多分。esいっぱいあってよくわからんけど。

で先述の.activeクラスをmodal要素にadd(modalを表示状態に)しています。

close()

openと逆で.activeをremove(modalを非表示に)します。
あと、まだZoom要素が無いからコメントしてますがresetScaleは
次回以降で登場します。

【拡大機能付きスライダー】javascript実装サンプル第4回 まとめと次回

今回は以上です。

普段からhtml/css利用している方ならば比較的簡単な内容だったのでは、と思います。

次回からはメインの拡大(Zoom)の機能を作成していきます。
ボリュームもあるので数回に分けるかもです。

【拡大機能付きスライダー】javascript実装サンプルの連載一覧

  1. [1]初心者の方向けに作成手順や説明等していきます
  2. [2]ドラッグ値/スワイプ値を取得する
  3. [3]スライダーを作成する
  4. [4]モーダルを作成する
  5. [5]拡大(ズーム)機能を作成する
  6. [6]拡大(ズーム)機能を作成する②

本連載に関して

本連載では、初心者向けに各所の解説をしていますが、
一歩踏み込んだ実践的な内容にはなっていると思います。
※フロントエンド(HTML/CSS/JavaScript)の基礎知識は必須になります。