やりたいこと
作ったwebサービスreftikaの応答速度のアップ。
外部のサーバーを挟んでいるのでどうしてももっさりしている。
webサービスの詳細はこちらの記事参照ください。「レファレンス協同データベースの記事をランダムに表示するWEBサービスをvue.jsで作りました。」
やったこと
検索画面と詳細画面の間にモーダルを挟む。
詳細画面を読み込むのにどうしても時間がかかるので遷移せずに「軽い詳細(矛盾した表現だけれど..)」をモーダルで表示できるようにしました。
下記は検索画面⇒モーダル⇒詳細画面の遷移を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
して、
Vue.use(VModal)
として、
<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の方法をとった。
<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へ記事詳細を取得しにいく。
<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から取得、なければ(ダイレクトアクセスの場合)新たに取得するように変更した。これで以前よりかなりサクサク動くようにすることができた。