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

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

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

下記は検索画面⇒モーダル⇒詳細画面の遷移をgifにしたものです。
![test11.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89564/bd8e6ca3-0c5d-d224-e70d-a5dcc41f2164.gif)

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

#実装
##モーダルの表示方法まとめ（初心者向け）
**1.単一ファイルコンポーネント**
[ モーダルウィンドウ- 基礎から学ぶ Vue.js](https://cr-vue.mio3io.com/examples/modal.html)

**2.[[ Vue.js ] どこからでも呼び出せるモーダルの実装方法](https://nitd.co.jp/blog/vue-js-modal_form_anywhere/)**
タイトル通り。storeを使用してどこからでも再利用可能なモーダルを作る。

**3.CDN版のvueでサクッとコンポーネント作成**
公式⇒[公式-モーダルコンポーネント の例](https://jp.vuejs.org/v2/examples/modal.html)。LIGの記事もわかりやすい。[SPAだけじゃない！Vue.js[2] モーダル実装にみるVue.jsの便利機能](https://liginc.co.jp/374210)

※公式について
2.6.0 以降ではslot 属性による名前付きスロットは非推奨となり代わりにv-slotの使用が推奨されているため一応注意。
slot *要素* とtemplate要素で使用するv-slot属性を利用することが推奨されています。
参照：[公式-非推奨の構文-slot 属性による名前付きスロット](https://jp.vuejs.org/v2/guide/components-slots.html#slot-%E5%B1%9E%E6%80%A7%E3%81%AB%E3%82%88%E3%82%8B%E5%90%8D%E5%89%8D%E4%BB%98%E3%81%8D%E3%82%B9%E3%83%AD%E3%83%83%E3%83%88)


**4.vue-js-modalまたは、vue-thin-modalを使用**
githubのリンク
[vue-js-modal](https://github.com/euvl/vue-js-modal)
[vue-thin-modal](https://github.com/ktsn/vue-thin-modal)

vue-thin-modalは開発経緯も簡単にブログに記載されていた。⇒[vue-thin-modal v1.0.0 をリリースしました](https://katashin.info/2018/07/09/231)。モーダルのよくある問題を 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から取得、なければ（ダイレクトアクセスの場合）新たに取得するように変更した。これで以前よりかなりサクサク動くようにすることができた。