用 Vue 3 构建任务清单:响应式编程的优雅实践

在前端开发中,任务清单(Todos)是一个经典练习项目。它虽功能简单,却能完整体现数据驱动、状态管理与用户交互的核心思想。若用传统 DOM 操作实现,代码往往冗长且难以维护;而借助 Vue 3 的组合式 API 与响应式系统,我们只需关注"数据如何变化",界面便会自动同步更新。这种声明式开发范式,不仅提升了开发效率,也让代码逻辑更清晰、更易测试。

从命令式到声明式:思维的转变

传统 JavaScript 开发通常采用命令式编程:先获取 DOM 元素,再监听事件,最后手动修改内容。

ini 复制代码
const app = document.getElementById('app');
const input = document.getElementById('todo-input');
input.addEventListener('change', (e) => {
  app.innerHTML = e.target.value.trim();
});

这种方式直接操作渲染引擎,每一步都需精确控制。一旦逻辑复杂(如增删改查、筛选、全选),代码会迅速膨胀,且容易因状态不一致导致 bug。

而 Vue 的核心理念是响应式数据驱动:你不再操作 DOM,而是定义数据;当数据变化时,框架自动更新视图。开发者只需思考"业务状态是什么",而非"页面该怎么改"。

响应式状态:用 ref 管理数据

在 Vue 3 的 <script setup> 中,我们使用 ref 创建响应式变量:

php 复制代码
<script setup>
import { ref } from 'vue'
const title = ref('Todos 任务清单')
const todos = ref([
  { id: 1, title: '打王者', done: false },
  { id: 2, title: '吃饭', done: true }
])
</script>

titletodos 都是响应式引用对象。通过 title.value = '新标题' 修改值后,模板中所有使用 {{ title }} 的地方都会自动刷新。这种机制将 UI 与状态紧密绑定,消除了手动 DOM 操作的繁琐。

模板指令:简洁表达逻辑

Vue 提供一系列指令,以声明方式描述 UI 行为:

ini 复制代码
<input v-model="title" @keyup.enter="addTodo" />
<ul v-if="todos.length">
  <li v-for="todo in todos" :key="todo.id">
    <input type="checkbox" v-model="todo.done" />
    <span :class="{ 'done': todo.done }">{{ todo.title }}</span>
  </li>
</ul>
  • v-model 实现双向绑定,输入框内容与 title 同步;
  • @keyup.enter 监听回车键,触发添加任务;
  • v-for 循环渲染列表,无需手动拼接 HTML;
  • :class 动态绑定样式,完成项显示删除线;
  • v-if 控制"暂无任务"提示的显示时机。

这些指令将常见交互模式封装成语义化语法,大幅降低样板代码量。

计算属性:高效派生状态

任务清单需要实时显示"未完成任务数"和"全选"状态。若在模板中直接写 todos.filter(...).length,每次渲染都会重新计算,影响性能。Vue 的 computed 提供了缓存机制:

ini 复制代码
const active = computed(() => {
  return todos.value.filter(todo => !todo.done).length
})

active 是一个计算属性,只有当 todos 发生变化时才会重新求值。模板中使用 {{ active }} 即可获得最新结果,且性能最优。

更巧妙的是,computed 支持 getter/setter,可用于实现"全选"功能:

javascript 复制代码
const allDone = computed({
  get() {
    return todos.value.every(todo => todo.done)
  },
  set(value) {
    todos.value.forEach(todo => todo.done = value)
  }
})

当用户勾选"全选"复选框时,set 被调用,批量更新所有任务状态;反之,若部分任务被取消,get 返回 false,复选框自动取消。这种双向联动仅需几行代码,却覆盖了复杂的交互逻辑。

添加任务:聚焦数据变更

新增任务的本质是向 todos 数组追加一项:

php 复制代码
const addTodo = () => {
  if (!title.value.trim()) return
  todos.value.push({
    id: Date.now(),
    title: title.value,
    done: false
  })
  title.value = ''
}

这里没有 createElementappendChildinnerHTML,只有对数据的操作。Vue 会自动检测数组变更,并高效更新 DOM。这种"数据即 UI"的思想,让业务逻辑与视图完全解耦。

样式与体验优化

通过动态类名,轻松实现视觉反馈:

css 复制代码
.done {
  color: #999;
  text-decoration: line-through;
}

配合 :class="{ 'done': todo.done }",完成的任务自动变灰并加删除线,提升用户体验。

总结

这个 Todos 应用虽小,却完整展示了 Vue 3 的核心优势:

  • 响应式系统让状态与视图自动同步;
  • 组合式 API 提供灵活、可复用的逻辑组织方式;
  • 模板指令 将常见交互抽象为简洁语法;
  • 计算属性 在保证性能的同时简化派生状态管理。

相比传统 DOM 操作,Vue 让开发者从"如何改页面"转向"数据该是什么样",极大降低了心智负担。对于初学者,这是快速上手现代前端开发的捷径;对于资深工程师,这是构建可维护、可扩展应用的坚实基础。正如那句老话:"当你专注于数据,UI 自会跟随。"

相关推荐
风止何安啊2 小时前
那些让你 debug 到凌晨的陷阱,我帮你踩平了:React Hooks 避坑指南
前端·react.js·面试
用户279656042702 小时前
wx微信小程序部分逻辑
前端
大大花猫2 小时前
我用AI写了个小程序,却被人说没有底线…
前端·微信小程序·交互设计
梵尔纳多2 小时前
打包 Electron 程序
前端·javascript·electron
接着奏乐接着舞。2 小时前
3D地球可视化教程 - 第6篇:蜂巢网格与自定义几何体
前端·vue.js·3d·threejs
GISer_Jing2 小时前
Taro打造电商项目实战
前端·javascript·人工智能·aigc·taro
KLW752 小时前
vue watch监听
前端·javascript·vue.js
晴殇i2 小时前
🎉 TRAE 一年使用的过程体验 🎉
前端
GDAL3 小时前
Tailwind CSS Flex 布局深入全面教程
前端·css·tailwindcss