SPAだけじゃない!Vue.js[2] モーダル実装にみるVue.jsの便利機能

SPAだけじゃない!Vue.js[2] モーダル実装にみるVue.jsの便利機能

つっちー

つっちー

こんにちは。フロントエンドのつっちーです。

前回に引き続き、「サーバーサイドテンプレートやHTMLファイルへのマークアップに対して、Vue.jsを使用する方法」に的を絞り、Vue.jsについて書いていきます。
今回は、Vue.jsが用意している様々な便利機能について、実際にそれを用いて作成したモーダルウィンドウを例として見ていきたいと思います。

モーダル実装にみるVue.jsの便利機能

こちらがモーダルウィンドウの完成形です。

See the Pen v-example-completed by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-completed by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-completed by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-completed by ligdsktschy (@lig-dsktschy) on CodePen.

ここから下記5つの挙動に分割し、利用しているVue.jsの機能について注目します。

  1. クリックでモーダルを開く
    複数のVueインスタンス間でイベントを共有する
  2. コンテンツ外をクリックでモーダルを閉じる
    要素自身のみにイベントハンドラーを登録する
  3. モーダルをフェードイン/フェードアウトで開閉する
    Vue.jsが提供するtransitionクラスを利用する
  4. モーダルの開閉に合わせて動画を再生/停止する
    Vue.jsのカスタムディレクティブを利用する
  5. 再生数を3桁ごとのカンマ区切りで表示
    Vue.jsのカスタムフィルターを利用する

以下の例では、Codepenの機能によって、あらかじめ下記のscriptタグが挿入されていることにご注意ください。

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>

ES Modulesのimportと、Webpackなどのモジュールバンドラーを用いた読み込みでも、同様に動作します。

利用しているVue.jsのバージョンは2.3.4です。

この連載では、SPA制作においてはVueのコンポーネント機能を用いて実装すべき部分を、Vueインスタンスとして実装します。SPA制作における、1Vueインスタンス=1アプリケーション、1コンポーネント=1部品の扱い方とは異なることにご注意ください。

1. クリックでモーダルを開く
→ 複数のVueインスタンス間でイベントを共有

See the Pen v-example-01 by ligdsktschy (@0ig-dsktschy) on CodePen.

See the Pen v-example-01 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-01 by ligdsktschy (@lig-dsktschy) on CodePen.

