
很多同学想学 Vue 3但容易被网上零散的教程劝退有的只讲语法不讲项目有的直接扔源码不讲思路有的是 Vue 2 老教程换个标题就开卖。恰逢 2026 年Vue 3 早已是国内外企业级前端项目的事实标准。如果你正打算入门前端或者从 Vue 2 跳到 Vue 3又或者想快速把一个能跑起来的 Vue 3 项目搭好这篇文章就是为你准备的。本文将用一套闭环学习路径带你走完 Vue 3 从环境准备、核心语法、组件通信到实战项目的全过程。不堆砌概念每个知识点都配有可复制的代码示例和解释每段代码都说明“放哪个文件、干什么用、为什么这么写”。学完以后你不仅能看懂 Vue 3 项目还能自己动手写出一个具备路由、状态管理、组件化开发的完整应用。无论你是零基础小白还是工作后需要技术栈升级的开发者这篇 Vue3 入门加进阶教程都能帮你在最短时间里建立起完整的前端知识框架。1. Vue 3 概念与背景1.1 Vue 3 是什么Vue读作 /vjuː/类似 view是一套用于构建用户界面的渐进式 JavaScript 框架。所谓“渐进式”指的是 Vue 可以按需使用你可以在一个页面中引入 Vue 处理简单的数据绑定也可以用 Vue Router、Pinia、Vite 等生态工具搭建一个完整的企业级单页应用SPA。Vue 3 是 Vue 框架的第三个大版本相比 Vue 2 在底层响应式原理、组件语法、TypeScript 支持、性能表现等多个方面都做了大幅升级。2026 年再看 Vue 3它已经不光是新特性而是主流招聘要求中前端岗位的基础技能。Vue 3 最核心的几个标签组合式 APIComposition API用更灵活的逻辑组织方式替代部分 Options API。响应式系统重写基于 Proxy 的响应式机制性能优于 Vue 2 的 Object.defineProperty。更友好的 TypeScript源码本身用 TS 编写类型推导更完善。Vite 构建工具秒级冷启动的开发服务器。1.2 为什么选择 Vue 3 而不是 Vue 2很多初学者会问Vue 2 资料多、语法简单为什么不继续学 Vue 2情况确实如此但 Vue 2 已于 2023 年 12 月 31 日停止官方维护也就是说 Vue 2 不会再有新的功能更新长期使用存在安全和兼容性隐患。而 Vue 3 已经是社区、企业、开源项目生态围绕的中心版本几乎所有活跃组件库Element Plus、Ant Design Vue、Vant 等都已全面转向支持 Vue 3。此外Vue 3 带来的组合式 API 让代码更易于复用和测试。当一个组件包含大量关联逻辑时Vue 2 的 data、methods、computed 会把同一业务逻辑切碎到不同选项里代码长了以后阅读成本很高Vue 3 组合式 API 允许你按业务功能聚合代码和维护人员大脑中的认知模型保持一致。1.3 Vue 3 的常见应用场景中后台管理系统这是一个主力场景配合 Element Plus 等组件库能快速搭建表格、表单、权限、图表等复杂页面。移动端 H5 应用配合 Vant 等移动端组件库实现移动端页面开发。企业官网与营销页面Vue 的渐进式特性让这种轻量场景也可以直接使用。小程序与跨端开发uni-app 等跨端框架已全面兼容 Vue 3 语法。桌面应用Electron Vue 3 可以构建跨平台桌面软件。1.4 Vue 2 和 Vue 3 的主要区别对比项Vue 2Vue 3响应式原理Object.defineProperty 拦截属性Proxy 拦截对象操作API 风格Options API 为主Composition API 为主兼容 Options API数据声明data() 返回对象ref、reactive生命周期beforeCreate、created 等onMounted、onUpdated 等setup 中调用组件通信$emit、$on、event bus$emit、defineProps、defineEmits、provide/inject构建工具Vue CLIwebpack为主Vite 官方推荐TypeScript支持有限原生友好类型推导完整性能较好更优包体积更小渲染更快2. 环境准备与版本说明在动手写代码之前先把开发环境搭好。这一步很多新手会踩坑所以下面把每个环节的操作和验证方式都写清楚。2.1 安装 Node.js 与 npmVue 3 项目高度依赖 Node.js 环境。无论你使用 Vite 还是 Vue CLI都需要 Node.js 提供运行环境。打开 Node.js 官网nodejs.org建议选择 LTSLong Term Support版本下载安装。LTS 版本意味着长期维护适合生产和学习。版本建议Node.js 18.0.0 npm 9.0.0如果你的电脑已经装过 Node.js可以打开终端Windows 使用 PowerShell 或 CMDmacOS 使用 Terminal执行以下命令查看版本node -v npm -v如果输出类似v20.11.0 10.2.4说明环境正常。如果版本过低建议直接到官网下载对应安装包重新安装比在终端里折腾升级更省心。2.2 选择构建工具ViteVite 是 Vue 官方推荐的构建工具。它基于原生 ES Module在开发环境下可以做到按需编译启动速度快到“秒开”。Vite 的核心优势开发服务器启动快不用等待整个项目打包完成。热更新HMR快保存代码后页面局部刷新。配置简单开箱即用。生产构建基于 Rollup产物干净。在 Vue 3 项目中建议直接使用 Vite而不是继续使用 Vue CLI。Vue CLI 不是不能用只是 Vite 已经成为更主流的选择。2.3 安装 IDE 与插件强烈建议使用 Visual Studio CodeVSCode。它免费、轻量、插件生态丰富算是前端开发最常用的编辑器。安装完成后打开扩展面板搜索并安装以下两个插件Vue Official原 VolarVue 3 的官方语言支持插件提供模板语法高亮、类型检查、自动补全等功能。ESLint统一代码规范提前发现低级错误。这里需要提醒如果你以前安装过 Vetur 插件Vue 2 时代常用的插件使用 Vue 3 项目时建议禁用它避免与 Volar 冲突。2.4 创建第一个 Vue 3 项目打开终端执行以下命令npm create vuelatest这个命令会启动 Vue 官方脚手架工具引导你创建一个 Vue 3 项目。运行过程中会询问一些配置选项例如✔ Project name: … vue3-demo ✔ Add TypeScript? … No / Yes ✔ Add JSX Support? … No / Yes ✔ Add Vue Router for Single Page Application development? … No / Yes ✔ Add Pinia for state management? … No / Yes ✔ Add ESLint for code quality? … No / Yes对于初学者建议先全部选择 No快速创建一个最简项目骨架把核心概念弄清楚后再逐步引入 TypeScript、Router、Pinia。项目创建完成后进入目录并安装依赖cd vue3-demo npm install然后启动开发服务器npm run dev启动成功后终端会显示一个本地访问地址通常类似➜ Local: http://localhost:5173/在浏览器打开这个地址看到 Vue 官方欢迎页面说明环境搭建成功。2.5 项目结构说明一个使用 Vite 创建的最小 Vue 3 项目主要文件如下vue3-demo/ ├── index.html ├── package.json ├── vite.config.js └── src/ ├── main.js ├── App.vue └── components/ └── HelloWorld.vueindex.html整个应用的 HTML 入口Vite 会在这里注入构建后的脚本。src/main.js应用的入口文件负责创建 Vue 应用实例并挂载到页面。src/App.vue根组件可以理解为整棵组件树的根节点。src/components/存放可复用的子组件。vite.config.jsVite 配置文件用来设置代理、别名等。3. Vue 3 核心语法拆解这一节是学习 Vue 3 的重头戏。先掌握模板语法、响应式数据、计算属性和监听器再进入组合式 API 的进阶用法。3.1 模板语法Vue 组件中的模板部分使用类似 HTML 的结构但加入了 Vue 特有的指令和表达式。文本插值最基础的数据展示方式使用双大括号template p{{ message }}/p /template script setup const message Hello Vue 3 /scriptmessage 变量中的值会被动态渲染到p标签内部。v-bind 绑定属性HTML 标签的原生属性比如href、src、class等需要用v-bind指令绑定template a v-bind:hrefurl跳转链接/a !-- v-bind 可以简写为冒号 -- img :srcimgUrl alt示例图片 /template script setup const url https://vuejs.org const imgUrl ./images/demo.png /script使用:属性名的简写方式是 Vue 3 项目中更常见的写法。v-if 与 v-for 指令v-if表示条件渲染只有表达式为真时才渲染元素。v-for用于列表循环渲染template p v-ifisShow条件为真时显示/p ul li v-foritem in list :keyitem.id{{ item.name }}/li /ul /template script setup const isShow true const list [ { id: 1, name: 张三 }, { id: 2, name: 李四 }, { id: 3, name: 王五 } ] /scriptv-for中的:key是必须的它帮助 Vue 精确识别每个列表项的身份在列表数据变化时减少不必要的 DOM 操作。v-model 双向绑定表单输入场景中最常用的指令可以实现数据与表单元素的双向同步template input v-modelusername typetext placeholder请输入用户名 p你输入的内容是{{ username }}/p /template script setup import { ref } from vue const username ref() /script用户在输入框内键入内容username 的值会同步变化反过来如果程序里修改 username输入框也会显示新值。3.2 响应式数据ref 与 reactiveVue 3 中声明响应式数据有两条主流路线ref和reactive。refref用于声明单个值的响应式数据可以包裹基本类型字符串、数字、布尔值也可以包裹对象和数组。import { ref } from vue const count ref(0) // 读取值 console.log(count.value) // 0 // 修改值 count.value 10在script setup中模板里使用 ref 变量时不需要写.valueVue 会自动解包。但在 JavaScript 逻辑中必须通过.value访问。template p{{ count }}/p button clickcount1/button /template script setup import { ref } from vue const count ref(0) /scriptreactivereactive用于声明对象类型的响应式数据。与 ref 不同它不需要.value包裹import { reactive } from vue const state reactive({ name: Vue 3, version: 3.4 }) // 直接访问 console.log(state.name) // 直接修改 state.version 3.5ref 与 reactive 怎么选这是 Vue 3 初学者最容易困惑的问题。简单建议单值类型字符串、数字、布尔值用 ref。复杂对象或表单数据集合用 reactive 更自然。如果你的项目风格偏团队规范化统一使用 ref 包裹也是常见做法ref 在 debug 和类型推导上表现更可控。3.3 计算属性computedcomputed用于声明一个根据其他响应式数据计算而来的值。它的最大特点是只有当依赖的数据变化时计算属性才会重新计算依赖数据没变时直接读取缓存的结果。import { ref, computed } from vue const price ref(100) const count ref(3) const total computed(() { return price.value * count.value }) console.log(total.value) // 300在模板中的用法template p单价{{ price }}/p p数量{{ count }}/p p总价{{ total }}/p button clickcount增加数量/button /templatetotal会根据 price 和 count 自动更新不需要手动调用任何函数。需要注意computed默认是只读的不要试图直接修改 computed 的值。如果确实需要“可写计算属性”需要传入带有 get 和 set 的对象但这在多数业务场景中并不常见。3.4 监听器watch 与 watchEffectwatch用于监听一个或多个响应式数据的变化并在变化后执行副作用操作。它的典型应用场景包括搜索框防抖、路由参数变化时的数据请求、某个状态变化后同步更新本地存储。基本用法import { ref, watch } from vue const keyword ref() watch(keyword, (newValue, oldValue) { console.log(搜索词从, oldValue, 变为, newValue) })监听多个数据时传入数组const name ref() const age ref(0) watch([name, age], ([newName, newAge], [oldName, oldAge]) { console.log(name 或 age 发生了变化) })如果需要监听对象内部属性的变化需要开启深度监听const user reactive({ name: 小明, profile: { age: 18 } }) watch( () user.profile.age, (newValue, oldValue) { console.log(年龄变化, newValue) } )使用watchEffect时回调函数中依赖了哪个响应式数据哪个数据变化时就会自动触发回调import { ref, watchEffect } from vue const count ref(0) watchEffect(() { console.log(count 现在是, count.value) }) count.value 1 count.value 2上面的代码执行后控制台会输出三行日志。第一次是立即执行后续是每次 count 变化时触发。3.5 生命周期函数Vue 3 组合式 API 中的生命周期函数统一以on开头使用前需要从 Vue 中导入。常用的几个生命周期函数作用onMounted组件挂载完成后执行适合发起接口请求、操作 DOMonUpdated组件更新完成后执行onUnmounted组件卸载前执行适合清除定时器、解绑事件onBeforeMount组件挂载前执行示例import { ref, onMounted, onUnmounted } from vue const count ref(0) let timer null onMounted(() { console.log(组件挂载完成) timer setInterval(() { count.value }, 1000) }) onUnmounted(() { console.log(组件卸载清除定时器) clearInterval(timer) })3.6script setup语法script setup是 Vue 3.2 引入的语法糖它让组合式 API 的写法更加简洁。在script setup中声明的变量、函数和导入默认可以直接在模板中使用不需要额外配置return暴露。一个完整的组件示例template div classuser-card h2{{ user.name }}/h2 p年龄{{ user.age }}/p button clickincreaseAge年龄 1/button /div /template script setup import { reactive } from vue const user reactive({ name: 小明, age: 18 }) const increaseAge () { user.age } /script这种写法减少了样板代码是目前 Vue 3 项目中最主流的单文件组件写法。4. 组件开发与组件通信组件是 Vue 应用的基石。把页面拆分成不同组件不仅有利于代码复用还让项目在多人协作时更容易维护。4.1 子组件如何接收父组件的数据父组件向子组件传递数据使用props。在子组件中定义 props!-- 文件路径src/components/ProductCard.vue -- template div classproduct-card h3{{ product.name }}/h3 p价格{{ product.price }}/p /div /template script setup defineProps({ product: { type: Object, required: true } }) /script在父组件中引入并传值template div ProductCard v-foritem in products :keyitem.id :productitem / /div /template script setup import { ref } from vue import ProductCard from ./components/ProductCard.vue const products ref([ { id: 1, name: Vue 实战课程, price: 99 }, { id: 2, name: 前端面试手册, price: 49 } ]) /script需要特别注意的是props 在子组件中是只读的不要直接修改 props 的值。如果确实需要修改应该通过父组件的事件来完成。4.2 子组件如何向父组件发送数据子组件通过defineEmits声明可以触发的事件然后通过emit发送数据!-- 文件路径src/components/Counter.vue -- template div p当前计数{{ count }}/p button clickemit(update:count, count 1)加一/button /div /template script setup defineProps({ count: { type: Number, default: 0 } }) const emit defineEmits([update:count]) /script父组件监听事件template Counter :counttotal update:counttotal $event / p父组件中的 total{{ total }}/p /template script setup import { ref } from vue import Counter from ./components/Counter.vue const total ref(0) /script4.3 使用 v-model 简化父子通信上面的写法可以简化为v-model。Vue 3 中v-model实际上是:modelValue和update:modelValue的语法糖。子组件template input :valuemodelValue input$emit(update:modelValue, $event.target.value) / /template script setup defineProps({ modelValue: { type: String, default: } }) defineEmits([update:modelValue]) /script父组件template CustomInput v-modelsearchText / /template script setup import { ref } from vue import CustomInput from ./components/CustomInput.vue const searchText ref() /script这种模式在后面封装通用表单组件时非常实用。4.4 跨层级通信provide 与 inject如果组件层级很深不想逐层传递 props 和 emit可以使用provide和inject。父组件通过provide提供数据任意后代组件通过inject获取数据。祖先组件script setup import { provide, ref } from vue const theme ref(light) provide(theme, theme) /script任意后代组件script setup import { inject } from vue const theme inject(theme) /script这个模式非常适合全局主题、用户信息、权限标识等共享数据的传递。5. 完整实战做一个待办事项应用了解基础语法后我们来动手做一个真正能运行的项目。这里选一个经典且五脏俱全的场景待办事项应用。这个项目会用到响应式数据、计算属性、v-for、组件拆分、事件通信非常适合检验上一节学到的知识。5.1 项目需求一个简单的待办事项应用需要具备输入框添加新待办事项。待办事项列表展示。支持标记完成和删除。通过计算属性展示未完成任务数量。5.2 创建组件结构在 src 目录下创建两个文件src/App.vue父组件管理数据和逻辑。src/components/TodoList.vue子组件展示列表并发送事件。src/components/TodoItem.vue子组件渲染单个待办事项。5.3 编写核心代码先修改src/App.vue!-- 文件路径src/App.vue -- template div classtodo-app h1Vue 3 待办事项/h1 div classinput-area input v-model.trimnewTodo typetext placeholder输入新的待办事项 keyup.enteraddTodo / button clickaddTodo添加/button /div p未完成任务{{ remainingCount }} 项/p TodoList :todostodos toggletoggleTodo removeremoveTodo / /div /template script setup import { ref, computed } from vue import TodoList from ./components/TodoList.vue const newTodo ref() const todos ref([ { id: 1, text: 学习 Vue 3 基础语法, done: false }, { id: 2, text: 完成一个实战项目, done: false } ]) const remainingCount computed(() { return todos.value.filter(item !item.done).length }) const addTodo () { if (newTodo.value ) { alert(请输入待办事项内容) return } todos.value.push({ id: Date.now(), text: newTodo.value, done: false }) newTodo.value } const toggleTodo (id) { const todo todos.value.find(item item.id id) if (todo) { todo.done !todo.done } } const removeTodo (id) { todos.value todos.value.filter(item item.id ! id) } /script style scoped .todo-app { max-width: 500px; margin: 50px auto; padding: 20px; border: 1px solid #eee; border-radius: 8px; } .input-area { display: flex; gap: 8px; } .input-area input { flex: 1; padding: 8px; } /style再创建src/components/TodoList.vue!-- 文件路径src/components/TodoList.vue -- template ul classtodo-list TodoItem v-fortodo in todos :keytodo.id :todotodo toggle$emit(toggle, todo.id) remove$emit(remove, todo.id) / /ul /template script setup import TodoItem from ./TodoItem.vue defineProps({ todos: { type: Array, required: true } }) defineEmits([toggle, remove]) /script最后创建src/components/TodoItem.vue!-- 文件路径src/components/TodoItem.vue -- template li classtodo-item :class{ done: todo.done } span click$emit(toggle){{ todo.text }}/span button click$emit(remove)删除/button /li /template script setup defineProps({ todo: { type: Object, required: true } }) defineEmits([toggle, remove]) /script style scoped .todo-item { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid #f0f0f0; } .todo-item.done span { text-decoration: line-through; color: #999; } /style5.4 运行与验证确保项目正在运行npm run dev在浏览器中打开页面在输入框中输入“学习 Vue Router”按回车或点击添加按钮。列表底部出现新条目未完成任务数量加 1。点击条目文字文字出现删除线未完成任务数量减 1。点击删除按钮该条目消失。整个流程就是 Vue 3 中“数据驱动视图”的标准实践你不需要手动操作 DOM只要修改数据页面就会自动同步。6. 项目工程化Vue Router 与 Pinia学会了组件化开发接下来要进入工程化阶段。在实际项目中一个完整的 Vue 3 应用基本都会用到 Vue Router路由和 Pinia状态管理。6.1 Vue Router 入门Vue Router 是 Vue 官方路由库负责管理单页应用中的页面跳转。在单页应用中切换页面并不会刷新整个浏览器而是通过路由映射关系动态替换页面组件。安装路由npm install vue-router4在src/router/index.js中配置路由// 文件路径src/router/index.js import { createRouter, createWebHistory } from vue-router import Home from ../views/Home.vue import About from ../views/About.vue const router createRouter({ history: createWebHistory(), routes: [ { path: /, name: home, component: Home }, { path: /about, name: about, component: About } ] }) export default router然后在入口文件src/main.js中注册路由// 文件路径src/main.js import { createApp } from vue import App from ./App.vue import router from ./router createApp(App).use(router).mount(#app)在组件中使用router-link跳转template nav router-link to/首页/router-link router-link to/about关于/router-link /nav router-view / /templaterouter-view是一个动态组件它会根据当前路由显示对应的页面组件。6.2 动态路由与路由守卫动态路由指的是带有参数的路由例如用户详情页/user/123{ path: /user/:id, name: user, component: UserDetail }在组件中通过useRoute获取路由参数script setup import { useRoute } from vue-router const route useRoute() console.log(route.params.id) /script路由守卫可以用来控制访问权限。比如在用户未登录时阻止进入需要登录才能访问的页面router.beforeEach((to, from, next) { const isLogin localStorage.getItem(token) if (to.meta.requiresAuth !isLogin) { next(/login) } else { next() } })6.3 Pinia 状态管理Pinia 是 Vue 3 官方推荐的状态管理库用于解决跨组件共享状态的问题。相比 VuexPinia 的 API 更简洁支持组合式 API 写法并且类型推导更好。安装 Pinianpm install pinia创建 store// 文件路径src/stores/user.js import { defineStore } from pinia import { ref } from vue export const useUserStore defineStore(user, () { const name ref() const token ref() const login (userInfo) { name.value userInfo.name token.value userInfo.token } const logout () { name.value token.value } return { name, token, login, logout } })在组件中使用script setup import { useUserStore } from ../stores/user const userStore useUserStore() const handleLogin () { userStore.login({ name: 小明, token: abc123 }) } /scriptPinia 的一个很大优势是在组件中使用 store 时直接从 store 上取值即可不需要像 Vuex 那样写一堆 mapState、mapMutations。7. 常见问题与排查思路新手学习和开发 Vue 3 项目的过程中会遇到不少重复率很高的问题。下面整理一份常见问题排查清单。问题现象常见原因解决思路页面空白控制台报错script setup 中变量在模板中未正确导入检查是否遗漏 import或变量名是否拼写错误ref 数据在模板中不更新直接对 ref 变量整体赋值而不是修改 value在 JS 中赋值时使用.value修改 reactive 对象后页面不刷新对象被新对象整体替换导致响应式丢失使用Object.assign或直接修改已有属性v-for 列表渲染异常缺少 key 或不使用 key为每个列表项绑定唯一 keyprops 传递后子组件修改无效props 是只读的子组件不能直接改通过 emit 事件通知父组件修改路由切换后页面不刷新组件被复用生命周期未重新触发使用 watch 监听route.params变化Edge 浏览器中页面底部按钮无法点击可能是弹层定位或层级问题检查 z-index、transform 是否影响定位上下文定时器或事件无法清除组件卸载时未清理在 onUnmounted 中清除定时器、解绑事件7.1 响应式数据不更新的常见情况很多初学者写 Vue 3 时遇到“页面没反应”第一反应是找框架的 bug。其实大多数情况下问题出在响应式数据的用法上。错误示例const state reactive({ count: 0 }) // 错误整体替换对象会丢失响应式 state { count: 1 }正确示例const state reactive({ count: 0 }) // 正确直接修改属性 state.count 1 // 或者对一个响应式对象进行覆盖时保留原对象 Object.assign(state, { count: 1 })7.2 路由跳转不刷新页面在 Vue 3 SPA 中当你从/user/1跳转到/user/2时原组件实例会被复用onMounted不会再次触发。这是期望行为但很多新手会误认为“页面没刷新”。解决方案监听路由参数的变化在变化时重新请求数据。script setup import { ref, watch } from vue import { useRoute } from vue-router const route useRoute() const userId ref(route.params.id) watch( () route.params.id, (newId) { userId.value newId // TODO: 重新请求用户详情接口 } ) /script7.3 关于 UI 组件库版本选择很多 Vue 3 初学者在引入 Element Plus 等组件库时报错原因通常是安装了与 Vue 版本不匹配的组件库版本。Element Plus 对应 Vue 3不要安装 Element UIVue 2 版本。Vant 使用vant4以上版本支持 Vue 3。Ant Design Vue 4.x 支持 Vue 3。安装前先查看对应组件库的 README确认兼容的 Vue 版本。8. 最佳实践与工程建议8.1 目录结构规范小项目可以随意放但团队项目建议约定目录结构。参考结构src/ ├── api/ # 接口请求 ├── assets/ # 静态资源 ├── components/ # 通用组件 ├── composables/ # 组合式函数 ├── layouts/ # 布局组件 ├── router/ # 路由配置 ├── stores/ # Pinia 状态 ├── styles/ # 全局样式 ├── utils/ # 工具函数 └── views/ # 页面组件8.2 代码写法建议script setup中自动暴露的变量较多建议在顶部统一导入避免零散 import。script setup import { ref, computed, watch, onMounted } from vue import { useRouter } from vue-router import { useUserStore } from /stores/user /script组合式 API 的核心价值是“按功能组织代码”。当一个页面有多个业务功能时可以用自定义组合函数拆分而不是把所有逻辑挤在一个组件里。// 文件路径src/composables/useTodoList.js import { ref, computed } from vue export function useTodoList() { const todos ref([]) const remainingCount computed(() { return todos.value.filter(item !item.done).length }) const addTodo (text) { todos.value.push({ id: Date.now(), text, done: false }) } return { todos, remainingCount, addTodo } }在组件中直接调用import { useTodoList } from ../composables/useTodoList const { todos, remainingCount, addTodo } useTodoList()这种抽离方式让逻辑可以被多个组件复用也让组件代码保持短小易读。8.3 配置管理与环境变量Vue 3 项目中使用环境变量时变量名必须以VITE_开头通过import.meta.env访问。在项目根目录创建.env.developmentVITE_API_BASE_URL/api在.env.production中VITE_API_BASE_URLhttps://api.example.com代码中访问const apiBaseUrl import.meta.env.VITE_API_BASE_URL这样就能在不同环境自动加载不同配置避免把开发环境地址误发到生产环境。8.4 异常处理与日志记录在接口请求和关键业务逻辑中做好异常处理是一个合格前端项目的基本要求。const fetchUserList async () { try { loading.value true const res await request.get(/api/user/list) userList.value res.data } catch (error) { console.error(获取用户列表失败, error) showErrorToast(网络异常请稍后重试) } finally { loading.value false } }不要忽略 catch 块也不要让用户直接看到原始报错信息。敏感生产环境应接入前端错误监控系统。8.5 安全与权限前端代码永远运行在用户浏览器中任何写入 localStorage 的敏感信息都不是绝对安全的。涉及登录态保存时应使用安全可靠的方案并在后端接口中做好权限校验。对于需要控制显示权限的按钮、菜单应该结合路由守卫和自定义指令而不是只靠v-if判断一个布尔值。真正的安全边界永远在后端。8.6 性能优化建议长列表使用虚拟滚动不要一次性渲染所有数据。大型组件按需引入避免同步引入整个组件库。路由使用懒加载{ path: /about, name: about, component: () import(../views/About.vue) }频繁变化的组件加v-memo或合理使用shallowRef、shallowReactive。图片懒加载减少首屏请求数量。9. 结语到此我们已经完成了从环境搭建到语法学习再到组件通信、实战项目、路由状态管理、最佳实践的系统学习。你不仅掌握了 Vue 3 的 ref、reactive、computed、watch、组件通信、Vue Router、Pinia 等核心技能还了解了实际工程中常见的坑点和解决方案。下一阶段推荐动手做一个完整的中后台管理系统把 Element Plus、Vue Router、Pinia、权限控制、接口封装等知识串起来。如果你已经能独立完成这类项目可以直接挑战 Vue 3 面试题中的高阶话题比如响应式原理、diff 算法、自定义指令等。学习 Vue 3 最有效的方式是边看边写边查。照着本文的示例敲一遍代码再尝试修改功能遇到问题时翻一翻官方文档和社区资料你对 Vue 3 的理解会越来越深。希望这份 Vue3 快速上手到进阶的教程能成为你前端开发路上的一块扎实垫脚石。