LoginSignup
0
0

More than 3 years have passed since last update.

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

Posted at

前置き

picture_pc_8be74d31bdb9a712682ef9abdc34e5a9.gif

前回の続きです🌟
https://note.com/aliz/n/n47b0d98be524

1つのcomponentsで
複数のModalを表示させましょう✨

Step5: 中身をcomponents分けする

Modalの外側と内側で
componentsを切り分けていきましょう。
queryによって切り替えているpタグを
organismsに移動させます🎈🧸
propsを使わなくて済むので
本当にただ移動させるだけです、楽ちん♪

file
components/
--| organisms/
----| modals/
-----| ModalContainer.vue
--| templates/
----| modals/
-----| ModalRoute.vue

layouts/
--| default.vue
ModalContainer.vue
<template>
 <div class="modal-container">
   <!-- 切り替える中身 -->
   <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>
</template>

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

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

<style lang="scss" scoped>
 .modal-container {
   .text {
     font-size: 36px;
   }
 }
</style>

Step6: 中身をFormにする

picture_pc_8be74d31bdb9a712682ef9abdc34e5a9.gif

ついでにformを作りましょう🌟
password入力のinputも作ると
inputをmoleculesで作る必要が出てくるので
一旦イメージだけできればOKです🧸🍯

ModalContainer.vue
<template>
 <div class="modal-container">
   <!-- 切り替える中身 -->
   <form
     class="form"
     v-if="$route.query.modal === 'login'"
     @submit.prevent
   >
     <label class="label">
       <span class="label">
         {{ $route.query.modal }}
       </span>
       <input
         v-model="form.email"
         :type="type"
         placeholder="email"
       >
     </label>
     <button
       class="button"
       type="submit"
       @click="$emit('submit', form)"
     >
       {{ $route.query.modal }}
     </button>
   </form>
   <form
     class="form"
     v-if="$route.query.modal === 'register'"
     @submit.prevent
   >
     <label class="label">
       <span class="label">
         {{ $route.query.modal }}
       </span>
       <input
         v-model="form.email"
         :type="type"
         placeholder="email"
       >
     </label>
     <button
       class="button"
       type="submit"
       @click="$emit('submit', form)"
     >
       {{ $route.query.modal }}
     </button>
   </form>
 </div>
</template>

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

export default Vue.extend({
 name: 'Modal',
 data () {
   return {
     form: {
       email: '',
     },
   }
 },
 props: {
   type: {
     type: String,
     default: 'text',
   },
 },
})
</script>

<style lang="scss" scoped>
 .modal-container {
   .form {
     .label {
       font-size: 24px;

       .label {
         display: block;
       }
     }

     .button {
       display: block;
     }
   }
 }
</style>

【解説】
@click="$emit('submit', form)"
 inputに入力する値formを$emitで渡します。

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>
     <ModalContainer
       @submit="submit"
     />
   </div>
 </div>
</template>

<script>
import Vue from 'vue'

export default Vue.extend({
 name: 'Modal',
 components: {
   ModalContainer: () => import('@/components/organisms/modals/ModalContainer.vue'),
 },
 methods: {
   submit (form) {
     console.log(form) // eslint-disable-line
   },
 },
})
</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%;
     }
   }
 }
</style>

【解説】
・@submit
 $emitでつけたイベント名
・// eslint-disable-line
 consoleなど特定の行に書かないと
 ESLintでエラーになります。
 https://qiita.com/nju33/items/2d0cfea4fffbfdbff87a

Step7: Formを分ける

今はformが2種類ですが
もし増えたら管理が面倒なので
分けてしまいましょう💡

え、1つのコンポーネントを
queryで切り替えるのが
メリットなんじゃないの?😲
分けたら意味なくない?😲
と思ったそこのアナタ❗️

安心してください🍑
componentタグを使えば良いのです✨

コンポーネント の基本

【ディレクトリ 】
modalsというファイルを作り
ModalContainerのform2つを
それぞれに分けましょう。

