📝在现代前端开发中,Vue 3 与 Vite 的组合已成为快速构建高性能、响应式 Web 应用的黄金搭档。本文将围绕一个完整的 Todos(任务清单) 示例项目,深入剖析其技术栈构成、核心代码实现逻辑、Vue 3 Composition API 的使用方式、Vite 配置细节,以及响应式编程思想如何彻底改变我们构建用户界面的方式。
🛠️ 技术栈概览
该项目基于以下关键依赖构建:
- Vue 3.5.25:当前最新稳定版的 Vue 框架,提供强大的响应式系统和组件化能力。
- Vite 7.2.7:新一代前端构建工具,以其闪电般的冷启动和热更新速度著称。
- @vitejs/plugin-vue 6.0.2:官方提供的 Vite 插件,用于支持
.vue单文件组件(SFC)的编译。 - Node.js 环境要求:Vite 和插件要求 Node.js 版本为
^20.19.0或>=22.12.0,确保了对现代 JavaScript 特性的良好支持。
这些依赖关系清晰地定义在 package.json 文件中,并通过 package-lock.json 锁定具体版本,保证了项目在不同环境中的一致性。
🏗️ 项目结构与入口
📂 核心文件
-
index.html:应用的唯一 HTML 入口文件。Vite 会以此为基础注入 JavaScript 和 CSS 资源。内容虽简单,仅包含<title>vue3-todos</title>,但它是整个 SPA(单页应用)的基石。 -
main.js:JavaScript 入口文件。在这里,我们创建 Vue 应用实例并挂载到 DOM。import { createApp } from 'vue' import './style.css' // 引入全局样式 import App from './App.vue' // 引入根组件 createApp(App).mount('#app') // 创建应用并将根组件挂载到 #app 元素上 -
vite.config.js:Vite 的配置文件。它启用了 Vue 插件,使 Vite 能够正确处理.vue文件。import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], })
🧩 组件体系
App.vue:这是应用的根组件,包含了 Todos 应用的所有核心逻辑和 UI。HelloWorld.vue:一个示例组件,通常由脚手架生成,用于演示基本的组件通信(props)和状态管理(ref)。虽然在主应用中未被使用,但它展示了 Vue 组件的标准结构。
💡 核心思想:响应式数据驱动
Vue 的核心哲学是 “数据驱动视图” 。开发者不再需要手动操作 DOM(如 document.getElementById 或 addEventListener),而是专注于数据本身。当数据发生变化时,Vue 的响应式系统会自动、高效地更新相关的 DOM。
在 App.vue 中,这一思想贯穿始终。
🧠 App.vue 深度解析
📦 响应式状态 (ref)
import { ref, computed } from 'vue'
// title 是一个响应式引用,用于绑定输入框的值
const title = ref("")
// todos 是一个包含任务对象的响应式数组
const todos = ref([
{ id: 1, title: '打游戏', done: false },
{ id: 2, title: '吃饭', done: false },
{ id: 3, title: '睡觉', done: false },
{ id: 4, title: '学习Vue', done: false }
])
ref()创建了一个响应式引用对象。在模板中直接使用title或todos时,Vue 会自动解包其.value属性。- 所有对
title.value或todos.value的修改都会触发视图的重新渲染。
➕ 新增任务 (addTodo)
const addTodo = () => {
if (!title.value.trim()) return; // 防止添加空任务
todos.value.push({
id: Math.random(), // 简单的 ID 生成(生产环境应使用更可靠的方法)
title: title.value,
done: false
});
title.value = ''; // 清空输入框
}
- 该函数通过修改
todos数组来添加新任务。由于todos是响应式的,列表会立即更新。 @keydown.enter="addTodo"指令将回车键事件绑定到此函数,提供了良好的用户体验。
🔍 计算属性 (computed)
计算属性是基于响应式依赖进行缓存的计算。只有当依赖项发生变化时,才会重新求值。
-
活动任务数量 (
active)const active = computed(() => { return todos.value.filter(todo => !todo.done).length })- 这个计算属性返回未完成任务的数量。它依赖于
todos数组。 - 在模板中使用
{{ active }}比直接写{{ todos.filter(...).length }}性能更好,因为后者在每次组件重新渲染时都会执行,而前者只在todos变化时才计算。
- 这个计算属性返回未完成任务的数量。它依赖于
-
全选/取消全选 (
allDone)const allDone = computed({ get() { // 如果 todos 为空,every 返回 true,这里我们希望它返回 false return todos.value.length > 0 && todos.value.every(todo => todo.done) }, set(val) { todos.value.forEach(todo => todo.done = val) } })- 这是一个可写的计算属性,同时具有
get和set函数。 get: 检查所有任务是否都已完成。set: 当用户点击“全选”复选框时,val会是true或false,此函数会将所有任务的done状态同步为该值。v-model="allDone"将这个计算属性与复选框双向绑定,实现了精妙的同步逻辑。
- 这是一个可写的计算属性,同时具有
🖼️ 模板与指令 (Template & Directives)
Vue 的模板语法简洁而强大,通过一系列指令将数据和 DOM 连接起来。
v-model: 创建双向数据绑定。在输入框上,它将value属性和input事件结合起来,使得title的值与输入框内容始终保持同步。v-for: 用于列表渲染。v-for="todo in todos"会为todos数组中的每一项创建一个<li>元素。:key提供了唯一的标识符,帮助 Vue 高效地追踪和更新列表项。v-if/v-else: 条件渲染。<ul v-if="todos.length">只有在任务列表不为空时才渲染。否则,渲染<div v-else>暂无计划</div>。@(v-on 的缩写) : 事件监听。@click,@keydown.enter等用于绑定事件处理器。:(v-bind 的缩写) : 动态绑定。:class="{'done': todo.done}"会根据todo.done的真假动态地给<span>元素添加或移除doneCSS 类。
🎨 样式 (Scoped CSS)
<style scoped> 标签确保其中的 CSS 规则只应用于当前组件,避免了全局样式污染。
.done类为已完成的任务添加灰色和删除线效果。.app-container设置了一个背景图片(./assets/image5.png),并使用rgba为内容区域添加了半透明背景以提高文字可读性。
🚀 开发与构建流程
通过 package.json 中的脚本,可以轻松管理项目:
npm run dev: 启动 Vite 开发服务器。它利用原生 ES 模块,无需打包即可提供极速的模块服务,并支持热模块替换(HMR) 。当你修改HelloWorld.vue或App.vue时,浏览器会即时更新,而无需刷新整个页面。npm run build: 使用 Vite 构建生产版本。它会利用 Rollup 进行代码分割、压缩和优化,生成部署就绪的静态文件。npm run preview: 本地预览构建后的生产版本,用于在部署前进行最终检查。
📚 总结:Vue 开发范式的转变
正如 readme.md 中所强调的,Vue 的开发方式与传统 DOM 操作有着本质区别:
- 传统方式:
找到元素 -> 修改元素。开发者的心智负担在于如何精确地定位和操作 DOM 节点。 - Vue 方式:
思考数据 -> 修改数据。开发者只需关注业务逻辑和数据流,Vue 负责将数据的变化高效地映射到视图上。
这种声明式的编程模型极大地提升了开发效率和代码的可维护性。通过 v-for、v-if、v-model、computed 等 API,我们可以用接近自然语言的方式描述 UI 应该是什么样子,而不是一步步告诉浏览器如何去构建它。
这个 Todos 应用虽小,却完整地展示了 Vue 3 Composition API 的强大之处,以及 Vite 如何为现代前端开发提供卓越的体验。