本案例为黑马程序员Vue.js阶段的经典实践项目,聚焦待办事项(Todo List)的核心功能开发,通过Vue实例创建、数据双向绑定、事件处理(添加/删除/编辑任务)、列表渲染(v-for)、条件渲染(v-if)等核心特性,实现任务的增删改查及状态管理,同时结合localStorage实现本地数据持久化,确保刷新页面后数据不丢失,案例旨在帮助开发者深入理解Vue的数据驱动视图理念,掌握组件化开发基础,是初学者熟悉Vue生命周期能力、计算属性等知识点的实战练手项目,具有很强的实用性和学习价值。
Vue.js实战入门:从零构建待办事项应用(黑马程序员案例精讲)
在Vue.js的学习旅程中,“待办事项(Todo List)”无疑是经典的入门级项目,它不仅巧妙地涵盖了Vue.js的核心概念——如数据绑定、指令系统、事件处理和组件化思想,更能让初学者快速直观地体验“数据驱动视图”的强大魅力,本文将以黑马程序员Vue.js课程中的实战案例为蓝本,带领大家从零开始,一步步构建一个功能完善的待办事项应用,并深入剖析其中涉及的关键知识点。
案例背景与学习价值
待办事项应用的核心功能围绕“任务”的生命周期管理展开,包括:新增任务、标记任务完成/未完成状态、删除任务、按状态筛选任务(全部/已完成/未完成)等,看似简单的需求,却几乎囊括了Vue.js基础阶段的所有核心语法,是理论与实践结合的绝佳载体:
- 数据绑定 (Data Binding):实现任务列表的动态渲染,数据变化自动反映到视图。
- 指令系统 (Directives):
v-model:实现输入框与数据的双向绑定。v-for:高效渲染任务列表。v-if/v-show:根据条件控制任务显示(如完成状态切换)。
- 事件处理 (Event Handling):利用
@click、@keyup.enter等指令响应用户交互(添加、删除、切换状态)。 - 计算属性 (Computed Properties):动态计算并返回筛选后的任务列表,优化性能。
- 本地存储 (LocalStorage):实现任务数据的持久化,刷新页面后数据不丢失。
通过这个案例,初学者能深刻理解Vue.js“响应式数据”的核心优势——当数据源发生变化时,依赖该数据的视图会自动、高效地更新,彻底告别传统JavaScript中繁琐的手动DOM操作,这正是Vue.js区别于传统开发模式的关键所在。
技术栈与前置准备
在动手开发前,请确保具备以下基础知识和环境:
前置知识储备
- **HTML/CSS基础**:能够搭建页面结构并编写基本样式。
- **JavaScript基础**:掌握变量、函数、数组、对象等核心语法。
- **Vue.js核心概念**:理解Vue实例、`data`选项、`methods`、`computed`、`watch`等基本结构(黑马程序员Vue.js课程会系统讲解这些概念)。
开发环境选择
- 方式一(推荐):使用Vue CLI创建项目,适合后续功能扩展和工程化开发,需要安装Node.js和Vue CLI。
- 方式二(快速入门):通过CDN引入Vue.js,无需构建工具,适合快速验证核心功能,降低入门门槛。
本文采用**CDN引入方式**,聚焦核心功能实现,帮助初学者快速上手。
核心功能实现步骤
第一步:搭建基础HTML结构与Vue实例
创建一个HTML文件,引入Vue.js(开发版便于调试,生产版用于部署),并初始化Vue实例,添加基础样式让界面更美观:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue.js 待办事项应用</title>
<style>
/* 基础样式 */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
background-color: #f5f7fa;
}
h2 {
color: #2c3e50;
text-align: center;
margin-bottom: 20px;
}
.input-container {
display: flex;
margin-bottom: 20px;
}
.todo-input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px 0 0 4px;
font-size: 16px;
}
.add-btn {
padding: 10px 20px;
background-color: #42b983;
color: white;
border: none;
border-radius: 0 4px 4px 0;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
.add-btn:hover {
background-color: #3aa876;
}
.todo-list {
list-style: none;
padding: 0;
}
.todo-item {
margin-bottom: 10px;
padding: 12px;
background-color: white;
border: 1px solid #e0e0e0;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.3s;
}
.todo-item:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.todo-item.completed {
text-decoration: line-through;
color: #999;
background-color: #f9f9f9;
}
.todo-text {
flex: 1;
margin-right: 10px;
}
.delete-btn {
color: #e74c3c;
cursor: pointer;
font-weight: bold;
padding: 5px 10px;
border-radius: 3px;
transition: background-color 0.3s;
}
.delete-btn:hover {
background-color: #fadbd8;
}
.filter-container {
margin-top: 20px;
text-align: center;
}
.filter-btn {
padding: 8px 15px;
margin: 0 5px;
border: 1px solid #ddd;
background-color: white;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s;
}
.filter-btn.active {
background-color: #42b983;
color: white;
border-color: #42b983;
}
.filter-btn:hover:not(.active) {
background-color: #f0f0f0;
}
.empty-state {
text-align: center;
color: #999;
padding: 20px;
font-style: italic;
}
</style>
</head>
<body>
<