前回学んだVue3の基本を元に、Vue3でToDoアプリを実装していきましょう。
ゴール
- 前回学んだ内容でVue3のToDoアプリを実装する
- できるだけ自分の力で実装を進める
ToDoアプリ作成
今回のToDoアプリ作成では、こちらからテンプレート部分は提供します。
そこにVueでインタラクティブな処理を実装していきます。
準備
前回作ったApp.vue
ファイルは参考にすると思うので、Tutorial2.vue
などに名前を変えて保存しましょう。
Git管理下のファイルのファイル名を変える時は、VSCode上から実施してください。
エクスプローラーやコマンドラインからリネームするとGitの対象から外れてしまいます。
(本来はGitのコマンドを使ってやるところをVSCodeが裏でいい感じに実施してくれています)
その上で新たなApp.vue
を作って以下のコードをコピーしてください。
<script>
export default {
data() {
return {}
},
methods: {},
}
</script>
<template>
<h1>My ToDo App</h1>
<input type="text" /><button>追加</button><button>完了済みを削除する</button>
<ul>
<li>
<input type="checkbox" checked /><span class="todo-done"
>Vueをマスターする</span
>
</li>
<li><input type="checkbox" /><span>牛乳を買う</span></li>
<li><input type="checkbox" /><span>家賃を払う</span></li>
</ul>
</template>
<style>
body {
background-color: #eee;
}
.todo-done {
text-decoration: line-through;
}
</style>
要件
いくつかの要件を示します。
実装していく順番は自由ですが、上から下がやりやすいと思います。
- ToDoデータは完了の状態と文字列を保持しリストで表示する
- 初期表示でデータが何もない時、リストの位置に「ToDoがまだありません!」と表示する
- フォームに文字を入力し、追加ボタンを押すと文字列を元にToDoリストに追加される
- ToDoに追加したタイミングでフォームの文字列はクリアされる
- フォームに文字が未入力時に追加ボタンを押しても、アラートが表示されリストに追加されない
- ToDo毎のチェックボックスのオンオフで文字列に完了済みのラインの切り替えができる
- 完了済みを削除するボタンを押すとチェックボックスがオンになっているToDoが削除される
以上を可能な限り独力で前回のコードを参考にしながら実装してみてください。
行き詰まった場合は、上の順番通り各要件ごとにヒントのテキストとコードがあるので参考にしてみてください。
- できるだけヒントを見ずに実装
- 詰まったらヒントを見ながら実装
- 分からなくなったらサンプルコードを参考に実装
ヒント集
以下からはヒント集になります。
イメージとしては以下の順番で取り組んでみてもらえれば嬉しいです。
- できるだけヒントを見ずに実装
- 詰まったらヒントを見ながら実装
- 分からなくなったらサンプルコードを参考に実装
ToDoデータは完了の状態と文字列を保持しリストで表示する
ヒント
- サンプルコードを参考に
data
に仮のデータtodos
を作ってみる - データはオブジェクトの配列で、オブジェクトは完了状態のbooleanとToDoの文字列を持つ
- テンプレートでは
v-for
を使って仮データを配列で表示してみる -
v-for
を適用するのはli
要素、v-for="todo in todos"
- 文字列を表示するのは
{{ }}
- この時点ではチェックボックスや完了済みラインは気にしない
コード
data() {
return {
todos: [
{
isDone: true,
text: 'Vueをマスターする'
},
{
isDone: false,
text: '牛乳を買う'
},
{
isDone: false,
text: '家賃を払う'
},
],
}
}
<li v-for="todo in todos">
<input type="checkbox" /><span>{{ todo.text }}</span>
</li>
ToDoデータが何もない状態の時、リストの位置に「ToDoがまだありません!」と表示する
ヒント
- メッセージ表示用のHMTL要素を追加する
-
v-if
とv-else
を使う -
v-if
の条件はToDoデータ配列の長さが0
の場合、todos.length === 0
- 最初はToDoデータがある状態で実装してみる
- 次にToDoデータを空の配列にして表示が正しくなされるか見てみる
コード
data() {
return {
todos: [],
}
},
<p v-if="todos.length === 0">ToDoがまだありません!</p>
<ul v-else>
<li v-for="todo in todos">
<input type="checkbox" /><span>{{ todo.text }}</span>
</li>
</ul>
フォームに文字を入力し、追加ボタンを押すと文字列を元にToDoリストに追加される
ヒント
- フォームの
input
要素の値を管理するデータをdata
内に持つ -
v-model
を使いinput
要素とdata
の値をバインディングする -
methods
にaddTodo
を追加する - データのToDoの配列にインプットとバインディングされている文字列を元にオブジェクトをpushする
- ToDoのデータはオブジェクトで、完了状態と文字列をプロパティとして持つこと
- Vueのインスタンス内でオプションのプロパティを利用する時は
this.
を忘れないこと!
コード
export default {
data() {
return {
newTodoText: '',
todos: [],
}
},
methods: {
addTodo() {
this.todos.push({
isDone: false,
text: this.newTodoText,
})
},
},
}
<input type="text" v-model="newTodoText" /><button @click="addTodo">追加</button>
ToDoに追加したタイミングでフォームの文字列はクリアされる
ヒント
-
methods
に追加したToDoを追加するメソッドに修正を加える - フォームとバインディングされているテキストをクリアする
-
data
内の特定の値をメソッド内で利用する時はthis.
を忘れないこと!
コード
addTodo() {
this.todos.push({
isDone: false,
text: this.newTodoText,
})
this.newTodoText = ''
}
フォームに文字が未入力時に追加ボタンを押しても、アラートが表示されリストに追加されない
-
methods
に追加したToDoを追加するメソッドに修正を加える - アラートはWeb標準で提供されている
alert
メソッドを使ってOK - 処理を抜け出すよう、分岐を設け
return
で処理を終える
コード
if(this.newTodoText === '') {
alert('文字を入力してください')
return
}
// あるいは1行で簡潔に
if (!this.newTodoText) return alert('文字を入力してください')
ToDo毎のチェックボックスのオンオフで文字列に完了済みのラインの切り替えができる
ヒント
- 文字の装飾用のCSSは
todo-done
クラスとして<style>
に用意されている -
class
にv-bind
する、v-bind
の略記法は:xxxxx
-
class
のバインディングの時はオブジェクトを渡し、キーをクラス名、値を真偽値(boolean) - クラス名にハイフンが入っている場合はオブジェクトのキー名はクォーテーションマークで囲む(
'class-name'
) - バインドするオブジェクトはこんな感じ、
{'class-name': booleanValue }
コード
<input type="checkbox" v-model="todo.isDone" /><span
:class="{ 'todo-done': todo.isDone }"
>{{ todo.text }}</span
>
完了済みを削除するボタンを押すとチェックボックスがオンになっているToDoが削除される
ヒント
- ボタンに対応する新たなメソッドを
methods
に追加する、名前はclearDoneTodos
など - Todo配列を、完了状態で未完了のものだけにフィルターした配列に置き換える
コード
clearDoneTodos() {
this.todos = this.todos.filter((todo) => !todo.isDone)
},
まとめ
実装作業はどうでしたでしょうか?
ヒントのテキストやコードを見ながらでも、実装できてコードの理解が進んでいれば順調です!
最後にサンプルとしての実装コード全体を共有するので、ご自身のコードと見比べてみてください。
必要に応じて修正してもらって、納得した形になったらGitにコミットしておきましょう。
<script>
export default {
data() {
return {
newTodoText: '',
todos: [
// { isDone: false, text: 'ToDoの文字列'}
],
}
},
methods: {
addTodo() {
if (!this.newTodoText) return alert('文字を入力してください')
this.todos.push({
isDone: false,
text: this.newTodoText,
})
this.newTodoText = ''
},
clearDoneTodos() {
this.todos = this.todos.filter((todo) => !todo.isDone)
},
},
}
</script>
<template>
<h1>My ToDo App</h1>
<input type="text" v-model="newTodoText" /><button @click="addTodo">
追加</button
><button @click="clearDoneTodos">完了済みを削除する</button>
<p v-if="todos.length === 0">ToDoがまだありません!</p>
<ul v-else>
<li v-for="todo in todos">
<input type="checkbox" v-model="todo.isDone" /><span
:class="{ 'todo-done': todo.isDone }"
>{{ todo.text }}</span
>
</li>
</ul>
</template>
<style>
body {
background-color: #eee;
}
.todo-done {
text-decoration: line-through;
}
</style>
次回はToDoアプリをコンポーネントに分割して、再利用性を高めながら可読性もあげていきます。
お疲れ様でした。