vueの勉強として、質問フォーム的なものを作ってみました。
作業記録的な感じでコードを晒してみました。
作ったもの
質問フォーム的なものを作ってみました。
とはいえ、流れを作っただけでロジックやスタイルは全然作っていません……
なので
- 用意した質問した質問と回答ラジオボタンを表示
- 選択して確定すると、回答した内容を表示
ということをしています。
プロジェクトの作成
まずはプレーンな状態のvueを勉強しよう!
ということで、試験やら別コンポーネントやらは無しでプロジェクト作成しました。
なのでプロジェクト作成時の質問は、基本「No」で作成。
App.vue
App.vueは
- componentの設定(新規作成)
- CSSの設定
を行いました。
<template> <div id="app"> <Sample/> </div> </template> <script> import Sample from './components/Sample' export default { name: 'App', components: { Sample } } </script> <style> body, body *{ background: #333; color: #ccc; } #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
主に
- 「HelloWorld」だったところを「Sample」に変更
- Sampleは今回作成したcomponent
- body, body *のCSSを作成
- 適当なダークテーマに設定
- とりあえずダークしたかったのでかなり適当です(笑)
Sample.vue
コンテンツの内容です。
「発展させたらなんか作れるんじゃね?」と思ってこんな名前にしてしまいました。
たった今、後悔しています。
長い目なので、templateとscriptを分けました。
template
templateはこんな感じで作りました。
<template> <div class="sample"> <h1>Test</h1> <div class="qa" v-if="!isAnswer"> <div class="question" v-for="item in items" :key="item.id"> <p>Q{{ item.id }}</p> <p>{{ item.question }}</p> <div class="answers"> <label v-for="(answer, id) in item.answer"> <input type="radio" :value="id" v-model="item.select" /> {{ answer }} </label> </div> <p>{{ item.select }}</p> </div> <button @click="onAnswer">Commit</button> </div> <div class="result" v-if="isAnswer"> <p>result</p> <p>Your selections</p> <div class="question" v-for="item in items" :key="item.id"> <p>Q{{ item.id }}</p> <p>{{ item.question }}</p> <div class="answers"> <p>{{ item.select }} : {{ item.answer[item.select] }}</p> </div> </div> <button @click="onBack">Back</button> </div> </div> </template>
ブロックを
- 質問の表示
- 結果の表示
の2つで分けてあって、v-ifで表示を切り替えています。
質問フォームは、v-forを使って表示しています。
選択されると、v-forで扱ったオブジェクトに、選択中の番号をセット。
結果はそれを見て表示します。
script
scriptはコチラ。
<script> export default { name: "Sample", data() { return { isAnswer: false, items: [ { id: 1, question: "Q1 text...", answer: ["a1", "b1"], select: -1 }, { id: 2, question: "Q2 text...", answer: ["a2", "b2", "c2"], select: -1 } ], }; }, methods: { onAnswer(event) { var isOK = true; for (let i = 0; i < this.items.length; i++) { const item = this.items[i]; if (item.select < 0) { isOK = false; break; } } this.isAnswer = isOK; }, onBack(event) { this.isAnswer = false; items.forEach(item => { item.select = -1; }); } } }; </script>
isAnswerは、回答が出揃ったか?を判定。
itemsは、質問/回答の情報を持っています。
これがtemplateのv-forで回されて表示とかされる感じですね。
Commitボタンが押されると、onAnswer()がコールされて判定します。
itemsの内容を見て、すべて回答されていたら、結果画面を表示します。
作ってみての所感
想像よりは簡単にできたなぁ、という印象です。
itemsの構造と、v-forの関連をどうすればいいのか初めはよくわかりませんでした。
しかし試しているうちに、普通にJSONやクラスの構造を扱うのと変わらないんだなぁと分かりました。
v-ifにしろv-forにしろ、やりかたが一旦分かればなんとかなるな。という印象でした。