今回はVue.jsを使った動的なモーダルウインドウの作り方を解説します。
動的なモーダルウインドウとはクリックした要素に応じて中身のコンテンツが変わるモーダルウインドウのことです。
具体的な画像と概念図を交えて解説していきます。
今回作成する動的なモーダル
今回作成するもののイメージです。自身のポートフォリオから引用しました。

Worksページで画像を一覧表示をさせています。その画像をクリックするとクリックした内容に応じた中身を動的に表示させています。
普通のHTMLで実装しようとすると、作品の個数分モーダルが必要になりますが、
そんな事したらVue使ってる意味がない!
ということで、Vueを使ってModal.vueコンポーネントを作成し、中身はクリックしたものによって動的に変わるように実装します。
Works.vueというページで画像を一覧表示させ、Modal.vueでモーダルウインドウ本体を作成していきます。
Vue.jsの場合であれば、Works.vueが親コンポーネント、Modal.vueが子コンポーネントの関係に当たります。
Vueにおける動的なモーダルの概念図
今回実装する機能の概念図はこんな感じです。
赤字で書かかれた数字ごとに何が起こってるのかを追ってみましょう。

大まかな概念が掴めたら実際のコードで見ていきます。
Works.vueでのコード
画像をクリックしたら引数付きでメソッドを実行
<div class="item-list" v-for="item in items">
<div class="card">
<img @click="openModal(item)" :src="item.img_src" alt="Card image">
</div>
</div>
v-for="item in items"でループして画像を一覧表示させています。
@click="openModal(item)"でそれぞれのitemを引数として指定し、メソッドを発火させています。
モーダルを表示させ、Modal.vueへの受け渡し用変数にitemを代入
methods: {
openModal (item) {
this.showContent = true
this.postItem = item
}
}
画像がクリックされた時に実行されるmodalOpenメソッドです。
まず、openModal(item)が実行されるとshowContentというモーダルが表示されているかどうかを管理する変数をtrueに変更します。
その後、Modal.vueにデータを受け渡しするための変数postItemにitemを代入しています。
Modalコンポーネントへitemデータの受け渡し
<modal :val="postItem" v-show="showContent" @close="closeModal" />
v-bindして値を指定することでModal.vueへWorks.vueで定義されたデータを受け渡すことができます。
今回は:val="postItem"としているので、Modal.vue側でvalと書くとpostItemのことになります。
ここでpostItemはopenModal(item)の引数のitemを代入してあるので、結果としてvalでitemを受け取れます。

ここまでで上記の図の②番までが実装できました。
Works.vueの最終的なコード(親コンポーネント)
<template>
<div class="page-inner">
<h2>Works</h2>
<p>過去の制作事例の一部を紹介します。</p>
<div class="item-list" v-for="item in items">
<div class="card">
<img @click="openModal(item)" :src="item.img_src" alt="Card image">
</div>
<modal :val="postItem" v-show="showContent" @close="closeModal" />
</div>
</div>
</template>
<script>
import Modal from '~/components/Modal.vue'
export default {
components: {
Modal
},
data () {
return {
showContent: false,
postItem: "",
items: [
{ id: 1,
desc: '課題で作成した美容室のHPです。',
range: 'コーディング(レスポンシブ対応)',
lang: 'HTML, CSS(Sass)',
img_src: require('../assets/salon.jpg'),
},
{
id: 2,
desc: '実案件で作成したコーポレートサイトです。',
range: 'コーディング(レスポンシブ対応)',
lang: 'HTML, CSS(Sass)',
img_src: require('../assets/navi.jpg'),
},
//
//省略(以下表示させたい分だけデータを定義していきます。)
//
]
}
},
methods: {
openModal(item) {
this.showContent = true
this.postItem = item
},
closeModal () {
this.showContent = false
}
}
}
</script>
次はModal.vue(子コンポーネント)です。
Modal.vueのコード
親から受け渡された値を取得する
先程親コンポーネント側で、以下のように:valで値を送りましたね。
<modal :val="postItem" v-show="showContent" @close="closeModal" />
親から送られてきた情報を子で受け取るにはpropsを使用します。
<script>
export default {
name: 'Modal',
props: ['val'],
}
</script>
これで、Modal.vueではvalを使うことで親からのデータを表示できます。
(※本来はpropsで受け取ったデータをcomputedなどで再定義して使うのが望ましいですが、割愛します。)
動的に値を表示する
<template>
<div id="overlay">
<div id="content">
<img :src="val.img_src">
<p>説明:{{ val.desc }}</p>
<p>作業範囲:{{ val.range }}</p>
<p>使用技術:{{ val.lang }}</p>
<button @click="$emit('close')">閉じる</button>
</div>
</div>
</template>
ここではvalで受け取った値を表示しています。親側から送られてきた値の情報をval.img_srcやval.descのような形で表示していることがわかります。
親のメソッドを発火してモーダルを閉じる
子コンポーネントであるModal.vueから親コンポーネントであるWorks.vueで定義されたメソッドにアクセスするには、$emitを使います。
クリックされると、@click=”$emit(‘close’)”で親に
「closeっていうイベントが起きたよ!!」
と伝えます。
<button @click="$emit('close')">閉じる</button>
親側ではそれを@closeで受け取って@close="closeModal"とすることでメソッドを呼び出すという訳ですね。
(今回は分かりやすく$emit('close')としましたが、イベント名は何でもOKです。
極端な話$emit('tojiru')としても@tojiruで受け取れます。)
<modal :val="postItem" v-show="showContent" @close="closeModal" />
発火されるcloseModalメソッドは以下のように定義しています。
methods: {
closeModal () {
this.showContent = false
}
}

これでこの画像の⑥番まで無事に実装できました。
お疲れさまでした!!
Modal.vueの最終的なコード(子コンポーネント)
<template>
<div id="overlay">
<div id="content">
<img :src="val.img_src">
<p>説明:{{ val.desc }}</p>
<p>作業範囲:{{ val.range }}</p>
<p>使用技術:{{ val.lang }}</p>
<button @click="$emit('close')">閉じる</button>
</div>
</div>
</template>
<script>
export default {
name: 'Modal',
props: ['val']
}
</script>
<style>
#overlay{
z-index:1;
position:fixed;
top:0;
left:0;
width:100%;
height:100%;
background-color:rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
#content{
z-index:2;
width:50%;
padding-top: 5em;
padding-bottom: 5em;
text-align: center;
}
#content > img {
width: 95%;
}
</style>
最後に
今回はVue.jsで動的なモーダルウインドウの作成方法を解説しました。
以下の記事ではVue.jsの初心者向けの具体的な学習ステップを紹介しています。
本格的にVue.jsの学習を始めてみたい方はぜひ参考にしてみてください。