Vue-Todo-list 案例

一、前言

在前端开发中,Todo List(待办事项列表) 是一个非常经典的入门项目。它涵盖了组件化思想、数据绑定、事件处理、本地存储等核心知识点,非常适合用来练习 Vue 的基本用法。

本文将带你一步步实现一个功能完整的 Vue Todo List 应用,包括:

  • 添加任务
  • 删除任务
  • 标记任务完成状态
  • 清除已完成任务
  • 使用 localStorage 保存数据

通过本案例,你将掌握 Vue 开发的基本流程与常用技巧,为后续开发更复杂的项目打下坚实基础。

二、项目目标

我们要实现一个如下功能的 Todo List:

功能 描述
添加任务 输入内容后点击"添加"按钮或按回车键新增任务
删除任务 点击任务右侧的删除按钮即可移除该任务
完成状态切换 点击任务文本可切换完成状态(划线显示)
显示任务总数 显示当前任务总数
显示未完成数 显示未完成的任务数量
清除已完成任务 可一键清除所有已完成的任务
数据持久化 使用 localStorage 保存数据,刷新页面不丢失

三、技术选型

  • Vue 3(支持 Composition API)
  • Vue CLI 脚手架初始化项目
  • <script setup> 语法糖(更简洁)
  • HTML + CSS 布局
  • localStorage 实现数据持久化

四、项目结构说明

bash 复制代码
vue-todo/
├── public/              # 静态资源(不参与构建)
├── src/
│   ├── App.vue          # 根组件
│   ├── main.js          # 入口文件
│   └── components/
│       └── TodoList.vue # 待办事项主组件
├── package.json
└── README.md

五、开发步骤详解

第一步:创建 Vue 项目

如果你还没有创建项目,可以通过 Vue CLI 快速搭建:

bash 复制代码
vue create vue-todo
cd vue-todo
npm run serve

选择默认配置即可。

第二步:创建 TodoList 组件

1. 创建组件文件

src/components/TodoList.vue 中创建组件。

javascript 复制代码
<template>
  <div class="todo-container">
    <h2>我的待办事项</h2>

    <!-- 添加任务 -->
    <div class="input-group">
      <input
        v-model="newTodo"
        @keyup.enter="addTodo"
        placeholder="输入新任务..."
        class="todo-input"
      />
      <button @click="addTodo" class="btn">添加</button>
    </div>

    <!-- 任务列表 -->
    <ul class="todo-list">
      <li
        v-for="(todo, index) in todos"
        :key="todo.id"
        :class="{ completed: todo.completed }"
        @click="toggleComplete(index)"
        class="todo-item"
      >
        {{ todo.text }}
        <button @click.stop="removeTodo(index)" class="delete-btn">删除</button>
      </li>
    </ul>

    <!-- 操作按钮 -->
    <div class="actions">
      <p>共 {{ todos.length }} 项任务,还有 {{ remainingCount }} 项未完成</p>
      <button @click="clearCompleted" class="btn">清除已完成</button>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watchEffect } from 'vue'

// 初始化任务数组
const todos = ref(loadFromLocalStorage())

// 新增任务
const newTodo = ref('')
function addTodo() {
  const text = newTodo.value.trim()
  if (text === '') return
  todos.value.push({
    id: Date.now(),
    text,
    completed: false
  })
  newTodo.value = ''
}

// 切换完成状态
function toggleComplete(index) {
  todos.value[index].completed = !todos.value[index].completed
}

// 删除任务
function removeTodo(index) {
  todos.value.splice(index, 1)
}

// 清除已完成任务
function clearCompleted() {
  todos.value = todos.value.filter(todo => !todo.completed)
}

// 计算未完成任务数
const remainingCount = computed(() => {
  return todos.value.filter(todo => !todo.completed).length
})

// 监听数据变化并保存到 localStorage
watchEffect(() => {
  saveToLocalStorage(todos.value)
})

// 本地存储方法
function saveToLocalStorage(data) {
  localStorage.setItem('todos', JSON.stringify(data))
}
function loadFromLocalStorage() {
  const data = localStorage.getItem('todos')
  return data ? JSON.parse(data) : []
}
</script>

<style scoped>
.todo-container {
  max-width: 500px;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 8px;
  font-family: Arial;
}

.input-group {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

.todo-input {
  flex: 1;
  padding: 8px;
  font-size: 16px;
}

.btn {
  padding: 8px 12px;
  background-color: #42b983;
  color: white;
  border: none;
  cursor: pointer;
  border-radius: 4px;
}

.todo-list {
  list-style: none;
  padding-left: 0;
}

.todo-item {
  padding: 10px;
  margin-bottom: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: pointer;
  position: relative;
}

.todo-item:hover .delete-btn {
  display: inline-block;
}

.todo-item.completed {
  text-decoration: line-through;
  color: gray;
}

.delete-btn {
  position: absolute;
  right: 10px;
  top: 10px;
  display: none;
  background-color: #e74c3c;
}

.actions {
  margin-top: 20px;
}
</style>

第三步:在 App.vue 中引入组件

javascript 复制代码
<template>
  <div id="app">
    <TodoList />
  </div>
</template>

<script setup>
import TodoList from './components/TodoList.vue'
</script>

<style>
#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>

六、运行效果预览

启动项目:

bash 复制代码
npm run serve

打开浏览器访问 http://localhost:8080,你会看到一个美观且功能齐全的待办事项列表。

你可以:

  • 输入任务并按下回车或点击"添加";
  • 点击任务条目切换完成状态;
  • 点击"删除"按钮删除任务;
  • 点击"清除已完成"按钮一键清理已完成任务;
  • 刷新页面后任务不会丢失。

七、功能扩展建议(进阶)

功能 实现建议
支持编辑任务 在任务条目上添加"编辑"按钮,允许修改文本内容
支持任务分类 添加标签或分类字段,如"工作"、"生活"等
使用 Vuex/Pinia 将状态管理抽离出来,便于大型项目维护
支持多人协作 结合 WebSocket 或 Firebase 实现实时同步
支持拖拽排序 使用第三方库如 SortableJS
移动端适配 使用响应式布局优化手机端体验

八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
nece00123 分钟前
vue3杂记
前端·vue
Carry3451 小时前
不清楚的 .gitignore
前端·git
张鑫旭1 小时前
AI时代2025年下半年学的这些Web前端特性有没有用?
前端·ai编程
pinkQQx1 小时前
H5唤醒APP技术方案入门级介绍
前端
Lefan1 小时前
UniApp 隐私合规神器!一键搞定应用市场审核难题 - lf-auth 隐私合规助手
前端
Null1551 小时前
浏览器唤起桌面端应用(进阶篇)
前端·浏览器
Jing_Rainbow1 小时前
【Vue-2/Lesson62(2025-12-10)】模块化与 Node.js HTTP 服务器开发详解🧩
前端·vue.js·node.js
风度前端2 小时前
用了都说好的 uniapp 路由框架
前端
冴羽2 小时前
2026 年 Web 前端开发的 8 个趋势!
前端·javascript·vue.js
码银2 小时前
ruoyi的前端(vue)新增的时候给字典设置默认值 但不能正常
前端