【Nuxt.js】Modal実践編：QueryでModalを管理する①

# 前置き
![modal5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/ec072349-ec08-3a1f-4503-4a0ca268edc7.gif)

今回はqueryによるModalの切り替えです！
上の画像のurlにご注目👀
queryが分からない場合はこちら
https://note.com/aliz/n/ndf76ebe9853b

**【メリット】**
1つのcomponentsで
複数のModalを表示させることができます✨
Modalごとにcomponentsを
作らなくても良いんです✨

ちなみにModalが1種類だけで良ければ
シンプルな解説記事をご覧ください
https://note.com/aliz/n/n2f0bc857defb

# テンプレート

aLizでテンプレートを用意しているので
ぜひgit cloneして使ってください🍒
・scssが使えたり
・ESlintで綺麗なコードが書けたり
便利です〜✨
ESlintエラーはこれで自動で直ります💕

```bash:ターミナル 
$ npm run lint:fix
```

⚠️変数で背景色などを変えています！
　どちらかで調整してみてください🌟
　・assets/scss/common.scssで
　　color, background-colorをコメントアウト
　・assets/scss/_colors.scssで
　　該当する変数の色を変更する

https://github.com/aLizlab/product_nuxt-template

難しければ通常ファイルでもOKです♪

# 構成

**【index.vue】**
・buttonをclickでrouter.push
**【ModalRoute.vue】**
・中身はqueryで切り替え
　pageでrouter.pushしたqueryに合わせて
　v-ifで表示を切り替える
・外見の白背景、
　閉じるボタン、
　閉じる背景は固定

# 下準備

**【index.vue】**
importしているcomponents/atoms/ButtonDefault.vue
こちらは消してOKです！
$emitの使い方の参考に入れています。
続きの記事で使うのでコメントアウトでもOK♪

# Step1: Modalを作成
<img width="600" alt="スクリーンショット 2020-05-05 17.41.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/84885d18-73f8-e5db-bd0f-31b54fba8e6c.png">

**【流れ】**
土台のModalを作りましょう♪
ファイルを作ったら
layouts/default.vueに入れて
表示を確認しながらやっていきましょう👀

**【❓layouts/default.vue】**
pagesに毎回componentsを
importしなくても良くなります🤗

**【ディレクトリ 】**
アトミックデザインに基づいて
ファイル分けをしています🙋‍♀️
要素の大きさごとに分けているので
どこに何があるのか直感的に分かり
非常に便利です！✨

