ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Vue3零基础5小时学习路线:从环境搭建到项目实战

Vue3零基础5小时学习路线:从环境搭建到项目实战 很多刚接触 Vue3 的同学都有这样一种感受网上免费教程很多但大部分要么只讲一两个 API要么直接丢一个复杂后台项目新手看着看着就跟不上了。好不容易看完一套视频自己动手写项目时还是不知道路由、状态管理、接口请求怎么组合在一起。这篇文章不说废话直接给你一条从零基础到能写 Vue3 项目的学习路径按照 5 小时的节奏来拆解配环境、讲语法、写案例、列排错思路尽量让你跟着做就能跑起来。Vue3 不是只有几个新语法而是一整套设计思路的变化。你会发现以前写 Vue2 习惯的 data、methods、computed 分块写法到了 Vue3 中变成 setup 函数里的“按逻辑组织”。表面上只是写法变了实际上是组件逻辑复用和工程化能力的大幅升级。本文会用通俗的语言解释概念再给可运行的代码最后用一个待办管理页面把 Vue Router、Pinia、Axios 串起来。1. Vue3 到底是什么为什么要学它1.1 Vue3 解决的核心问题Vue3 是 Vue.js 的下一代主要版本。相比 Vue2它的底层响应式系统从 Object.defineProperty 换成了 ES6 的 Proxy这让数据监听更完整性能也更好。更重要的是Vue3 从设计层面把“组合式 API”作为推荐写法让组件内相关逻辑可以放在一起而不是强行走 data、methods、computed、watch 的固定分区。举个例子在 Vue2 中一个业务模块可能要改 data 里的一个值、methods 里的一个方法、watch 里的一个监听器、computed 里的一个派生属性这些代码被分散在四个区域。如果业务复杂你需要在组件里上下翻找。Vue3 的 setup 或script setup允许你按照功能模块写代码比如搜索功能相关的状态、方法、监听都放一起阅读和维护成本明显降低。1.2 Vue2 与 Vue3 的核心差异从 Vue2 升级到 Vue3不只是版本号变了。下面这张表列出的差异是面试和实际开发中最常遇到的维度Vue2Vue3响应式原理Object.defineProperty需递归遍历对象属性Proxy 代理支持新增属性和删除属性监听数据声明data() 返回普通对象ref / reactive / shallowRef 等逻辑复用mixins命名冲突风险高组合式函数Composables依靠普通函数组合API 风格选项式 APIOptions API选项式仍兼容推荐组合式 API性能虚拟 DOM 优化有限静态节点提升、事件缓存、更快的 diff路由推荐Vue Router 3Vue Router 4状态管理Vuex 3Pinia 成为官方推荐构建工具webpack 为主Vite 成为官方推荐的开发构建工具TypeScript支持较弱源码用 TS 重写类型推导更好对新手来说最直观的感受是新建一个 Vue3 组件代码长这样template div{{ message }}/div /template script setup import { ref } from vue const message ref(Hello Vue3) /script没有 data 选项没有 methods 选项一个script setup就能把逻辑全部写清楚。不要小看这个变化它从根本上改变了组件拆分和复用的方式。1.3 5 小时学习路线怎么安排5 小时不是说你必须连续不断学 5 小时而是把你的学习内容按优先级拆开避免在细枝末节上浪费时间。建议按下面这个节奏来第 1 小时搭建 Vue3 项目理解 Vite 和项目目录结构跑通第一个页面。第 2 小时掌握组合式 API 核心重点学 ref、reactive、computed、watch。第 3 小时学习组件通信、生命周期、自定义指令和 provide/inject。第 4 小时学习 Vue Router 和 Pinia做一个多页面应用。第 5 小时封装 Axios 请求联调接口整理常见报错。这套路线不追求覆盖所有冷门 API而是先构建一个能写项目的知识骨架。当你把本文的示例代码都手敲一遍再看官方文档时很多概念都会变得容易理解。2. 环境准备用 Vite 创建第一个 Vue3 项目2.1 需要安装什么写 Vue3 项目核心环境只需要一个 Node.js。本文示例使用 npm 作为包管理器你也可以用 pnpm 或 yarn原理一样。Node.js 版本建议安装当前 LTS 稳定版至少保证在 18 以上。版本过低会导致 Vite 或依赖安装失败。不确定自己 Node 版本的可以在命令行执行node -v npm -v能输出版本号就说明 Node 环境正常。如果没有安装去 Node.js 官网下载对应系统的安装包一路默认安装即可。注意不要在生产服务器上随意升级 Node要先确认项目依赖的兼容性。2.2 创建 Vue3 项目创建项目推荐使用 create-vite 脚手架。在命令行执行npm create vitelatest vue3-quickstart -- --template vue执行后会自动生成 vue3-quickstart 目录。进入目录并安装依赖cd vue3-quickstart npm install启动开发服务器npm run dev终端会出现类似下面的提示VITE v5.x.x ready in xxx ms ➜ Local: http://localhost:5173/打开 http://localhost:5173/如果能看到 Vite Vue 的默认页面就算环境搭建成功。安装 Vue Router、Pinia 和 Axiosnpm install vue-router4 npm install pinia npm install axios这里要说明的是依赖版本会随着时间更新本文以当前稳定版为例。如果你的终端提示某些包版本冲突优先检查 Node 版本再统一升级相关依赖不要盲目删除 lock 文件。2.3 项目目录结构说明新生成的 Vue3 项目结构看起来可能有点复杂但核心目录就几个vue3-quickstart ├── index.html ├── package.json ├── vite.config.js └── src ├── main.js ├── App.vue ├── components ├── views ├── router ├── stores └── assetsindex.html页面入口Vue 应用会挂载到这个 HTML 里的#app节点上。src/main.js应用入口文件负责创建应用、注册插件。src/App.vue根组件所有页面最终渲染在它内部。src/components公共组件目录建议按业务模块继续划分子目录。src/router路由配置目录。src/stores状态管理目录Pinia 的 store 可以放这里。src/assets静态资源图片、公共样式可以放这里。新手最容易犯的错误是在 App.vue 里写大量业务逻辑。实际上App.vue 应该保持简单只负责布局和路由出口。3. Vue3 核心语法拆解3.1 setup 与 script setup在 Vue3 组件中setup是组合式 API 的入口。你可以把它理解为“组件开始初始化时执行的一段代码”。最直接的写法是script import { ref } from vue export default { setup() { const count ref(0) return { count } } } /script这种写法需要手动 return 模板中要用到的变量写起来还是有点繁琐。所以 Vue3.2 之后推荐script setup它会自动把顶层变量暴露给模板script setup import { ref } from vue const count ref(0) /script从刚才的代码可以看出script setup是在普通 setup 之上的语法糖。它最大的优点是不需要 return模板直接使用变量。这也意味着在script setup中引入的组件、声明的变量、函数都可以在模板中直接使用代码更简洁。有一点需要特别注意script setup中不要使用export default它是通过编译时处理完成的不能混用普通选项式导出的写法。3.2 ref 与 reactive两种响应式数据声明响应式数据是 Vue 的核心概念。所谓响应式就是当数据变化时引用它的页面区域会自动更新。Vue3 中最常用的两个 API 是 ref 和 reactive。ref 声明基础类型和对象ref 可以声明基础类型也可以包裹对象。它的特点是在 Script 中操作值时必须用.value在模板中 Vue 会自动解包不需要写.value。script setup import { ref } from vue const name ref(张三) const user ref({ age: 18 }) function changeName() { name.value 李四 user.value.age 20 } /script template div{{ name }}/div div{{ user.age }}/div button clickchangeName修改/button /template这里最容易出错的地方是在 JavaScript 中直接写name 李四是不生效的。因为 ref 返回的是一个包装后的对象真正的值在.value上。模板中的自动解包只是方便模板语法不影响 Script 中的使用规则。reactive 声明纯对象reactive 接收一个普通对象返回一个响应式代理对象。它的特点是操作属性时不用.valuescript setup import { reactive } from vue const state reactive({ count: 0, list: [] }) function add() { state.count state.list.push(state.count) } /scriptreactive 更适合声明深度嵌套的对象。但要注意它不能直接替换整个对象因为 reactive 是基于 Proxy 的代理直接重新赋值会让代理关系失效。现实项目中我更推荐“能用 ref 就用 ref”。ref 更统一支持各种类型而且现在很多人已经习惯xxx.value的写法。reactive 适合用于集中定义一整块对象模型比如表单模型。3.3 computed 计算属性computed 用于声明派生数据。它的本质是根据已有响应式数据计算出一个新值并且这个新值有缓存只有依赖的数据变化时才会重新计算。script setup import { ref, computed } from vue const price ref(100) const count ref(2) const total computed(() price.value * count.value) /script template div总价{{ total }}/div /templatetotal 不需要写.value因为在模板中会自动解包。如果你在 computed 中修改了依赖的数据total 会自动更新但 total 本身不建议被手动修改。computed 的核心作用是避免在模板中写复杂表达式让模板保持干净。3.4 watch 监听器watch 用来监听响应式数据的变化适合处理异步操作、副作用或需要关联更新的场景。script setup import { ref, watch } from vue const keyword ref() watch(keyword, (newValue, oldValue) { console.log(搜索词变化, oldValue, -, newValue) }) /script如果要监听多个数据可以传数组watch([keyword, page], ([newKeyword, newPage], [oldKeyword, oldPage]) { // 处理多个数据变化 })如果你需要在监听时立即执行一次回调可以传入第三个参数watch(keyword, (newValue) { console.log(立即执行一次后续变化也会触发) }, { immediate: true })还有一种 watchEffect它会自动收集回调中用到的响应式数据数据变化时自动重新执行。它不需要手动指定依赖适合不需要关心旧值的场景。3.5 生命周期函数Vue3 的生命周期与 Vue2 类似但名称发生了变化并且只能在 setup 中调用Vue2Vue3beforeCreate不需要setup 直接替换created不需要setup 直接替换beforeMountonBeforeMountmountedonMountedbeforeUpdateonBeforeUpdateupdatedonUpdatedbeforeUnmountonBeforeUnmountunmountedonUnmounted最常见的用法是 onMounted 中请求接口script setup import { onMounted } from vue import { fetchTodoList } from ../api/todo onMounted(() { fetchTodoList() }) /script注意生命周期函数注册时不能使用await包裹外层否则同步注册时机就变了。如果要在 mounted 中做异步操作直接在回调里写 async 函数即可。3.6 组件通信Vue3 的组件通信方式非常多新手一开始容易混淆。实际项目中掌握这几种就够了父传子defineProps子组件通过 defineProps 声明接收的属性!-- 子组件 TodoItem.vue -- script setup const props defineProps({ title: { type: String, required: true }, done: { type: Boolean, default: false } }) /script template div :class{ done } {{ title }} /div /template在父组件中这样使用TodoItem title学习 Vue3 :donetrue /子传父defineEmits子组件声明要触发的事件script setup const emit defineEmits([change]) function handleClick() { emit(change, 参数值) } /script父组件监听TodoItem changehandleChange /跨层级通信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) /scriptprovide/inject 不是响应式传值时就传一个 ref 或 reactive后续修改会自动联动。如果不小心传成了普通字符串后代是拿不到实时更新的。3.7 自定义指令与全局注册自定义指令在 Vue3 中仍然保留。比如我们需要一个自动聚焦输入框的指令// src/directives/index.js export const vFocus { mounted: (el) { el.focus() } }在 main.js 中全局注册// src/main.js import { createApp } from vue import App from ./App.vue import { vFocus } from ./directives const app createApp(App) app.directive(focus, vFocus) app.mount(#app)组件模板中直接使用input v-focus placeholder请输入内容 /自定义指令适合处理 DOM 层面的通用逻辑比如权限按钮控制、水印生成、点击外部关闭等。但如果是纯粹的业务逻辑优先用组件和组合式函数不要什么都塞进指令里。4. 实战案例快速搭建一个待办管理页面4.1 需求分析与功能拆分到这里我们把前面的知识点串起来做一个最小的“待办管理”页面。这个案例会用到Vue Router 配置页面路由。Pinia 管理待办状态。Axios 做接口请求。组件化列表项组件。ref、computed、onMounted、自定义指令。页面功能如下输入框新增待办事项。列表展示待办点击切换完成状态。删除待办。统计总数和已完成数量。4.2 创建路由与页面骨架在 src 下创建 router 目录新建 index.js// src/router/index.js import { createRouter, createWebHistory } from vue-router import TodoHome from ../views/TodoHome.vue const router createRouter({ history: createWebHistory(), routes: [ { path: /, name: Home, component: TodoHome } ] }) export default router修改 main.js注册 Router 和 Pinia// src/main.js import { createApp } from vue import { createPinia } from pinia import App from ./App.vue import router from ./router import { vFocus } from ./directives const app createApp(App) app.use(createPinia()) app.use(router) app.directive(focus, vFocus) app.mount(#app)创建页面文件 src/views/TodoHome.vuetemplate main classtodo-page h1待办事项/h1 div classinput-row input v-modelnewTodo v-focus placeholder输入待办内容 keyup.enterhandleAdd / button clickhandleAdd新增/button /div p进度{{ store.doneCount }} / {{ store.total }}/p ul li v-foritem in store.todos :keyitem.id :class{ done: item.done } span{{ item.title }}/span button clickstore.toggleTodo(item.id)切换/button button clickstore.removeTodo(item.id)删除/button /li /ul /main /template script setup import { ref } from vue import { useTodoStore } from ../stores/todo const store useTodoStore() const newTodo ref() function handleAdd() { const text newTodo.value.trim() if (!text) { alert(请输入待办内容) return } store.addTodo(text) newTodo.value } /script style scoped .todo-page { max-width: 600px; margin: 40px auto; } .input-row { display: flex; gap: 8px; margin-bottom: 12px; } li.done span { text-decoration: line-through; color: #999; } /style这里使用了store.doneCount和store.total这两个是 Pinia 中的 getter。下面来编写 store。4.3 使用 Pinia 管理待办状态在 src 下创建 stores 目录新建 todo.js// src/stores/todo.js import { defineStore } from pinia export const useTodoStore defineStore(todo, { state: () ({ todos: [], loading: false }), getters: { total: (state) state.todos.length, doneCount: (state) state.todos.filter((item) item.done).length }, actions: { async fetchTodos() { this.loading true // 模拟请求后续可替换为 axios 调用 const mockData [ { id: 1, title: 学习 Vue3 基础语法, done: true }, { id: 2, title: 完成待办管理页面, done: false } ] await new Promise((resolve) setTimeout(resolve, 200)) this.todos mockData this.loading false }, addTodo(title) { const newItem { id: Date.now(), title, done: false } this.todos.push(newItem) }, toggleTodo(id) { const item this.todos.find((todo) todo.id id) if (item) { item.done !item.done } }, removeTodo(id) { this.todos this.todos.filter((todo) todo.id ! id) } } })在 TodoHome.vue 的 onMounted 中调用 fetchTodosscript setup import { onMounted, ref } from vue import { useTodoStore } from ../stores/todo const store useTodoStore() const newTodo ref() onMounted(() { store.fetchTodos() }) function handleAdd() { // ... } /scriptPinia 的状态被组件调用后组件与 store 之间会自动建立响应式关系。所以 store.todos 变化时页面上的 v-for 列表也会自动更新。这里不需要额外的事件订阅或手动刷新。4.4 接口请求封装Axios 示例业务项目里不可能一直用 mock 数据。下面演示 Axios 的基础封装方式。创建 src/utils/request.js// src/utils/request.js import axios from axios const request axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL || /api, timeout: 10000 }) // 请求拦截器可以在这里统一加 Token request.interceptors.request.use( (config) { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }, (error) Promise.reject(error) ) // 响应拦截器统一处理错误码 request.interceptors.response.use( (response) response.data, (error) { // 实际项目中按后端约定处理 return Promise.reject(error) } ) export default request把刚才 store 中的 mock 数据替换为真实请求// src/stores/todo.js import { defineStore } from pinia import request from ../utils/request export const useTodoStore defineStore(todo, { state: () ({ todos: [], loading: false }), getters: { total: (state) state.todos.length, doneCount: (state) state.todos.filter((item) item.done).length }, actions: { async fetchTodos() { this.loading true try { const res await request.get(/todos) this.todos res } finally { this.loading false } }, async addTodo(title) { const res await request.post(/todos, { title }) this.todos.push(res) }, async toggleTodo(id) { const item this.todos.find((todo) todo.id id) if (!item) return await request.put(/todos/${id}, { done: !item.done }) item.done !item.done }, async removeTodo(id) { await request.delete(/todos/${id}) this.todos this.todos.filter((todo) todo.id ! id) } } })这套代码是真实项目中非常常见的模式。注意 fetchTodos 中使用 try/finally确保请求无论成功还是失败都会关闭 loading 状态。你在本地模拟阶段可以用 json-server、Mock.js 或者后端联调地址来测试。4.5 运行与验证运行项目npm run dev打开页面后你会看到待办列表、完成进度、新增输入框。点击“切换”按钮文字会出现删除线点击“删除”按钮对应项会消失。这个例子虽然简单但已经把 Vue3 的响应式、组件通信、状态管理、路由和请求封装覆盖到了一半以上。如果你使用的是 mock 数据看不到网络请求是正常的。改成 Axios 版本后打开浏览器控制台的 Network 面板就能看到请求记录。遇到跨域问题时可以在 vite.config.js 中配置代理// vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })这样前端请求/api/todos时Vite 开发服务器会转发到本地后端服务避免浏览器跨域限制。5. 高频问题与排查思路5.1 数据修改了页面却不更新问题现象常见原因解决思路页面没有响应控制台也没有报错使用 ref 后忘记.value检查 Script 中是否写xxx.value对象新增属性不生效Vue2 习惯带入 Vue3但 Vue3 Proxy 已支持确认使用的是 reactive 或 ref 包裹的对象整个 reactive 对象被重新赋值直接覆盖了 Proxy 对象改为给对象内部属性赋值或用 ref 替代数组通过下标修改不更新使用了非响应式的普通数组使用 ref/reactive 包裹用 splice/push 或整体替换最常见的其实是第一次写组合式 API 时忘记.value。如果你在函数中写了const count ref(0) function add() { count 1 // 错误 }count 在 Script 中是一个 RefImpl 对象直接加 1 没有意义。正确写法是count.value 1。而模板中写{{ count }}时Vue 会帮你自动解包所以模板里不需要.value。这是新手最容易懵的点。5.2 Vite 启动失败或依赖安装报错问题现象常见原因解决思路运行 npm run dev 提示 out of memory多个项目占用资源关闭多余服务或调整 Node 内存限制Node Sass / node-sass 报错Vue3 项目中不推荐 node-sass改用 sassdart-sass安装依赖后启动报语法错误Node 版本过低升级 Node 到 LTS 版本vite 命令找不到依赖没装完删除 node_modules 和 package-lock.json重新安装处理依赖问题不要一上来就删除 lock 文件这个文件记录着依赖版本关系随意删除容易导致版本不一致。优先尝试npm install如果仍然失败再考虑清理 node_modules 后全新安装。5.3 路由跳转后组件不刷新这个问题在面试和业务开发中都很常见。比如从/user/1跳转到/user/2如果两个路由使用了同一个组件实例Vue 会复用组件不会重新执行 mounted 或 created所以页面数据不会刷新。解决方法有两种第一种在组件内监听路由参数变化import { watch } from vue import { useRoute } from vue-router const route useRoute() watch( () route.params.id, (newId) { // 根据新 id 重新请求数据 fetchDetail(newId) } )第二种使用路由守卫import { onBeforeRouteUpdate } from vue-router onBeforeRouteUpdate((to, from) { // 处理参数变化 })不是所有路由跳转都会遇到这个问题只有同一个组件被复用时才需要处理。5.4 defineProps 使用报错在script setup中defineProps 是编译宏不需要导入。但如果把 defineProps 当作普通函数调用或者在选项式 API 中使用就会报错。正确写法script setup const props defineProps({ title: String }) console.log(props.title) /script模板中直接使用 title不需要props.title。如果你在模板中写了props.title也没有错但没必要。defineProps 中的属性校验类型可以用 String、Number、Boolean、Object、Array 等。使用 Boolean 类型时父组件传入:donefalse时模板表现正常但如果只是传TodoItem done /值会是 true这是 Vue 对布尔属性的特殊处理。6. 工程实践与进阶方向6.1 组件拆分与命名规范刚学完 Vue3 后很容易把页面代码全部堆在一个文件里比如在 TodoHome.vue 里同时写表单、列表、弹窗、分页。前期这样写确实快但项目变大后会非常痛苦。比较好的习惯是views 目录放页面级组件一个 url 对应一个 views 文件。components 目录放业务组件和通用组件按模块分子目录。通用组件使用 Base、App、Ui 开头比如 BaseButton、BaseModal。业务组件命名尽量贴近业务含义比如 TodoItem、UserSearchForm。涉及复杂状态逻辑时抽成组合式函数到 src/composables 目录。组合式函数是 Vue3 最推荐的逻辑复用方式。比如待办列表的加载逻辑可以抽成// src/composables/useTodoList.js import { ref } from vue import request from ../utils/request export function useTodoList() { const todos ref([]) const loading ref(false) async function fetchTodos() { loading.value true try { const res await request.get(/todos) todos.value res } finally { loading.value false } } return { todos, loading, fetchTodos } }组件里只需要一行调用import { useTodoList } from ../composables/useTodoList const { todos, loading, fetchTodos } useTodoList()这种方式比 mixins 更清晰因为不涉及命名空间的合并逻辑来源一目了然。6.2 状态管理与接口层职责很多初学者会纠结一个问题数据到底放在组件里还是 Pinia 里我的建议是优先放组件等数据确实需要跨组件共享时再提升到 Pinia。把不需要共享的临时表单内容放进 Pinia只会让全局状态变得混乱。Pinia 中适合放这几种数据用户登录信息、应用配置、跨页面共享的列表状态、购物车等。普通页面内部的搜索条件、临时输入框内容用 ref 就够了。接口请求不要散落在每个组件里。统一封装 request 实例按业务模块拆 api 文件比如 src/api/todo.js// src/api/todo.js import request from ../utils/request export function getTodoList() { return request.get(/todos) } export function createTodo(data) { return request.post(/todos, data) } export function updateTodo(id, data) { return request.put(/todos/${id}, data) } export function deleteTodo(id) { return request.delete(/todos/${id}) }组件只负责调用函数不关心请求地址和参数拼接方式。这样后续接口改动时只需要修改 api 层不会影响页面。6.3 性能优化优先级新手不要一上来就追求极端性能优化先把代码写正确再关注性能。常用的优化手段按重要程度排列组件状态不要过度暴露给全局。长列表使用 key 保持稳定。v-for 和 v-if 不要同时用在同一个元素上。大数据列表考虑虚拟滚动组件。大组件进行异步加载Vue Router 路由懒加载。组件库按需引入比如 Element Plus 或 Ant Design Vue 按需加载。图片懒加载减少首屏网络请求。路由懒加载是一个很容易实现且收益明显的优化。写法如下// src/router/index.js const router createRouter({ history: createWebHistory(), routes: [ { path: /, name: Home, component: () import(../views/TodoHome.vue) } ] })组件不再首屏全量加载而是访问对应路由时才动态 import。6.4 从 Vue2 迁到 Vue3 的关注点如果你从 Vue2 项目迁移到 Vue3除了语法变化还需要关注几个容易忽略的点filter 过滤器在 Vue3 中被移除建议改成计算属性或方法。全局事件总线$on、$off在 Vue3 中移除推荐使用 mitt 或业务事件库。自定义指令的钩子名变化mounted 替代 bindunmounted 替代 unbind。v-model 用法调整组件上可以使用多个 v-model比如v-model:title。插槽语法更统一推荐v-slot写法。Vuex 迁移到 Pinia 时把 state 写成函数getters 基本可以改成箭头的写法mutations 被 actions 替代。同时迁移时不要一次性大范围改代码先升级构建工具再逐组件替换 API。把 Vue2 和 Vue3 的差异表打印出来遇到问题时对照排查效率会高很多。6.5 后续学习路线学完本文内容你已经可以写一个简单的 Vue3 应用了。下一步更重要的是项目实战建议这样做把刚做的待办管理页面扩展成一个小后台加上登录页、列表页、详情页用 Vue Router 做多页面跳转用 Pinia 保存登录状态用 Axios 对接真实接口。把你踩到的每一个坑记录下来这是提升最快的方式。想系统深入的话可以继续学习 Composition API 的底层实现、Vue3 的编译优化原理、SSR 或 Nuxt3、移动端跨端方案等。但不要把这些一次性铺开先把基础项目做扎实后续学框架原理时才能理解为什么设计成这样。如果你在学习过程中遇到“语法明明没写错但页面就是不对”的情况先不要怀疑 Vue 框架按照控制台报错去检查依赖版本、组件导入路径和响应式数据写法。大多数问题都能在项目依赖和 API 使用方式上找到答案。把本文的示例代码跟着敲一遍能运行再尝试改动入门阶段就足够稳了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进