はじめに
こんばんは。
今回も前回の続きです。
今回は、ついにモーダル表示やりました。
本題
まず vue-js-modal
をインストールします。
plugins/vue-js-modal.js
vue-js-modalの設定ファイル作成します。
import Vue from 'vue' import VModal from 'vue-js-modal' Vue.use(VModal, { dynamic: true, dynamicDefaults: { clickToClose: true }, injectModalsContainer: true })
nuxt-config.js
pluginを読み込みます
... plugins: [{ src: '~/plugins/vue-js-modal.js' }], ...
index.vue
新たに編集時のイベントを渡しています。
<template> <div class="bg-blue-100"> <h1 class="text-2xl">Todo List</h1> <div class="flex"> <CardList type="todo" :card-list="cardList.todo" @doAddCard="doAddCard" @doModifyCard="doModifyCard" /> <CardList type="doing" :card-list="cardList.doing" @doAddCard="doAddCard" @doModifyCard="doModifyCard" /> <CardList type="done" :card-list="cardList.done" @doAddCard="doAddCard" @doModifyCard="doModifyCard" /> </div> </div> </template> <script> import CardList from '../components/CardList' export default { components: { CardList }, data() { return { cardList: { todo: [ { title: 'aaa', body: 'AAA', status: 'todo' }, { title: 'bbb', body: 'BBB', status: 'todo' }, { title: 'ccc', body: 'CCC', status: 'todo' }, { title: 'ddd', body: 'DDD', status: 'todo' }, { title: 'eee', body: 'EEE', status: 'todo' }, { title: 'fff', body: 'FFF', status: 'todo' } ], doing: [{ title: '○○○○○', body: '◎◎◎◎◎◎◎', status: 'doing' }], done: [ { title: '000', body: '0000000000', status: 'done' }, { title: '111', body: '1111111111', status: 'done' }, { title: '222', body: '2222222222', status: 'done' } ] } } }, methods: { doAddCard(type, title) { this.cardList[type].push({ title, body: '' }) }, doModifyCard(type, key, title, body) { this.cardList[type][key].title = title this.cardList[type][key].body = body } } } </script> <style></style>
CardList.vue
実際にmodalの表示を行っています。
<template> <div class="flex-1 bg-gray-100 m-2 cursor-pointer"> <p class="text-xl ml-2">{{ type }}</p> <Card v-for="(card, k) in cardList" :key="k" :card-key="k" :card-title="card.title" @showModal="showModal" /> <modals-container @onModifyCard="onModifyCard" /> <AddCard @onAddCard="onAddCard" /> </div> </template> <script> import Card from './Card' import AddCard from './AddCard' import CardDetailModal from './CardDetailModal' export default { name: 'CardList', components: { AddCard, Card }, props: { type: { type: String, require: true, default: '' }, cardList: { type: Array, require: true, default: null } }, methods: { showModal(cardKey) { this.$modal.show( CardDetailModal, { cardKey, cardData: this.cardList[cardKey] }, { height: 500 } ) }, onAddCard(title) { this.$emit('doAddCard', this.type, title) }, onModifyCard(cardKey, cardTitle, cardBody, cardStatus) { this.$emit('doModifyCard', cardStatus, cardKey, cardTitle, cardBody) this.$modal.hideAll() } } } </script> <style scoped></style>
Card.vue
カード一つ一つにイベントを設定します。
<template> <div class="z-10 flex-auto bg-white m-2 shadow"> <p class="w-full p-3" @click="$emit('showModal', cardKey)"> {{ cardTitle }} </p> </div> </template> <script> export default { props: { cardKey: { type: Number, require: true, default: 0 }, cardTitle: { type: String, require: true, default: '' } } } </script> <style scoped></style>
CardDetailModal.vue
modalの中身です。
<template> <div class="m-8"> <h2 class="text-3xl">{{ cardData.title }}の修正</h2> <div class="mt-5"> <div> <p class="my-1 text-lg">タイトル</p> <input v-model="title" class="w-full p-3 border-2" @focus="$event.target.select()" /> </div> <div class=" mt-5"> <p class="my-1 text-lg">本文</p> <textarea v-model="body" class="w-full p-3 border-2" rows="6" @focus="$event.target.select()" ></textarea> </div> <div class="mt-5 text-right"> <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" @click="$emit('onModifyCard', cardKey, title, body, cardData.status)" > 追加 </button> <button class="bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow" @click="$emit('close')" > 閉じる </button> </div> </div> </div> </template> <script> export default { name: 'CardDetailModal', props: { cardKey: { type: Number, require: true, default: 0 }, cardData: { type: Object, require: true, default: () => {} } }, data() { return { body: this.cardData.body, title: this.cardData.title } } } </script> <style scoped></style>
終わりに
最初の方読み込みが悪いのか、emitを設定できなかったり、しかし再読みこすると設定できたりと思わぬトラブルがありましたが、なんとかなりました。
emitの使い方(というよりコンポーネントの分け方?)が多分下手で、無駄にいっぱい引数取り回しててちょっとダサいです。。。
まぁ、できたので良し!
次はバリデーションをやってみます。
ではまた。