发布时间:2026/9/2 9:59:43
Vue 3 极简速成:从零构建任务管理器,掌握组合式API与Pinia 最近在带新人上手前端项目时发现很多同学对 Vue 3 望而却步觉得组合式 API、响应式系统、构建工具等概念复杂网上教程要么太旧还在讲 Options API要么太散只讲某个 API。其实Vue 3 的核心思想非常清晰上手也很快。本文旨在用最短的路径带你从零搭建一个可运行的 Vue 3 项目理解其核心概念并完成一个具备增删改查功能的小应用。学完后你将能独立配置开发环境、编写组件、管理状态并具备继续深入学习的能力。1. Vue 3 核心概念速览为什么是现在学它的最佳时机在深入代码之前我们需要理解 Vue 3 带来的根本性变化及其设计哲学。这能帮助你在后续编码时不仅知道“怎么做”更明白“为什么这么做”。1.1 组合式 API (Composition API) vs 选项式 API (Options API)这是 Vue 3 最标志性的特性。传统的选项式 API 将代码按照data、methods、computed、lifecycle等选项进行组织。对于小型组件这很清晰。但当组件逻辑变得复杂时与同一个功能相关的代码例如一个“用户搜索”功能可能涉及响应式数据、计算属性、方法、生命周期钩子会被拆分到不同的选项块中导致阅读和维护时需要不断上下滚动逻辑关注点分散。组合式 API 则允许你使用导入的函数如ref,reactive,computed,onMounted来定义组件的逻辑。你可以像编写普通 JavaScript 函数一样将相关联的代码组织在一起。这使得逻辑复用更强大可以轻松地将一组相关的响应式状态和函数提取为“组合式函数”在多个组件间复用。代码组织更灵活不再受限于固定的选项模板可以按功能而非选项类型来组织代码。更好的 TypeScript 支持组合式函数能提供更完善的类型推导。简单来说选项式 API 是“按选项类型分文件柜”组合式 API 是“按业务功能打包行李”。Vue 3 完全支持两种写法但组合式 API 是未来的主流和官方推荐。1.2 响应式系统的革新ref与reactiveVue 3 的响应式系统基于 ES6 的Proxy重写性能更好能力更强。它主要通过两个函数暴露给开发者ref()用于定义响应式的基本类型值如string,number,boolean。它返回一个带有.value属性的响应式对象。在模板中会自动解包无需写.value在 JavaScript 中则需要。import { ref } from vue const count ref(0) // 创建一个响应式引用初始值为0 console.log(count.value) // 访问值 count.value // 修改值reactive()用于定义响应式的对象。它返回一个对象的响应式代理。import { reactive } from vue const state reactive({ count: 0, name: Vue }) console.log(state.count) // 直接访问属性 state.count // 直接修改属性关键选择通常基础类型用ref对象用reactive。但在组合式函数中统一使用ref有时更便于保持返回值结构的一致性。1.3 其他重要新特性script setup语法糖一种更简洁的编写单文件组件的方式。它是在script标签上添加setup属性让代码更接近纯粹的 JavaScript大幅减少模板代码。本文实战部分将全程使用它。Teleport可以将组件的一部分模板“传送”到 DOM 中的其他位置如 body 末尾常用于模态框、通知框。Fragments组件可以拥有多个根节点。更好的性能更小的打包体积、更快的渲染速度、更高效的重渲染机制。理解了这些我们就有了坚实的理论基础。接下来从环境搭建开始实战。2. 环境准备与项目创建我们将使用 Vue 官方的构建工具 Vite 来创建项目它比传统的 Webpack 更快、更轻量。2.1 环境要求Node.js请确保已安装 Node.js (版本 14.18, 16 或更高)。在终端运行node -v检查。包管理器可以使用 npm (随 Node.js 安装) 或 yarn、pnpm。本文使用 npm 进行演示。代码编辑器推荐使用 Visual Studio Code并安装 Vue 官方扩展 “Volar”。2.2 使用 Vite 创建 Vue 3 项目打开终端命令行执行以下命令# 使用 npm 6.x npm create vuelatest my-vue3-app # 使用 npm 7, 需要额外的双横线 npm create vuelatest my-vue3-app # 使用 yarn yarn create vue my-vue3-app # 使用 pnpm pnpm create vue my-vue3-app执行后你会看到一个交互式的项目配置向导。我们做如下选择Project name: 直接回车使用my-vue3-app或输入你的项目名。Add TypeScript?:No(本文为简化先不使用 TS但实际项目强烈建议使用)。Add JSX Support?:No。Add Vue Router for Single Page Application development?:No(本文先聚焦核心后续可自行添加)。Add Pinia for state management?:Yes(这是 Vue 官方推荐的状态管理库类似 Vuex但更简单我们稍后会用到)。Add Vitest for Unit Testing?:No。Add an End-to-End Testing Solution?: None。Add ESLint for code quality?:Yes(代码规范检查建议开启)。Add Prettier for code formatting?:Yes(代码格式化建议开启)。配置完成后进入项目目录并安装依赖cd my-vue3-app npm install2.3 项目结构初探创建完成后项目目录结构如下my-vue3-app/ ├── node_modules/ # 项目依赖包 ├── public/ # 静态资源如图标 │ └── favicon.ico ├── src/ # 源代码目录 │ ├── assets/ # 资源文件如图片、样式 │ ├── components/ # 可复用组件 │ │ └── HelloWorld.vue │ ├── stores/ # Pinia 状态管理 store因为我们选择了 Pinia │ │ └── counter.js │ ├── App.vue # 应用根组件 │ └── main.js # 应用入口文件 ├── .gitignore ├── index.html # HTML 模板 ├── package.json # 项目配置和依赖 ├── vite.config.js # Vite 配置 └── ... (其他配置文件)现在可以启动开发服务器了npm run dev终端会输出本地服务器地址通常是http://localhost:5173。用浏览器打开它你将看到 Vue 的默认欢迎页面。我们的速成之旅将从改造这个页面开始。3. 核心语法与script setup初体验让我们先清理默认页面创建一个最简单的计数器组件来熟悉组合式 API 和script setup。3.1 改造App.vue打开src/App.vue文件用以下代码完全替换!-- src/App.vue -- script setup import { ref } from vue import MyCounter from ./components/MyCounter.vue const appTitle ref(Vue 3 极简速成 Demo) /script template div classapp h1{{ appTitle }}/h1 p这是一个使用 Vue 3 Composition API 和 script setup 构建的简单应用。/p MyCounter / /div /template style scoped .app { font-family: Arial, sans-serif; max-width: 800px; margin: 40px auto; padding: 20px; text-align: center; } h1 { color: #42b883; /* Vue 主题色 */ } /style代码解析script setup声明使用组合式 API 的语法糖。在这里面声明的顶级变量、函数、import 都会自动暴露给模板。import { ref } from vue从 Vue 中导入ref函数。const appTitle ref(...)创建一个响应式的字符串引用。在模板中直接用{{ appTitle }}使用无需.value。MyCounter /引入并使用了我们即将创建的子组件。3.2 创建第一个组件MyCounter.vue在src/components目录下新建文件MyCounter.vue并写入!-- src/components/MyCounter.vue -- script setup import { ref, computed, onMounted } from vue // 1. 使用 ref 定义响应式数据 const count ref(0) const step ref(1) // 2. 使用 computed 定义计算属性 const doubleCount computed(() count.value * 2) const countParity computed(() count.value % 2 0 ? 偶数 : 奇数) // 3. 定义方法 function increment() { count.value step.value } function decrement() { count.value - step.value } function reset() { count.value 0 step.value 1 } // 4. 使用生命周期钩子 onMounted(() { console.log(计数器组件已挂载初始值为, count.value) }) /script template div classcounter h2计数器示例/h2 div classdisplay p当前值: strong{{ count }}/strong/p p双倍值: strong{{ doubleCount }}/strong/p p奇偶性: strong{{ countParity }}/strong/p /div div classcontrols label 步长: input typenumber v-model.numberstep min1 / /label button clickdecrement-/button button clickincrement/button button clickreset重置/button /div p classhint尝试修改步长然后点击加减按钮。/p /div /template style scoped .counter { border: 2px solid #42b883; border-radius: 10px; padding: 20px; margin-top: 20px; background-color: #f9f9f9; } .display { margin-bottom: 15px; font-size: 1.1em; } .controls { display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 15px; } .controls button { padding: 8px 16px; font-size: 1.2em; cursor: pointer; background-color: #42b883; color: white; border: none; border-radius: 5px; } .controls button:hover { background-color: #33a06f; } .controls input { padding: 5px; width: 60px; text-align: center; margin-right: 10px; } .hint { font-size: 0.9em; color: #666; } /style核心知识点响应式数据count和step通过ref创建。注意在 JavaScript 中修改需要.value在模板中则不需要。计算属性doubleCount和countParity通过computed创建。它们依赖响应式数据并缓存结果只有依赖变化时才重新计算。方法直接声明函数即可模板中通过click等指令绑定。生命周期通过onMounted等函数注册生命周期钩子。模板语法{{ }}文本插值。v-model.numberstep双向数据绑定。.number修饰符确保输入值被转为数字类型。click事件监听。保存所有文件浏览器中的页面会自动更新。你现在应该能看到一个功能完整的计数器可以修改步长并进行加减操作。控制台会输出组件挂载的日志。4. 实战构建一个简易任务管理器 (Todo List)现在我们运用所学构建一个更实用的功能任务管理器。它将涵盖列表渲染、条件渲染、事件处理、组件通信等核心概念。4.1 设计数据结构与状态首先在src/components目录下创建TodoList.vue。一个任务Todo对象通常包含id唯一标识、text内容、completed是否完成。我们将任务列表定义为响应式数组。!-- src/components/TodoList.vue -- script setup import { ref, computed } from vue // 定义任务类型 // 使用一个简单的自增ID生成器 let nextId 0 function generateId() { return nextId } // 响应式任务列表 const todos ref([ { id: generateId(), text: 学习 Vue 3 基础, completed: true }, { id: generateId(), text: 完成速成实战项目, completed: false }, { id: generateId(), text: 阅读官方文档, completed: false } ]) // 响应式的新任务文本 const newTodoText ref() /script template div classtodo-list h2我的任务清单/h2 !-- 后续步骤将填充这里 -- /div /template style scoped .todo-list { border: 2px solid #35495e; border-radius: 10px; padding: 20px; margin-top: 30px; background-color: #fff; } /style4.2 实现添加任务功能在script setup中添加添加任务的方法并在模板中创建输入表单。script setup // ... 之前的代码保持不变 // 添加新任务的方法 function addTodo() { const trimmedText newTodoText.value.trim() if (!trimmedText) { alert(任务内容不能为空) return } todos.value.push({ id: generateId(), text: trimmedText, completed: false }) newTodoText.value // 清空输入框 } /script template div classtodo-list h2我的任务清单/h2 !-- 添加新任务表单 -- div classadd-todo input typetext v-modelnewTodoText keyup.enteraddTodo placeholder输入新任务按回车添加 / button clickaddTodo添加/button /div !-- 任务列表区域 -- div classlist-container p v-iftodos.length 0暂无任务添加一个吧/p ul v-else !-- 我们将在这里渲染任务列表 -- /ul /div /div /template style scoped /* ... 之前的样式保持不变 ... */ .add-todo { display: flex; gap: 10px; margin-bottom: 20px; } .add-todo input { flex: 1; padding: 10px; border: 1px solid #ccc; border-radius: 5px; font-size: 1em; } .add-todo button { padding: 10px 20px; background-color: #42b883; color: white; border: none; border-radius: 5px; cursor: pointer; } .add-todo button:hover { background-color: #33a06f; } .list-container { min-height: 100px; } /style知识点v-model绑定输入框。keyup.enter监听回车键事件。v-if/v-else进行条件渲染。4.3 渲染任务列表与状态切换现在渲染任务列表并为每个任务添加完成状态切换和删除功能。script setup // ... 之前的代码保持不变 // 切换任务完成状态 function toggleTodo(todo) { todo.completed !todo.completed } // 删除任务 function deleteTodo(id) { // 过滤掉 id 不匹配的任务实现删除 todos.value todos.value.filter(todo todo.id ! id) } /script template div classtodo-list h2我的任务清单/h2 !-- ... 添加任务表单保持不变 ... -- !-- 任务列表区域 -- div classlist-container p v-iftodos.length 0暂无任务添加一个吧/p ul v-else li v-fortodo in todos :keytodo.id :class{ completed: todo.completed } input typecheckbox :checkedtodo.completed changetoggleTodo(todo) / span classtodo-text{{ todo.text }}/span button classdelete-btn clickdeleteTodo(todo.id)×/button /li /ul /div /div /template style scoped /* ... 之前的样式保持不变 ... */ ul { list-style: none; padding: 0; } li { display: flex; align-items: center; padding: 12px; margin-bottom: 8px; background-color: #f8f9fa; border-radius: 6px; border-left: 4px solid #42b883; } li.completed { opacity: 0.7; border-left-color: #ccc; } li.completed .todo-text { text-decoration: line-through; color: #888; } .todo-text { flex: 1; margin-left: 10px; text-align: left; } .delete-btn { background: none; border: none; color: #ff6b6b; font-size: 1.5em; cursor: pointer; line-height: 1; padding: 0 5px; } .delete-btn:hover { color: #ff4757; } /style知识点v-fortodo in todos列表渲染。:keytodo.id为每个迭代项提供唯一的 keyVue 用它来高效更新 DOM。:class{ completed: todo.completed }动态绑定 CSS 类。:checked属性绑定。change和click事件处理。4.4 添加统计功能与筛选器最后我们添加一个统计区域显示任务总数、完成数并提供一个筛选器来查看所有/进行中/已完成的任务。script setup import { ref, computed } from vue // ... 之前的 todos, newTodoText, 方法等保持不变 ... // 定义筛选类型 const filter ref(all) // all, active, completed // 计算属性根据筛选器过滤后的任务列表 const filteredTodos computed(() { switch (filter.value) { case active: return todos.value.filter(todo !todo.completed) case completed: return todos.value.filter(todo todo.completed) default: return todos.value } }) // 计算属性统计信息 const stats computed(() { const total todos.value.length const completed todos.value.filter(todo todo.completed).length const active total - completed return { total, completed, active } }) /script template div classtodo-list h2我的任务清单/h2 !-- 统计信息 -- div classstats span总计: strong{{ stats.total }}/strong/span span进行中: strong{{ stats.active }}/strong/span span已完成: strong{{ stats.completed }}/strong/span /div !-- 筛选器 -- div classfilters button :class{ active: filter all } clickfilter all 全部/button button :class{ active: filter active } clickfilter active 进行中/button button :class{ active: filter completed } clickfilter completed 已完成/button /div !-- ... 添加任务表单保持不变 ... -- !-- 任务列表区域现在渲染 filteredTodos -- div classlist-container p v-iffilteredTodos.length 0 {{ filter all ? 暂无任务添加一个吧 : filter active ? 没有进行中的任务。 : 没有已完成的任务。 }} /p ul v-else li v-fortodo in filteredTodos :keytodo.id :class{ completed: todo.completed } !-- ... 每个任务的复选框、文本、删除按钮保持不变 ... -- /li /ul /div /div /template style scoped /* ... 之前的样式保持不变 ... */ .stats { display: flex; justify-content: space-around; margin-bottom: 15px; padding: 10px; background-color: #e9ecef; border-radius: 5px; font-size: 0.9em; } .filters { display: flex; justify-content: center; gap: 10px; margin-bottom: 15px; } .filters button { padding: 6px 12px; border: 1px solid #ddd; background-color: white; border-radius: 4px; cursor: pointer; } .filters button.active { background-color: #42b883; color: white; border-color: #42b883; } /style4.5 在 App.vue 中集成组件最后在src/App.vue中引入并使用我们的TodoList组件。!-- src/App.vue 更新后 -- script setup import { ref } from vue import MyCounter from ./components/MyCounter.vue import TodoList from ./components/TodoList.vue // 引入新组件 const appTitle ref(Vue 3 极简速成 Demo) /script template div classapp h1{{ appTitle }}/h1 p这是一个使用 Vue 3 Composition API 和 script setup 构建的简单应用。/p MyCounter / TodoList / !-- 使用任务列表组件 -- /div /template style scoped .app { font-family: Arial, sans-serif; max-width: 800px; margin: 40px auto; padding: 20px; text-align: center; } h1 { color: #42b883; } /style保存所有文件你的浏览器中现在应该展示一个包含计数器和完整任务管理器的应用了你可以添加任务、标记完成、删除任务并使用筛选器查看不同状态的任务列表。5. 状态管理入门使用 Pinia当应用变大多个组件需要共享状态时我们就需要状态管理。Vue 3 官方推荐使用Pinia。它比 Vuex 更简单、类型安全且与组合式 API 是天作之合。我们在创建项目时已经安装了 Pinia现在来使用它。5.1 创建一个 StoreStore 是一个保存状态和业务逻辑的实体。我们在src/stores目录下创建一个todoStore.js。// src/stores/todoStore.js import { defineStore } from pinia import { ref, computed } from vue // defineStore 的第一个参数是 store 的唯一 ID export const useTodoStore defineStore(todo, () { // State: 相当于组件中的 data const todos ref([]) let nextId 0 // Getters: 相当于组件中的 computed const completedTodos computed(() todos.value.filter(todo todo.completed)) const activeTodos computed(() todos.value.filter(todo !todo.completed)) const stats computed(() ({ total: todos.value.length, completed: completedTodos.value.length, active: activeTodos.value.length })) // Actions: 相当于组件中的 methods function addTodo(text) { const trimmedText text.trim() if (!trimmedText) return todos.value.push({ id: nextId, text: trimmedText, completed: false }) } function toggleTodo(id) { const todo todos.value.find(t t.id id) if (todo) { todo.completed !todo.completed } } function deleteTodo(id) { todos.value todos.value.filter(todo todo.id ! id) } function clearCompleted() { todos.value todos.value.filter(todo !todo.completed) } // 必须返回 state 和 actions return { todos, completedTodos, activeTodos, stats, addTodo, toggleTodo, deleteTodo, clearCompleted } })5.2 在组件中使用 Store现在我们修改TodoList.vue组件使其使用 Pinia Store 来管理状态。!-- src/components/TodoList.vue (使用 Pinia 版本) -- script setup import { ref, computed } from vue import { useTodoStore } from ../stores/todoStore // 导入 store // 在 setup 中调用 useTodoStore() 来获取 store 实例 const todoStore useTodoStore() // 本地状态筛选器和输入框文本 const filter ref(all) const newTodoText ref() // 使用 store 中的计算属性 const filteredTodos computed(() { switch (filter.value) { case active: return todoStore.activeTodos case completed: return todoStore.completedTodos default: return todoStore.todos } }) // 使用 store 中的 actions function addTodo() { todoStore.addTodo(newTodoText.value) newTodoText.value } function toggleTodo(id) { todoStore.toggleTodo(id) } function deleteTodo(id) { todoStore.deleteTodo(id) } function clearCompleted() { todoStore.clearCompleted() } /script template div classtodo-list h2我的任务清单 (Pinia 状态管理)/h2 !-- 统计信息数据来自 store -- div classstats span总计: strong{{ todoStore.stats.total }}/strong/span span进行中: strong{{ todoStore.stats.active }}/strong/span span已完成: strong{{ todoStore.stats.completed }}/strong/span button v-iftodoStore.stats.completed 0 clickclearCompleted classclear-btn 清除已完成 /button /div !-- ... 筛选器、添加表单、任务列表的模板部分与之前几乎完全相同 ... -- !-- 只需将之前的方法调用替换为调用 store 的 actions数据绑定替换为 store 的 state/getters -- !-- 例如v-fortodo in filteredTodos, changetoggleTodo(todo.id) -- div classfilters button :class{ active: filter all } clickfilter all全部/button button :class{ active: filter active } clickfilter active进行中/button button :class{ active: filter completed } clickfilter completed已完成/button /div div classadd-todo input typetext v-modelnewTodoText keyup.enteraddTodo placeholder输入新任务按回车添加 / button clickaddTodo添加/button /div div classlist-container p v-iffilteredTodos.length 0 {{ filter all ? 暂无任务添加一个吧 : filter active ? 没有进行中的任务。 : 没有已完成的任务。 }} /p ul v-else li v-fortodo in filteredTodos :keytodo.id :class{ completed: todo.completed } input typecheckbox :checkedtodo.completed changetoggleTodo(todo.id) / span classtodo-text{{ todo.text }}/span button classdelete-btn clickdeleteTodo(todo.id)×/button /li /ul /div /div /template style scoped /* ... 样式保持不变可添加 .clear-btn 的样式 ... */ .clear-btn { margin-left: 15px; padding: 3px 8px; font-size: 0.8em; background-color: #ff6b6b; color: white; border: none; border-radius: 3px; cursor: pointer; } .clear-btn:hover { background-color: #ff4757; } /style关键变化组件不再自己管理todos数组和nextId这些状态移到了 Store 中。组件通过useTodoStore()获取 store 实例然后访问其状态 (todoStore.todos) 和调用其方法 (todoStore.addTodo())。逻辑更加清晰状态管理被抽离组件只负责视图和用户交互。现在如果有另一个组件也需要读取或修改任务列表它只需要导入并使用同一个useTodoStore()状态自然就是共享的。这就是 Pinia 的强大之处。6. 常见问题与排查思路在学习和使用 Vue 3 的过程中你可能会遇到一些典型问题。这里列出几个高频问题及其解决方法。问题现象可能原因解决思路模板中数据不更新1. 数据不是响应式的。2. 直接修改了数组/对象的属性未触发响应。1. 确保使用ref或reactive创建数据。2. 对于reactive对象直接赋值新属性不会响应。应使用Object.assign或解构。对于数组避免使用索引直接赋值使用push、splice或返回新数组。ref值在 JS 中访问报错或不对忘记了.value。在script setup的 JavaScript 部分访问ref变量必须使用.value。在模板中则不需要。组件引入后无法使用1. 组件未正确导入或注册。2. 使用了选项式 API 但未在components选项中注册。1. 检查导入路径是否正确。2. 在script setup中import 的组件会自动注册。如果使用普通的script需要在components选项中注册。Pinia store 获取不到数据1. Store 未在应用级别挂载。2. 在setup()外使用了 store。1. 确保在main.js中正确创建并安装了 Pinia 插件。2. 必须在setup()函数或script setup中调用useXxxStore()。Vite 开发服务器无法启动1. 端口被占用。2. Node.js 版本过低。3. 依赖安装不完整。1. 尝试npm run dev -- --port 3000指定其他端口。2. 升级 Node.js 到 LTS 版本。3. 删除node_modules和package-lock.json重新运行npm install。script setup中定义的方法在模板中找不到方法未在顶层声明或包裹在了其他作用域内。确保所有需要暴露给模板的变量、函数都在script setup的顶层作用域中定义。7. 最佳实践与下一步学习建议恭喜你完成了 Vue 3 的核心速成为了写出更健壮、可维护的代码请遵循以下最佳实践并规划你的下一步学习路径。7.1 编码最佳实践优先使用script setup对于新项目和新组件这是官方推荐的写法更简洁TypeScript 支持更好。合理的组件拆分当一个组件变得过于庞大逻辑复杂、模板过长时考虑将其拆分为多个更小、职责更单一的组件。使用组合式函数抽离逻辑将可复用的响应式逻辑如获取数据、监听窗口大小提取到独立的组合式函数中通常放在composables/目录下。为列表渲染始终提供keyv-for指令中的:key必须是唯一且稳定的标识符如数据库 ID不要使用数组索引。谨慎使用v-if和v-for在同一元素Vue 3 中这会导致错误。如果需要条件渲染列表可以在外层包裹一个template标签使用v-for在内层元素使用v-if。状态管理选择对于简单的父子组件通信使用props和emit。对于跨层级、非父子组件共享状态或状态逻辑复杂时使用 Pinia。样式作用域在单文件组件中使用style scoped来限制样式只作用于当前组件避免全局污染。7.2 工程化建议启用 ESLint 和 Prettier我们在创建项目时已经选择了它们。它们能自动规范代码格式和发现潜在错误保持团队代码风格一致。使用 TypeScript对于任何严肃的项目强烈建议使用 TypeScript。它能提供强大的类型检查减少运行时错误提升开发体验。创建项目时可以选择添加。路由管理当应用有多个页面时需要引入 Vue Router。使用npm install vue-router安装并配置路由表。HTTP 请求库推荐使用axios或fetch进行网络请求。可以将其封装成统一的请求模块便于管理拦截器、基地址等。构建与部署使用npm run build进行生产构建生成的静态文件位于dist目录可以部署到任何静态文件服务器或云服务。7.3 下一步学习路线你已经掌握了 Vue 3 的核心。要成为一名合格的 Vue 开发者建议按以下顺序深入学习官方文档通读 Vue 3 官方文档的基础和深入组件章节这是最权威的学习资料。Vue Router学习如何构建单页面应用 (SPA)管理路由、导航守卫、懒加载等。状态管理进阶深入学习 Pinia了解 Store 的模块化、持久化、插件等高级用法。组合式 API 进阶学习watch、watchEffect、provide/inject、自定义指令、Teleport、Suspense 等高级特性。生态工具学习使用 Vue Devtools 进行调试了解 Vite 的更多配置学习单元测试 (如 Vitest) 和端到端测试 (如 Cypress)。UI 组件库根据项目需求学习使用一个成熟的 UI 组件库如 Element Plus、Ant Design Vue、Vuetify 等能极大提升开发效率。实战项目找一个完整的项目点子如博客系统、后台管理前端综合运用所学知识进行开发这是巩固技能的最佳方式。本文的完整项目源码已包含计数器、任务管理器含 Pinia 版本等所有示例代码你可以基于此进行扩展和练习。记住编程是门实践的艺术多写、多思考、多查阅文档你很快就能驾驭 Vue 3。如果在实践中遇到具体问题CSDN 社区和官方文档是你最好的朋友。

