LoginSignup
8
9

More than 3 years have passed since last update.

<初心者>Vue.jsで作ったサービスにモーダルを設置した話<モーダル導入法いろいろ>

Posted at

やりたいこと

作ったwebサービスreftikaの応答速度のアップ。
外部のサーバーを挟んでいるのでどうしてももっさりしている。
webサービスの詳細はこちらの記事参照ください。「レファレンス協同データベースの記事をランダムに表示するWEBサービスをvue.jsで作りました。」

やったこと

検索画面と詳細画面の間にモーダルを挟む。
詳細画面を読み込むのにどうしても時間がかかるので遷移せずに「軽い詳細(矛盾した表現だけれど..)」をモーダルで表示できるようにしました。

下記は検索画面⇒モーダル⇒詳細画面の遷移をgifにしたものです。
test11.gif

これでスマホでもサクサクたくさんの事例を見ていける!

実装

モーダルの表示方法まとめ(初心者向け)

1.単一ファイルコンポーネント
モーダルウィンドウ- 基礎から学ぶ Vue.js

2.[ Vue.js ] どこからでも呼び出せるモーダルの実装方法
タイトル通り。storeを使用してどこからでも再利用可能なモーダルを作る。

3.CDN版のvueでサクッとコンポーネント作成
公式⇒公式-モーダルコンポーネント の例。LIGの記事もわかりやすい。SPAだけじゃない!Vue.js[2] モーダル実装にみるVue.jsの便利機能

※公式について
2.6.0 以降ではslot 属性による名前付きスロットは非推奨となり代わりにv-slotの使用が推奨されているため一応注意。
slot 要素 とtemplate要素で使用するv-slot属性を利用することが推奨されています。
参照:公式-非推奨の構文-slot 属性による名前付きスロット

4.vue-js-modalまたは、vue-thin-modalを使用
githubのリンク
vue-js-modal
vue-thin-modal

vue-thin-modalは開発経緯も簡単にブログに記載されていた。⇒vue-thin-modal v1.0.0 をリリースしました。モーダルのよくある問題を Bootstrap ModalやModaalを参考に解決しているとのこと。ありがちな問題についてはわかりやすいスライド付きです。

以下はvue-js-modalの導入サンプル。githubより引用。

npm install vue-js-modal --save

して、

main.js
Vue.use(VModal)

として、

Home.vue
<template>
省略
<modal name="hello-world">
  hello, world!
</modal>
省略
</template>
<script>
methods: {
  show () {
    this.$modal.show('hello-world');
  },
  hide () {
    this.$modal.hide('hello-world');
  }
}
</script>

とするだけで呼び出せる。便利です。
ほかにjQueryを使用する方法もあるけれど、手慣れている以外にわざわざjQueryを利用するメリットってあるのだろうか。

今回は1の方法をとった。

Modal.vue
<template>
<transition name="modal" appear>
  <div class="modal modal-overlay" @click="$emit('close')"  >
    <div class="modal-window">
      <div class="modal-content">
        <p v-html="question" class="question"></p>
        <hr>
        <p v-html="answer" class="answer"></p>
      </div>
      <router-link :to="{ name: 'detail', params:{num:this.num}}">
        <button type="button" class="button">詳細を見る</button>
        </router-link>
    </div>
  </div>
</transition>
</template>
<script>
export default {
  name: 'Modal',
  data() {
    return {
    }
  },
  props: {
    question:String,
    answer:String,
    id:String,
    num:Number
  },
}
</script>
<style scoped>
省略
</style>

このModal.vueがv-forで表示している各記事のクリックで表示されるようにしたい。そこで、@clickで記事indexを登録する関数toggleDetailを用意。表示したい記事IDをdataのmodalIndexという変数に登録するとともに、モーダルの表示・非表示(dataのisDetail変数)のトグルも行っている。
モーダルはmodalIndexをもとにstoreへ記事詳細を取得しにいく。

Result.vue
<div class="resultswrapper" id="resultswrapper">
  <div class="result" v-for="(refqa,index) in this.$store.state.message" v-bind:key='index'>
    <div  @click="toggleDetail(index)" >
    <div class="result-question">
      <p v-html="refqa.question"></p>
    </div>
    <div class="result-answer">
      <p v-html="refqa.answer" ></p>
    </div>
</div>
  </div>

  <Modal  @close="toggleDetail(modalIndex)" class="modal" v-if="isDetail[modalIndex]" :question=this.$store.state.message[modalIndex].questionAll :answer=this.$store.state.message[modalIndex].answerAll :id=this.$store.state.message[modalIndex].id :num=modalIndex />
</div>
省略
<script>
    methods:{
      toggleDetail:function(index){
        this.$set(this.isDetail, index, !this.isDetail[index]);
        this.modalIndex = index;
      }
    }
</script>

ちなみに、この後の修正で記事詳細画面でも情報がstoreにあればstoreから取得、なければ(ダイレクトアクセスの場合)新たに取得するように変更した。これで以前よりかなりサクサク動くようにすることができた。

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9