もちろん好きに作ってもらってもOKです！
分け方などはこちらを参考にしてください👀
また原則としてimportするのは
自分の1つ下のサイズのみです💡
[Atomic Designとは](https://design.dena.com/design/atomic-design-%E3%82%92%E5%88%86%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%A4%E3%82%82%E3%82%8A%E3%81%AB%E3%81%AA%E3%82%8B/)

```bash:file
components/
--| templates/
----| modals/
-----| ModalRoute.vue

layouts/
--| default.vue
```

```layouts/default.vue
<template>
 <div class="layout layout-default">
   <main class="content">
     <nuxt />
     <ModalRoute />
   </main>
 </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
 name: 'LayoutDefault',
 components: {
   ModalRoute: () => import('@/components/templates/modals/ModalRoute.vue'),
 },
})
</script>

// スタイリングは変更ないため省きます
```

**【components/templates/ModalRoute.vue】**
・iconはiconmonstrのX Mark 1
・HTML/CSSがメインのため解説なし

```ModalRoute.vue
<template>
 <div class="modal-route">
   <div class="bg" />
   <div class="modal-wrap">
     <button class="button">
       <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 20.188l-8.315-8.209 8.2-8.282-3.697-3.697-8.212 8.318-8.31-8.203-3.666 3.666 8.321 8.24-8.206 8.313 3.666 3.666 8.237-8.318 8.285 8.203z" /></svg>
     </button>
     <!-- 切り替える中身 -->
     <p class="text">
       Hello Nuxt.js!
     </p>
   </div>
 </div>
</template>

<script>
import Vue from 'vue'

export default Vue.extend({
 name: 'Modal',
})
</script>

<style lang="scss" scoped>
 .modal-route {
   position: fixed;
   top: 0;
   width: 100%;
   height: 100%;

   .bg {
     width: 100%;
     height: 100%;
     background-color: rgba(0,0,0,0.5);
   }

   .modal-wrap {
     border-radius: 8px;
     background-color: #ffffff;
     width: 50%;
     height: 50%;
     position: absolute;
     top: 50%;
     left: 50%;
     transform: translate(-50%, -50%);
     padding: 30px;

     .button {
       border: none;
       position: absolute;
       top: 5%;
       right: 2%;
     }

     .text {
       font-size: 36px;
     }
   }
 }
</style>
```

# Step2: queryで表示/非表示を切り替える

![modal.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/b238fa15-5c2a-c860-36c3-f6735b947b05.gif)

今のままだと常にModalが表示されます👀
queryでModalの
表示/非表示を切り替えましょう！🍒
Vue Router基礎編(params, query)はこちらhttps://note.com/aliz/n/ndf76ebe9853b

```index.vue
<template>
 <div class="page page-index">
   <h1>aLiz Nuxt's Template</h1>
   <button
     @click="$router.push('?modal=abc')"
   >
     Click!
   </button>
 </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
 name: 'PageTop',
 layout: 'default',
 components: {
 },
})
</script>
```

**【解説】**
・$router.push('?modal={好きな英数字}')
　$router.pushでqueryを指定します。
　queryが'modal'の時にModalRouteを表示

**【ModalRoute.vue】**
template部分のみ

```ModalRoute.vue
<template>
 <div
   v-if="$route.query.modal"
   class="modal-route"
 >
   <div
     class="bg"
     @click="$router.push('/')"
   />
   <div class="modal-wrap">
     <button
       class="button"
       @click="$router.push('/')"
     >
       <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 20.188l-8.315-8.209 8.2-8.282-3.697-3.697-8.212 8.318-8.31-8.203-3.666 3.666 8.321 8.24-8.206 8.313 3.666 3.666 8.237-8.318 8.285 8.203z" /></svg>
     </button>
     <!-- 切り替える中身 -->
     <p class="text">
       Hello Nuxt.js!
     </p>
     </div>
   </div>
 </div>
</template>
```

**【解説】**
**・v-if="$route.query.modal"**
　Modal全体を
　queryが'modal'の時のみ表示させる
**・@click="$router.push('/')"**
　背景と閉じるボタンをクリックしたら
　queryの'modal'を外して
　Modal全体を非表示にする
　💡$emitがいらないので楽ですね♪

# Step3: 中身をqueryごとに作る

![modal3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/32a7f895-16b3-56b5-95de-8eb3b648a508.gif)

中身は分かりやすく
<p>タグのみでやりましょう🌟
作ったらurlを変更して
チェックしましょう✨👀

```ModalRoute.vue
// template部分のみ
<template>
 <div
   v-if="$route.query.modal"
   class="modal-route"
 >
   <div
     class="bg"
     @click="$router.push('/')"
   />
   <div class="modal-wrap">
     <button
       class="button"
       @click="$router.push('/')"
     >
       <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 20.188l-8.315-8.209 8.2-8.282-3.697-3.697-8.212 8.318-8.31-8.203-3.666 3.666 8.321 8.24-8.206 8.313 3.666 3.666 8.237-8.318 8.285 8.203z" /></svg>
     </button>
     <!-- 切り替える中身 -->
     <p
       v-if="$route.query.modal === 'abc'"
       class="text"
     >
       Hello Nuxt.js!
     </p>
     <p
       v-if="$route.query.modal == '123'"
       class="text"
     >
       {{ $route.query.modal }}
     </p>
   </div>
 </div>
</template>
```

**【解説】
・v-if="$route.query.modal === 'abc'"**
　queryが?modal=abcならtrueで表示
　→index.vueでbuttonをクリックすると
　　queryが一致するので表示
**・v-if="$route.query.modal === '123'"**
　queryが?modal=123ならtrueで表示
**・{{ $route.query.modal }}**
　ついでに表示も変えてみましょう♪

# Step4: 調整
![modal4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/e256481e-a10d-d5e5-9e9b-b734ed6d1d7f.gif)

ボタンを表示を追加したり
実際のページらしいテキストに変更し
見た目を整えていきましょう🍒
・buttonを追加する
・それぞれqueryをloginとregisterに変更

```index.vue
// template部分のみ
<template>
 <div class="page page-index">
   <h1>aLiz Nuxt's Template</h1>
   <button
     @click="$router.push('?modal=login')"
   >
     ログイン
   </button>
   <button
     @click="$router.push('?modal=register')"
   >
     登録
   </button>
 </div>
</template>
```

```ModalRoute.vue
// template部分のみ
<template>
 <div
   v-if="$route.query.modal"
   class="modal-route"
 >
   <div
     class="bg"
     @click="$router.push('/')"
   />
   <div class="modal-wrap">
     <button
       class="button"
       @click="$router.push('/')"
     >
       <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 20.188l-8.315-8.209 8.2-8.282-3.697-3.697-8.212 8.318-8.31-8.203-3.666 3.666 8.321 8.24-8.206 8.313 3.666 3.666 8.237-8.318 8.285 8.203z" /></svg>
     </button>
     <!-- 切り替える中身 -->
     <p
       v-if="$route.query.modal === 'login'"
       class="text"
     >
       {{ $route.query.modal }}
     </p>
     <p
       v-if="$route.query.modal == 'register'"
       class="text"
     >
       {{ $route.query.modal }}
     </p>
   </div>
 </div>
</template>
```

今回はここまで！
Modalの外側と内側で
コンポーネント分けをし、
最終的にformを作成していきます！

# 次回予告

**【Nuxt.js】番外編：Progate初心者がNuxt.jsでWEBサイトを作るまでのロードマップ②
公開予定日は5/12(火)です🌟**

前回の①はこちら
主にProgate〜GitHubまで
https://note.com/aliz/n/nb89303a84f66


**記事が公開したときにわかる様、
フォローをお願いします😀💕**
https://twitter.com/aLizlab