概要
Nuxtのプロジェクト内で以下画像のような画面を作成しています。
ひとまず動作するようにしようと思い、以下コードのように記述したのですが、繰り返しも多くかなりダメなコードになってしまっていると思います。
以下を実現させるために、よりよい書き方等あればと思い質問させていただきました。
どなたかアドバイスいただけますでしょうか。
不足点は以降発見次第追記させていただきます。
どうぞ、よろしくお願いいたします。
実現したいこと
前提条件
- 各カード(li要素)、コンポーネントにはjsonからIDを取得し、そのIDに応じた要素を表示させる。
- IDの数は増減する可能性がある。
期待している挙動
- 各カードをクリックすると、対応したコンポーネント(モーダル)を表示。
- コンポーネントのボタンをクリックすると、コンポーネントを閉じる(非表示)
- コンポーネントのAgreeボタンをクリックすると対応するカードの状態をtrueに変更(それに伴うスタイルの付与)
- 全てのカードの状態がtrueになると、画面下部のボタンをactivate
サンプル画面
以下実装中のサンプル画面です。
- 各カードをクリックすると、それに対応する子コンポーネントがモーダルとして表示されます。
- モーダル内のボタンをクリックすると、またそれに対応したカードの状態(data)をtrueに変更し、v-ifによる文章の変更及びstyleの付与を行っております。
- 全てのカードの状態がtrueになるとボタンがアクティベートされクリック可能になります(この部分は現在実装している下記コードではid数の増減に対応できていません)
該当のソースコード
各コード、style等不要と思われる部分は消しています。
親コンポーネント
以下コードで、特に繰り返しになってしまっている記述についてどうにか省略できないか考えております。
現在はjsonから取得するidを3つに設定しているため、少しすっきりして見えますが、idを10個など取得すると、かなり可読性の悪いコードになってしまっています。
追記
だんだん短くなってきました...!
vue
1<template> 2 <section class="container"> 3 4 <!-- componentを配置 / 子コンポーネントでボタンをクリック時にイベントハンドラを受けとり、イベントを発火 --> 5 <agree-document v-if="isShow.id01" @doAgree="closeModal"></agree-document> 6 <agree-document2 v-if="isShow.id02" @doAgree="closeModal"></agree-document2> 7 <agree-document3 v-if="isShow.id03" @doAgree="closeModal"></agree-document3> 8 9 <div class="wrapper"> 10 <ul> 11 <!-- jsonから取得したidの数だけv-forで繰り返し --> 12 <li v-for="id in ids" :key="id"> 13 14 <!-- カードの上に重ね、クリックするとコンポーネントを表示 --> 15 <div v-if="id == id" @click="openModal(id)" class="list__item-link"></div> 16 17 <!-- カードタイトル --> 18 <p v-if="id == 'id01'">カード1</p> 19 <p v-if="id == 'id02'">カード2</p> 20 <p v-if="id == 'id03'">カード3</p> 21 22 <div v-if="id == id"> 23 <p v-if="!isAgreed[id]">Not agree</p> 24 <p v-if="isAgreed[id]" class="isAgreed">Agreed</p> 25 </div> 26 27 </li> 28 </ul> 29 30 <!-- button --> 31 <button 32 :class="{ isActive: completed }" 33 > 34 <span>次へ</span> 35 </button> 36 </div> 37 </section> 38</template> 39 40<script> 41import { request } from "~/data/index"; // 別ファイルで定義したrequest関数を取得 42 43// コンポーネントの読み込み 44import AegreDocument from "~/components/AgreeDocument.vue"; 45import AegreDocument2 from "~/components/AgreeDocument2.vue"; 46import AegreDocument3 from "~/components/AgreeDocument3.vue"; 47 48export default { 49 components: { 50 AgreeDocument, 51 AgreeDocument2, 52 AgreeDocument3 53 }, 54 data() { 55 return { 56 ids: [], 57 isShow: { 58 id01: false, 59 id02: false, 60 id03: false 61 }, 62 isAgreed: { 63 id01: false, 64 id02: false, 65 id03: false 66 } 67 }; 68 }, 69 computed: { 70 // ここもハードで処理を書いているため、 71 completed() { 72 return ( 73 this.isAgreed.id01 && 74 this.isAgreed.id02 && 75 this.isAgreed.id03 76 ); 77 } 78 }, 79 mounted() { 80 // 別のjsファイルで作成した関数を使用し、jsonからresponseを取得 81 this.$nextTick(() => { 82 const params = {}; 83 request(this.$axios, this.$store, params, this.$router) 84 .then(response => { 85 this.ids = response.data.ids; 86 }) 87 }); 88 }, 89 methods: { 90 openModal(id) { 91 Object.keys(this.isShow).forEach(key => { 92 if (key === id) { 93 this.isAgreed[key] = true; 94 this.isShow[key] = !this.isShow[key]; 95 } 96 }); 97 }, 98 closeModal() { 99 Object.keys(this.isShow).forEach(key => { 100 if (this.isShow[key] === true) this.isShow[key] = false; 101 }); 102 } 103 } 104}; 105</script> 106 107<style scoped> 108.list__item-link { 109 background-color: transparent; 110 width: 100%; 111 height: 100%; 112 position: absolute; 113 top: 0; 114 left: 0; 115} 116 117/* ボタン通常時 */ 118.btn { 119 pointer-events: none; 120} 121/* ボタンactive時 */ 122.isActive { 123 color: #fff; 124 background: blue; 125 cursor: pointer; 126 pointer-events: auto; 127} 128/* コンポーネントで同意後にtextの色をactiveにする */ 129.isAgreed { 130 color: red; 131} 132</style> 133
取得するjsonファイル
json
1{ 2 "data": { 3 "ids": [ 4 "id01", 5 "id02", 6 "id03" 7 ] 8 } 9}
モーダルとして表示する子コンポーネント
以下コンポーネントはjsonから取得するidの数だけ作成してあります。
vue
1<template> 2 <section> 3 4 <div v-if="id[index] == 'id01'"> 5 <h1>ID1のタイトル</h1> 6 </div> 7 <button type="button" class="btn btn-next" @click="doAgree"> 8 <span class="btn-text">Agree</span> 9 </button> 10 11 </section> 12</template> 13 14<script> 15import { request } from "~/data/index"; // 別ファイルで定義したrequest関数を取得 16 17export default { 18 data() { 19 return { 20 ids: [], 21 index: 0 22 }; 23 }, 24 mounted() { 25 this.$nextTick(() => { 26 const params = {}; 27 request(this.$axios, this.$store, params, this.$router) 28 .then(response => { 29 this.ids = response.data.ids}) 30 }); 31 }, 32 methods: { 33 // ボタンクリック時に、親コンポーネントのイベントを発火 34 doAgree() { 35 this.$emit("doAgree"); 36 } 37 } 38}; 39</script>
補足情報(ツールのバージョン)
"nuxt": "^2.4.2",
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/02/20 05:49
2019/02/20 14:57