Vue版のTODOアプリです。React回と同じ仕様で作るので、構文の違いがクリアになります。最小構成から始めて、コンポーネント分割の方向性も示します。
仕様
- 入力欄にTODOを入れる
- 追加ボタンでリストに追加
- 各行に削除ボタン
任意:空文字は追加しない、Enterで追加、件数表示
App.vue(最小実装)
App.vue を以下に置き換えて動かしてみます。
<script setup>
import { ref } from "vue"
const todos = ref([])
const text = ref("")
const addTodo = () => {
const trimmed = text.value.trim()
if (!trimmed) return
todos.value.push({
id: Date.now(),
text: trimmed,
})
text.value = ""
}
const removeTodo = (id) => {
todos.value = todos.value.filter((t) => t.id !== id)
}
</script>
<template>
<div style="padding: 16px;">
<h1>TODO</h1>
<div style="display: flex; gap: 8px;">
<input v-model="text" placeholder="やることを入力" @keydown.enter="addTodo" />
<button @click="addTodo">追加</button>
</div>
<p>件数: {{ todos.length }}</p>
<ul>
<li v-for="t in todos" :key="t.id" style="display: flex; gap: 8px;">
<span>{{ t.text }}</span>
<button @click="removeTodo(t.id)">削除</button>
</li>
</ul>
</div>
</template>
ポイント:
- 入力同期は
v-model - Enter追加は
@keydown.enter - 配列更新は
todos.value.push(...) - 削除は
filter
次の改善:コンポーネント分割
動いたら、次の分割が自然です。
TodoInput.vueTodoList.vueTodoItem.vue
Vueはpropsとイベント(emit)で親子連携するのが基本です。
練習問題
- TODOが0件なら案内メッセージを表示してみましょう(v-if)。
- 完了チェックを付け、完了は打ち消し線にしてみましょう。
- localStorageに保存してリロードしても残るようにしてみましょう。


コメント