🌷before🌷

file
components/
--| organisms/
----| modals/
-----| ModalContainer.vue
--| templates/
----| modals/
-----| ModalRoute.vue

layouts/
--| default.vue

🌷after🌷

file
components/
--| templates/
----| modals/
-----| ModalRoute.vue

modals/
--| login.vue
--| register.vue

layouts/
--| default.vue

【modals/login.vue】
・formのregister部分を除きましょう🧹
・$emitのイベント名を分かりやすく
 submitLoginに変更しましょう!

login.vue
<template>
 <div class="modal-container">
   <!-- 切り替える中身 -->
   <form
     v-if="$route.query.modal === 'login'"
     class="form"
     @submit.prevent="$emit('submitLogin', form)"
   >
     <label class="label">
       <span class="label">
         {{ $route.query.modal }}
       </span>
       <input
         v-model="form.email"
         :type="type"
         placeholder="email"
       >
     </label>
     <button
       class="button"
       type="submit"
     >
       {{ $route.query.modal }}
     </button>
   </form>
 </div>
</template>

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

export default Vue.extend({
 props: {
   type: {
     type: String,
     default: 'text',
   },
 },
 data () {
   return {
     form: {
       email: '',
     },
   }
 },
})
</script>

<style lang="scss" scoped>
 .modal-container {
   .form {
     .label {
       font-size: 24px;

       .label {
         display: block;
       }
     }

     .button {
       display: block;
     }
   }
 }
</style>

【modals/register.vue】
変更部分はlogin.vueと同じです

register.vue
<template>
 <div class="modal-container">
   <!-- 切り替える中身 -->
   <form
     v-if="$route.query.modal === 'register'"
     class="form"
     @submit.prevent="$emit('submitRegister', form)"
   >
     <label class="label">
       <span class="label">
         {{ $route.query.modal }}
       </span>
       <input
         v-model="form.email"
         :type="type"
         placeholder="email"
       >
     </label>
     <button
       class="button"
       type="submit"
     >
       {{ $route.query.modal }}
     </button>
   </form>
 </div>
</template>

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

export default Vue.extend({
 props: {
   type: {
     type: String,
     default: 'text',
   },
 },
 data () {
   return {
     form: {
       email: '',
     },
   }
 },
})
</script>

<style lang="scss" scoped>
 .modal-container {
   .form {
     .label {
       font-size: 24px;

       .label {
         display: block;
       }
     }

     .button {
       display: block;
     }
   }
 }
</style>

【components/organisms/modals/ModalRoute.vue】

NidakRoute.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>
     <!-- <ModalContainer
       @submit="submit"
     /> -->
     <component
       :is="$route.query.modal"
       @submitLogin="submit($event)"
       @submitRegister="submit($event)"
     />
   </div>
 </div>
</template>

<script>
import Vue from 'vue'

export default Vue.extend({
 name: 'Modal',
 components: {
   login: () => import('@/modals/login.vue'),
   register: () => import('@/modals/register.vue'),
 },
 methods: {
   submit (form) {
     console.log(form) // eslint-disable-line
   },
 },
})
</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%;
     }
   }
 }
</style>

【解説】
・component :is="$route.query.modal"
 └:isでcomponentを呼び出します!
  コンポーネントの登録が必要なので
  中身をそれぞれimportしましょう📩
 └それぞれを1つのコンポーネントとみなし
  queryで切り替えましょう🍒
@submitLogin="submit($event)"
 └$emitのイベント名を変えたので
  どちらも書きましょう✍️
 └($event)は省略可能

お疲れ様でした🤗
完成です🎉💕

次回予告

【Nuxt.js】アプリ開発実践編:
Nuxt + Vuex + firebaseでログイン付きToDoリスト

こちらのTODOリストに
ログイン機能をつけていきます!✨
https://note.com/aliz/n/n8411db2c9a20

公開予定日は5/19(火)です🌟

0
0
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
0
0