文档
Vue 3 代办事项(Composition API)
目标
用 Composition API 写一个经典的 Todo List,涵盖 ref、v-model、v-for、computed 等核心概念。
完整代码
src/App.vue
<script setup lang="ts">
import { ref, computed } from 'vue'
interface Todo {
id: number
text: string
done: boolean
}
const todos = ref<Todo[]>([])
const newTodo = ref('')
const remaining = computed(() => todos.value.filter(t => !t.done).length)
function addTodo() {
const text = newTodo.value.trim()
if (!text) return
todos.value.push({ id: Date.now(), text, done: false })
newTodo.value = ''
}
function removeTodo(id: number) {
todos.value = todos.value.filter(t => t.id !== id)
}
</script>
<template>
<div class="container">
<h1>📋 代办事项 ({{ remaining }} 项未完成)</h1>
<form @submit.prevent="addTodo" class="input-group">
<input
v-model="newTodo"
placeholder="输入新任务..."
class="todo-input"
/>
<button type="submit" class="btn-add">添加</button>
</form>
<ul class="todo-list">
<li
v-for="todo in todos"
:key="todo.id"
:class="{ done: todo.done }"
@click="todo.done = !todo.done"
>
<span class="check">{{ todo.done ? '✅' : '⬜' }}</span>
<span class="text">{{ todo.text }}</span>
<button @click.stop="removeTodo(todo.id)" class="btn-del">🗑️</button>
</li>
</ul>
<p v-if="todos.length === 0" class="empty">暂无任务,添加一个吧~</p>
</div>
</template>
<style scoped>
.container { max-width: 480px; margin: 2rem auto; font-family: system-ui; }
h1 { font-size: 1.5rem; margin-bottom: 1rem; }
.input-group { display: flex; gap: 8px; margin-bottom: 1rem; }
.todo-input { flex: 1; padding: 8px 12px; border: 2px solid #e2e8f0; border-radius: 8px; font-size: 1rem; }
.btn-add { padding: 8px 20px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; }
.todo-list { list-style: none; padding: 0; }
.todo-list li { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-bottom: 1px solid #f1f5f9; cursor: pointer; }
.todo-list li.done .text { text-decoration: line-through; color: #94a3b8; }
.text { flex: 1; }
.btn-del { background: none; border: none; cursor: pointer; opacity: 0.5; }
.btn-del:hover { opacity: 1; }
.empty { color: #94a3b8; text-align: center; }
</style>
运行
npm install && npm run dev
预期输出
浏览器打开后显示代办事项界面,可添加/勾选/删除任务,剩余计数实时更新。