相关新闻

2026/9/2 9:59:43

戴森HT01美发造型器深度评测:如何理性评估高价美发工具的价值

最近在整理家里的电器,发现一个挺有意思的现象:很多朋友,尤其是对生活品质有要求的朋友,在选购美发工具时,会陷入一种“技术崇拜”和“价格焦虑”的混合状态。一边是传统吹风机、卷发棒几十到几百元的价格区间&#xf…

2026/9/2 9:59:43

需求池到发布清单:如何做好产品迭代的功能取舍

“下周该发布什么功能”,如果这句话出现在你们每周的例会上,说明团队已经进入一个相对稳定的迭代周期。但稳定不等于顺利。我见过不少产品研发团队,需求池里躺着几十条记录,产品经理觉得每条都紧急,研发组长说下个版本…

2026/9/2 10:09:47

Spewer:用模型路由为 Codex CLI 与 Claude Code 降低 API 成本

现在很多开发者的日常已经离不开 Codex CLI 和 Claude Code,但到了月底看 API 账单,心态往往就变了。简单任务用旗舰模型,成本偏高;复杂任务用便宜模型,又容易反复返工。Spewer 就是冲着这个场景来的:它把 …

2026/9/2 10:09:47

Spring Boot 3.x与Vue 3全栈实战:手把手搭建美食点餐系统