この例は、モーダルを開くトリガーのVueインスタンス(#js-trigger)と、モーダルのVueインスタンス(#js-modal)の、2つのVueインスタンスからなります。トリガーをクリックしてモーダルを開くためには、トリガーインスタンスでクリックイベントが発生したことを、モーダルインスタンスに伝える必要があります。あるVueインスタンスから別のVueインスタンスへのイベント伝達は、伝達専用のVueインスタンス(イベントバス)を作成することで実現できます。

Vueインスタンスには、独自のイベントを定義することができます。Vueインスタンスが予め持っている$onメソッド、$emitメソッドによって定義、発火します。$onはjQueryのonメソッドと、$emitはjQueryのtriggerメソッドと、それぞれ同じ記法で利用できます。この例ではclick.triggerという独自イベントを定義しています。

オプションオブジェクトのcreated属性には、データ、算出プロパティ、メソッドなどが準備できた段階で実行される処理を、関数の形で定義することができます。この例では、モーダルインスタンスのメソッドの準備完了を待つために利用しています。マウント完了時に実行されるmounted属性や、データ変更時に実行されるupdated属性など、他にも様々なタイミングを検知できます(ライフサイクルフック)。

2. コンテンツ外をクリックでモーダルを閉じる
→ 要素自身のみにイベントリスナーを登録する

See the Pen v-example-02 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-02 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-02 by ligdsktschy (@lig-dsktschy) on CodePen.

この例では、xボタンをクリックする他に、モーダルウィンドウのコンテンツ外(グレーの部分)をクリックすることでもモーダルウィンドウを閉じることができます。
通常、モーダルウィンドウ自体にイベントを登録し、ハンドラー内でイベントターゲットがその子要素でないのを確認することでこれを実現しますが、Vue.jsはよりシンプルに記述できる構文を提供します。

ディレクティブのイベント名の後ろに.selfを追記することで、イベントターゲットが自分自身である(子要素でない)時にのみ、ハンドラーが発火します。このように、ハンドラーへ付加効果を与える接尾辞はイベント修飾子と呼ばれ、他にもpreventDefaultを実行させる.prevent修飾子、一度しかハンドラーを発火させない.once修飾子などがあります。

3. モーダルをフェードイン/フェードアウトで開閉する
→ Vue.jsが提供するtransitionクラスを利用する

See the Pen v-example-03 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-03 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-03 by ligdsktschy (@lig-dsktschy) on CodePen.

この例では、モーダルウィンドウの開閉時に背景をCSSアニメーション(transition)を用いてフェードさせており、フェードイン(以下往路)は早め、フェードアウト(以下復路)は遅めと、所要時間に変化をつけています。これを実現するCSSは通常、往路/復路の判別が難しい、可読性の低い記述になりがちですが、Vue.jsはこれを解決する機能を提供します。

テンプレートにおいて、要素をtransitionラッパーコンポーネントで囲っておくと、transition発生中にいくつかのクラスが要素へ自動で付与されます。

<transition name="接頭辞"></transition>

これらのクラスは、アニメーションの設定に利用するためのクラスで、設定がどの状態に適用されるのか判別しやすい名前がつけられています。name属性の値を接頭辞とし、以下6つのクラス名が使用されます。

  • 接頭辞-enter-active
    → 往路のアニメーション全体に対して設定をするためのクラス
  • 接頭辞-enter
    → 往路の開始状態を設定するためのクラス
  • 接頭辞-enter-to
    → 往路の終了状態を設定するためのクラス
  • 接頭辞-leave-active
    → 復路のアニメーション全体に対して設定をするためのクラス
  • 接頭辞-leave
    → 復路の開始状態を設定するためのクラス
  • 接頭辞-leave-to
    → 復路の終了状態を設定するためのクラス

4. モーダルの開閉に合わせて動画を再生/停止する
→ Vue.jsのカスタムディレクティブを利用する

See the Pen v-example-04 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-04 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-04 by ligdsktschy (@lig-dsktschy) on CodePen.

この例では、モーダルウィンドウを開くと自動で動画が再生され、閉じると自動で停止されます。動画の再生/停止処理は通常、モーダルウィンドウの開閉処理とは(同時ではあっても)無関係に実行されると思いますが、Vue.jsを利用することで、モーダルウィンドウの開閉に連動して発生させることが可能です。

ディレクティブは、これまで予め用意されたもののみを利用してきましたが、独自に定義することも可能です(カスタムディレクティブ)。カスタムディレクティブは、その値の変更に応じて、要素に任意の処理を発生させることができます。Vue.directiveメソッドによって定義され、第一引数にはディレクティブ名が、第二引数には値に変更があった場合に発生する処理が渡されます。ディレクティブ名には、第一引数の値に接頭辞v-を付与したものが使用されます。第二引数の関数では、要素への参照やディレクティブの値など、処理に必要となる値が引数として取得できます。

5. 再生数を3桁ごとのカンマ区切りで表示
→ Vue.jsのカスタムフィルターを利用する

See the Pen v-example-05 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-05 by ligdsktschy (@lig-dsktschy) on CodePen.

See the Pen v-example-05 by ligdsktschy (@lig-dsktschy) on CodePen.

この例では、動画の再生数を3桁ごとのカンマ区切りで表示しています。JSのNumberオブジェクトには、これを実現可能なtoLocaleStringメソッドがありますが、一部ブラウザではサポートされていません。Vue.jsではこのような文字列操作を簡単に定義できます。

テンプレート上の文字列を操作する機能として、Vue.jsにはフィルターと呼ばれる機能が用意されています。フィルターは、テンプレート上の二重波カッコ内で、文字列(を表す式)に続けて | 記号とフィルタ名を記述することで適用します。フィルターは、Vue.filterメソッドによって定義され、第一引数にはフィルター名が、第二引数には文字列に適用する処理が渡されます。第二引数の関数では、対象の文字列を引数として取得し、処理結果をreturnで返すことで元の文字列と置き換えられます。

まとめ

Vue.jsを利用することで、多くの面倒くさい処理を簡潔に解決することができます。それぞれの機能には、他にも様々なバリエーションが用意されています。本文中のリンクから該当のVue.jsのドキュメントへ飛べるようになっていますので、ぜひそちらもチェックしてみてください。

次回は、Vue.jsをさらに便利にしてくれるプラグインの使い方について説明する予定です。
ではまた。つっちーでした。

LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。

Webサイト制作の実績・料金を見る

この記事のシェア数

つっちー
つっちー フロントエンドエンジニア / 土屋 大輔

フロントエンドエンジニアのつっちーです。 作曲してたらエンジニアになってました。 地図が好きで、一日中眺めていられます。 推しマップは路線地図。

このメンバーの記事をもっと読む
それいけ!フロントエンド | 213 articles