在实际 Java Web 项目开发中,一个功能完整、前后端分离的“美食菜谱点餐系统”是检验全栈能力非常好的练手项目。它涵盖了用户管理、菜品展示、购物车、订单处理等核心业务模块,同时要求开发者对 Spring Boot 后端 API 设计、Vue3 前端工程化、数据库设计…

2026/9/2 10:09:47

东软Java面试题深度解析:从核心原理到实战技巧

简介:本资源是面向Java求职者、特别是冲刺东软Java开发岗位的面试专项题库,聚焦基础语法、集合框架、多线程、JVM内存模型、反射、Spring核心机制及Java 8新特性等高频考点,助力候选人精准把握东软技术面试重点与考察逻辑。压缩包共13个文件&…

2026/9/2 10:09:47

STM32C542R入门实战:从零点亮LED,掌握嵌入式开发全流程

如果你刚开始接触 STM32,可能会觉得它很复杂:各种型号、开发环境、库函数、时钟配置……光是看手册就头大。但我想告诉你,学习 STM32 最好的方式,不是从复杂的理论开始,而是从一个最简单的目标入手—— 点亮一颗 LED …

2026/9/1 16:02:17

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/2 9:00:32

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/2 8:41:06

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/2 0:03:41

单片机毕业设计-基于单片机与蓝牙通讯的输液状态监测终端设计与开发 基于 STM32 或 51 单片机的液位‑滴速‑温度多参数输液监护装置设计(024005)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/9/2 0:03:41

DeepSeek字幕翻译实战:从API调用到批量SRT转中文的完整方案

这次我们来看一个很实用的 DeepSeek 落地场景:用 DeepSeek 把英文视频字幕自动翻译成中文。具体案例是《恶魔君》1989 年第 28 集的英转中字幕任务,标题写得很直白,但背后其实是一整套可以复用的技术流程:字幕解析、模型调用、批量…

2026/9/2 0:03:41

用Python搭建搞笑语音助手:从语音识别到语音合成全教程

当你家里摆着一台天猫精灵,却总希望语音助手偶尔“不正经”一点,不用官方腔回答问题,而是张口就接几句搞笑段子,会是什么体验?我最近动手验证了一下这个想法——没有去改装任何市面上现有的智能音箱,而是直…

2026/9/2 1:15:22

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/2 1:15:22

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/2 1:15:20

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…