学习地图
这门学科是干什么的
Vue 是一个用于构建用户界面的前端框架。它最核心的事情只有一句话:**让页面随着数据变化而自动更新**。
你真正要学的,不只是几个 API,而是三件事:
-
用"组件"拆页面。
-
用"状态"驱动界面。
-
用"工程化方式"组织前端项目。
**学习本质:必须吃透**
Vue 本质上是在帮我们把"业务状态"和"页面表现"建立稳定映射。
一句最重要的话可以记住:`UI = f(state)`,界面是状态的函数。
它解决什么问题
在没有框架时,前端经常要手动操作 DOM:
-
找元素
-
改文本
-
改 class
-
绑定事件
-
手动同步数据和界面
页面一复杂,就会出现三个典型问题:
| 问题 | 原生方式常见表现 | Vue 的解决方式 |
| --- | --- | --- |
| 界面和数据容易不同步 | 数据改了,但 DOM 忘了改 | 响应式系统自动追踪依赖并更新视图 |
| 页面难复用 | 一页一套 DOM + JS | 用组件封装和复用 |
| 项目一大就混乱 | JS、HTML、状态、接口逻辑耦合 | 用组件、路由、状态管理拆分职责 |
它和哪些相关技术有关系
| 相关技术 | 和 Vue 的关系 | 是否前置必备 |
| --- | --- | --- |
| HTML/CSS | Vue 模板最终还是渲染成 HTML,样式仍然靠 CSS | 是 |
| JavaScript | Vue 的本体就是基于 JS 的 | 是 |
| ES6+ | 模块化、解构、箭头函数、Promise 很常用 | 是 |
| DOM / 浏览器事件 | 帮助理解 Vue 为什么能接管页面更新 | 是 |
| Node.js / npm | 创建项目、安装依赖、运行开发服务 | 是 |
| Vite | 现在最常见的 Vue 构建工具 | 是 |
| Vue Router | 做多页面感受的单页应用导航 | 很重要 |
| Pinia | 管理跨组件共享状态 | 很重要 |
| Axios / Fetch | 请求后端接口 | 很重要 |
| TypeScript | 企业项目里很常见,但不是一上来必须精通 | 先知道,后深入 |
| SSR / Nuxt | 服务端渲染与全栈能力 | 先知道,后深入 |
学它之前需要哪些前置知识
建议至少具备下面这些基础,不需要很深,但要会用:
-
HTML 基础:标签、表单、列表、语义化。
-
CSS 基础:选择器、盒模型、Flex、定位。
-
JavaScript 基础:变量、函数、对象、数组、作用域。
-
ES6 常用语法:模块化、解构、模板字符串、Promise、async/await。
-
浏览器基础:DOM、事件冒泡、默认行为、网络请求。
-
命令行基础:`cd`、`npm install`、`npm run dev`。
如果你现在 JS 还不熟,学习顺序一定是:**先补 JS 常用语法,再学 Vue**。
因为 Vue 的难点,很多时候并不是框架本身,而是 JS、组件思维和异步思维。
真正重要的 20% 核心内容是什么
下面这些内容,占了 Vue 实战和面试里最有价值的 80%:
-
**组件化思维**:怎么拆页面、怎么复用组件。
-
**模板语法与指令**:插值、`v-bind`、`v-model`、`v-if`、`v-for`、事件绑定。
-
**响应式数据**:`ref`、`reactive`、数据变化为什么会驱动视图更新。
-
**组件通信**:`props`、`emit`、`provide / inject`、状态管理的适用边界。
-
**计算属性与侦听器**:`computed`、`watch`、`watchEffect` 的区别和场景。
-
**生命周期**:什么时候发请求、什么时候操作 DOM、什么时候清理副作用。
-
**路由与页面组织**:Vue Router 的路由匹配、导航、嵌套路由、守卫。
-
**状态管理**:Pinia 如何管理全局状态。
-
**接口请求与异步状态处理**:加载中、错误态、空态、重试。
-
**基础排错能力**:组件不更新、`key` 用错、响应式丢失、`props` 误改、`nextTick` 误用。
哪些内容是初学者容易陷入、但不值得一开始深挖的
这些内容不是不重要,而是不该在最开始投入过多时间:
-
Vue 源码逐行阅读。
-
编译器细节,比如模板 AST 的每个转换过程。
-
自定义渲染器。
-
SSR / Nuxt 的复杂部署。
-
极限性能优化和复杂构建链魔改。
-
太早陷入"Vue 2 和 Vue 3 所有差异背诵"。
-
太早陷入"所有生态库全都学一遍"。
建议原则:
-
**必须掌握**:组件、响应式、通信、生命周期、路由、状态管理、排错。
-
**知道即可**:SSR、宏观源码架构、编译器实现细节、高阶性能调优。
设计哲学
Vue 的设计哲学可以概括成三句话:
-
**渐进式**:你可以从一页小功能开始用,也可以做完整工程项目。
-
**声明式**:你描述"页面应该长什么样",不是手写每一次 DOM 修改过程。
-
**组合式**:逻辑按能力组织,而不是按生命周期函数强行分散。
学习顺序
下面是推荐的学习顺序,也是企业里最接近真实成长路径的一条线:
- **第一阶段:入门认知**
理解 Vue 在前端中的角色,能跑起第一个应用,知道"为什么页面会自动更新"。
- **第二阶段:核心语法与组件**
掌握模板语法、指令、组件、`props`、事件、表单、列表、条件渲染。
- **第三阶段:响应式与组件通信机制**
吃透 `ref`、`reactive`、`computed`、`watch`、生命周期,以及父子、兄弟、跨层通信。
- **第四阶段:底层原理**
理解响应式追踪、依赖收集、调度更新、虚拟 DOM、Diff、`nextTick`、模板编译链路。
- **第五阶段:工程实践**
会用 Vite、Vue Router、Pinia、接口封装、目录结构、组件规范、环境配置、构建发布。
- **第六阶段:常见问题与排错**
能定位"不更新""重复渲染""路由失效""状态丢失""样式污染""异步竞态"等问题。
- **第七阶段:面试与评估**
把知识整理成可以解释、可以对比、可以落到代码和场景的答案。
- **第八阶段:项目闭环**
完成一个中小型项目,把知识点串起来,形成"会做 + 会讲 + 会排错"的能力。
正确学习顺序为什么是这样
因为 Vue 学偏最常见的原因有两个:
-
一开始背 API,不理解"状态驱动视图"。
-
一开始啃源码,却没有真实业务问题作为抓手。
所以正确路径一定是:
**先直觉认知 -> 再掌握常用 API -> 再理解机制 -> 再进入工程与源码。**
企业里通常怎么用 Vue
企业里最常见的组合是:
-
`Vue 3 + Vite`
-
`Vue Router`
-
`Pinia`
-
`Axios / Fetch`
-
`Element Plus / Ant Design Vue / 自研组件库`
-
`TypeScript`(很多团队会加)
面试官通常怎么问
初级到中级 Vue 面试,常见问法通常分四类:
-
概念类:Vue 是什么?响应式是什么?`computed` 和 `watch` 区别是什么?
-
机制类:Vue 为什么更新快?`nextTick` 是干什么的?`key` 为什么重要?
-
工程类:项目怎么拆组件?如何管理公共状态?接口如何封装?
-
排错类:为什么页面不更新?为什么列表复用有问题?为什么子组件不能直接改 `props`?
自循环推进规则
从这里开始,这份文档不再依赖"回复继续"才能往下学,而是按下面的闭环自动推进:
-
先学当前阶段的主干内容。
-
跑通当前阶段的最小示例。
-
完成当前阶段的练习题或工程任务。
-
对照当前阶段的"学完标志"和"验收标准"自测。
-
如果自测正确率在 80% 以上,直接进入下一阶段。
-
如果自测正确率低于 80%,先按文末"反向补课"回补,再继续推进。
建议学习节奏:
-
第一到第三阶段:重在建立正确直觉和常用写法。
-
第四到第六阶段:重在理解为什么这样设计,以及怎么排错。
-
第七到第八阶段:重在把知识变成面试表达和项目能力。
你可以把这份文档当成一个可循环执行的学习流程:
`学概念 -> 写示例 -> 做练习 -> 自测 -> 查漏补缺 -> 进入下一阶段 -> 项目闭环`
第一阶段:Vue 到底是什么,为什么它能让页面跟着数据走
1. 学什么
这一阶段你要建立三个最重要的直觉:
-
Vue 不是"一个会写页面的语法糖",而是一个**状态驱动 UI 的框架**。
-
Vue 的基本单位是**组件**,不是一整页代码。
-
Vue 的核心价值是:**你改数据,Vue 帮你更新页面**。
本阶段只要求你掌握下面这些最基础但最关键的内容:
-
Vue 在前端中的角色
-
声明式开发是什么
-
组件是什么
-
响应式更新是什么
-
`createApp`、`setup`、`ref` 的最基本使用
-
Vue 项目如何跑起来
2. 为什么重要
如果这一阶段没吃透,后面所有内容都会变成"背 API":
-
你会记住 `v-model`,但不知道它为什么存在。
-
你会记住 `watch`,但不知道什么时候该用。
-
你会记住生命周期,但不知道为什么有这些时机。
所以这一阶段最重要的目标不是"写复杂页面",而是建立一个稳定认知:
**Vue 通过响应式系统,把数据变化映射为视图变化。**
3. 核心概念
3.1 先用直觉理解
可以把 Vue 想成一个"聪明的前台屏幕系统":
-
你手里改的是后台数据。
-
屏幕上展示的是这些数据的结果。
-
只要数据变了,屏幕自动刷新,不需要你再一个个找 DOM 改。
3.2 技术定义
| 概念 | 直觉类比 | 技术定义 |
| --- | --- | --- |
| 声明式 UI | 告诉厨师"我要什么菜",而不是自己切菜下锅 | 描述数据和视图关系,而不是手动操作 DOM 过程 |
| 组件 | 乐高积木 | 可复用、可组合的 UI 与逻辑单元 |
| 响应式 | 温度计会跟温度自动变化 | 数据变化后,依赖它的视图或逻辑会自动重新执行 |
| 模板 | 页面草图 | 用接近 HTML 的语法描述视图结构 |
| 状态 | 当前系统的事实 | 决定页面展示结果的数据 |
| 挂载 | 把程序接到页面上 | Vue 应用接管某个 DOM 容器并开始渲染 |
3.3 必须吃透
下面这句话请你反复看:
**以前是"我去改页面",现在是"我改状态,框架改页面"。**
这是 Vue 和原生 DOM 编程最大的分界线。
4. 原理解释
4.1 Vue 的工作流程
当你写出一个 Vue 页面时,大致发生了下面这些事情:
-
`createApp()` 创建一个应用实例。
-
`mount('#app')` 把应用挂到页面上的某个容器。
-
Vue 读取模板,建立"模板依赖了哪些数据"的关系。
-
你在 `setup()` 里定义响应式数据,比如 `ref(0)`。
-
模板使用了这个数据,比如 `{{ count }}`。
-
当 `count` 变化时,Vue 知道这个值被页面依赖了。
-
Vue 不会粗暴整页重画,而是找到需要更新的部分,补丁式更新 DOM。
4.2 为什么这样设计
Vue 这样设计,是为了同时解决三个问题:
-
**开发效率**:不再每次都手动改 DOM。
-
**可维护性**:页面逻辑以组件和状态组织,更清晰。
-
**性能平衡**:通过依赖追踪和批量调度,避免无意义重渲染。
4.3 一个必须知道的底层思想
虽然你现在不用深入源码,但要先知道下面这条主线:
`响应式数据 -> 依赖收集 -> 数据变化 -> 调度更新 -> DOM 打补丁`
后面学 `computed`、`watch`、`nextTick`、虚拟 DOM 时,都会回到这条链路。
5. 示例
5.1 最小可运行示例
下面这个例子可以直接保存为 `index.html` 后打开运行:
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue 最小示例</title>
</head>
<body>
<div id="app">
<h1>当前计数:{{ count }}</h1>
<button @click="count++">加 1</button>
<button @click="reset">重置</button>
<p v-if="count >= 3">你已经点击了至少 3 次</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const count = ref(0)
const reset = () => {
count.value = 0
}
return {
count,
reset
}
}
}).mount('#app')
</script>
</body>
</html>
```
5.2 这个示例说明了什么
这个例子虽然小,但已经覆盖了 Vue 的基础骨架:
-
`createApp`:创建应用
-
`setup`:编写组件逻辑
-
`ref`:创建响应式数据
-
`{{ count }}`:模板插值
-
`@click`:事件绑定
-
`v-if`:条件渲染
5.3 为什么模板里不需要写 `.value`
在 JavaScript 里,`ref` 的值需要通过 `count.value` 访问。
但在模板里,Vue 会帮你自动解包,所以直接写 `count`。
6. 工程实践
6.1 标准起步方式
真实项目里,一般不会直接用 CDN 起步,而是用 Vite 创建 Vue 工程:
```bash
npm create vue@latest
cd your-project
npm install
npm run dev
```
6.2 你会看到的核心目录
```text
your-project/
├─ public/
├─ src/
│ ├─ assets/
│ ├─ components/
│ ├─ App.vue
│ └─ main.js
├─ index.html
├─ package.json
└─ vite.config.js
```
6.3 一个真实工程场景
假设你要做一个"学生管理页面",页面上有:
-
学生列表
-
搜索框
-
新增按钮
-
删除按钮
-
详情弹窗
而 Vue 的做法会是:
-
把页面拆成列表组件、搜索组件、弹窗组件。
-
把"学生数据"和"当前筛选条件"作为状态。
-
模板根据状态自动渲染结果。
-
用户点击按钮,实际改的是状态,不是手动改一堆 DOM。
7. 常见误区
-
**把 Vue 当成模板拼接工具**
-
**上来就背很多 API**
-
**在 Vue 里还习惯手动操作 DOM**
-
**分不清 `ref` 和普通变量**
-
**一开始就沉迷源码**
-
**学 Vue 却不补 JavaScript**
8. 面试题
-
Vue 是什么?它解决了什么问题?
-
什么是声明式开发?
-
Vue 为什么能在数据变化时自动更新页面?
-
`ref` 是什么?为什么模板里不用写 `.value`?
-
`createApp().mount()` 做了什么?
9. 自测题
-
用你自己的话解释:为什么说 Vue 是"状态驱动 UI"的框架?
-
原生 DOM 手动更新页面,和 Vue 响应式更新页面,本质差别是什么?
-
`ref(0)` 和 `let count = 0` 在 Vue 组件里有什么本质区别?
-
`createApp`、`setup`、`mount` 分别负责什么?
-
为什么说组件是 Vue 项目的基本组织单位?
-
如果点击按钮后数据变了,但页面没变,你第一反应应该检查什么?
10. 学完标志
学完这一阶段后,你应该能做到:
-
用自己的话解释 Vue 是什么,以及它为什么比手动 DOM 操作更适合复杂页面。
-
说清楚"声明式开发""组件""响应式"的含义。
-
独立跑起一个 Vue 项目。
-
写出一个最小可运行组件,包含数据、事件和条件渲染。
-
初步解释"为什么数据变了,页面会跟着变"。
第一阶段练习题
练习 1:计数器增强版
要求你实现:
-
一个数字计数器。
-
一个"加 1"按钮。
-
一个"减 1"按钮。
-
一个"重置"按钮。
-
当数字大于等于 5 时显示提示文字。
-
当数字小于 0 时,文字变成红色。
练习 2:个人信息卡片
要求你实现:
-
页面展示姓名、年龄、职业。
-
点击按钮后年龄加 1。
-
点击按钮切换"在职 / 离职"状态。
-
用条件渲染显示不同文案。
练习 3:待办事项最小版
要求你实现:
-
输入框输入待办内容。
-
点击按钮新增一条待办。
-
页面显示待办列表。
-
每条待办旁边有删除按钮。
第一阶段验收标准
如果你能独立完成上面 3 个练习中的至少 2 个,并且能口头回答下面这 4 个问题,就算第一阶段基本达标:
-
Vue 为什么适合做复杂前端页面?
-
什么是响应式数据?
-
为什么我们更推荐"改状态"而不是"手动改 DOM"?
-
一个 Vue 项目最基本是怎么启动起来的?
第二阶段:模板语法、组件拆分与页面表达
1. 学什么
这一阶段开始真正进入"会写页面"的部分,重点掌握:
-
插值表达式 `{{ }}`
-
属性绑定 `v-bind`
-
事件绑定 `v-on`
-
表单双向绑定 `v-model`
-
条件渲染 `v-if`、`v-else-if`、`v-else`、`v-show`
-
列表渲染 `v-for`
-
列表更新中的 `key`
-
单文件组件 `*.vue`
-
基础组件拆分
-
`props` 和 `emit` 的基础使用
2. 为什么重要
这一阶段是 Vue 日常开发里使用频率最高的一层。
如果说第一阶段是在建立"状态驱动视图"的认知,那么第二阶段就是把这个认知翻译成具体代码。
企业开发中,你每天都在写这层内容:
-
表单输入
-
条件展示
-
列表渲染
-
点击事件
-
组件传值
-
页面拆分
3. 核心概念
3.1 指令是什么
Vue 指令就是带 `v-` 前缀的特殊语法,用来描述"数据怎么影响页面"。
| 指令 | 作用 | 高频场景 |
| --- | --- | --- |
| `v-bind` | 动态绑定属性 | `src`、`class`、`disabled` |
| `v-on` / `@` | 绑定事件 | 点击、输入、提交 |
| `v-model` | 双向绑定表单值 | 输入框、下拉框、单选框 |
| `v-if` | 条件创建 / 销毁节点 | 弹窗、权限区块 |
| `v-show` | 条件切换显示隐藏 | 高频切换的面板 |
| `v-for` | 列表渲染 | 列表、表格、菜单 |
3.2 `v-if` 和 `v-show` 对比
| 项目 | `v-if` | `v-show` |
| --- | --- | --- |
| 本质 | 控制节点是否创建 | 控制 CSS `display` |
| 初始成本 | 条件为假时不渲染 | 一开始就渲染 |
| 切换成本 | 每次切换可能销毁和重建 | 切换很快 |
| 适用场景 | 不常切换、结构较重 | 高频切换、结构较轻 |
3.3 `props` 和 `emit` 对比
| 概念 | 方向 | 作用 |
| --- | --- | --- |
| `props` | 父 -> 子 | 父组件给子组件传数据 |
| `emit` | 子 -> 父 | 子组件通知父组件发生了某个事件 |
4. 原理解释
4.1 模板为什么能写得像 HTML
因为 Vue 会把模板编译成渲染函数。
你看到的是接近 HTML 的声明式写法,Vue 内部执行的是 JavaScript 渲染逻辑。
4.2 `v-model` 为什么是语法糖
它本质上是两件事的组合:
-
把值绑定到表单元素上。
-
在输入变化时同步回数据。
你可以把它理解成:
```vue
<input :value="keyword" @input="keyword = $event.target.value" />
```
4.3 为什么 `v-for` 一定要重视 `key`
因为 `key` 就是列表项的"身份证"。
如果 `key` 写错,比如直接写索引:
-
删除一项时可能复用错 DOM
-
输入框值可能串位
-
局部状态可能错乱
5. 示例
5.1 最小可运行示例
`App.vue`
```vue
<template>
<div>
<h2>待办列表</h2>
<input v-model="keyword" placeholder="请输入关键词" />
<button @click="addTodo">新增</button>
<p v-if="filteredTodos.length === 0">暂无数据</p>
<TodoList :items="filteredTodos" @remove="removeTodo" />
</div>
</template>
<script setup>
import { computed, ref } from 'vue'
import TodoList from './components/TodoList.vue'
const keyword = ref('')
const todos = ref([
{ id: 1, text: '学习 Vue' },
{ id: 2, text: '写一个待办应用' }
])
const filteredTodos = computed(() =>
todos.value.filter(item => item.text.includes(keyword.value))
)
const addTodo = () => {
if (!keyword.value.trim()) return
todos.value.push({
id: Date.now(),
text: keyword.value
})
keyword.value = ''
}
const removeTodo = (id) => {
todos.value = todos.value.filter(item => item.id !== id)
}
</script>
```
`components/TodoList.vue`
```vue
<template>
<ul>
<li v-for="item in items" :key="item.id">
<span>{{ item.text }}</span>
<button @click="$emit('remove', item.id)">删除</button>
</li>
</ul>
</template>
<script setup>
defineProps({
items: {
type: Array,
default: () => []
}
})
defineEmits(['remove'])
</script>
```
6. 工程实践
6.1 实际开发操作步骤
-
先画出页面结构。
-
判断哪些是静态部分,哪些是动态部分。
-
找出页面状态:输入值、列表数据、当前选中项、显示隐藏状态。
-
决定哪些内容放父组件,哪些拆成子组件。
-
用 `props` 传数据,用 `emit` 回传事件。
-
给列表项补稳定 `key`。
-
最后再考虑样式和细节交互。
6.2 一个真实工程场景
比如做"商品列表页":
-
父组件负责:关键词、筛选项、商品数组、请求状态。
-
搜索栏组件负责:输入和点击搜索。
-
商品卡片组件负责:展示单个商品信息。
-
分页组件负责:页码切换。
7. 常见误区
-
**把所有东西都写在一个组件里**
-
**子组件直接修改 `props`**
-
**`v-for` 用索引当 `key`**
-
**把 `v-if` 和 `v-for` 写在同一个节点上**
-
**认为 `v-model` 是"Vue 黑魔法"**
8. 面试题
-
`v-if` 和 `v-show` 有什么区别?分别适合什么场景?
-
`v-model` 的本质是什么?
-
为什么 `v-for` 需要 `key`?如果不用会怎样?
-
父子组件怎么通信?
-
为什么子组件不能直接修改 `props`?
9. 自测题
-
你能不用看资料写出 `v-bind`、`v-model`、`v-for` 的基本用法吗?
-
你能说清楚 `v-if` 和 `v-show` 的性能差异吗?
-
你能独立把一个页面拆成父组件和两个子组件吗?
-
你能解释为什么 `key` 应该用稳定唯一值吗?
-
如果子组件点击删除按钮,你知道为什么更推荐用 `emit` 通知父组件,而不是子组件直接删数据吗?
10. 学完标志
学完这一阶段后,你应该能做到:
-
用 Vue 写出表单、列表、条件显示页面。
-
独立完成基础组件拆分。
-
正确使用 `props` 和 `emit` 完成父子通信。
-
说清楚 `v-if`、`v-show`、`v-model`、`v-for`、`key` 的场景和原理直觉。
第三阶段:响应式、生命周期与组件通信机制
1. 学什么
这一阶段进入 Vue 的核心能力层,重点是:
-
`ref` 和 `reactive`
-
`computed`
-
`watch` 和 `watchEffect`
-
生命周期钩子
-
父子、兄弟、跨层组件通信
-
`provide / inject`
-
共享状态该什么时候上 Pinia,什么时候不需要
2. 为什么重要
Vue 真正的"框架味道",主要就在这一层。
初学者最容易卡住的地方,不是模板,而是下面这些问题:
-
为什么有时候数据变了页面不变?
-
`computed` 和 `watch` 到底该用哪个?
-
接口请求该放在哪个生命周期里?
-
父组件、子组件、跨层组件之间如何传值才不乱?
3. 核心概念
3.1 `ref` 和 `reactive`
| 概念 | 适合什么数据 | 访问方式 | 常见场景 |
| --- | --- | --- | --- |
| `ref` | 基本类型,也可包对象 | JS 中用 `.value` | 数字、字符串、布尔值、DOM 引用 |
| `reactive` | 对象、数组 | 直接访问属性 | 表单对象、复杂状态对象 |
3.2 `computed`、`watch`、`watchEffect`
| 概念 | 作用 | 适合场景 |
| --- | --- | --- |
| `computed` | 计算派生值,有缓存 | 筛选结果、格式化显示、统计值 |
| `watch` | 监听指定源变化并执行副作用 | 发请求、同步本地存储、路由联动 |
| `watchEffect` | 自动收集内部依赖并执行 | 快速编写依赖驱动副作用 |
一句话区分:
-
**派生新值,用 `computed`**
-
**响应变化做副作用,用 `watch`**
3.3 生命周期
| 钩子 | 常见用途 |
| --- | --- |
| `onMounted` | 获取初始数据、访问真实 DOM |
| `onUpdated` | 某次更新后观察 DOM 结果 |
| `onUnmounted` | 清理定时器、事件监听、订阅 |
3.4 组件通信怎么选
| 场景 | 推荐方式 |
| --- | --- |
| 父 -> 子 | `props` |
| 子 -> 父 | `emit` |
| 跨层但层级固定 | `provide / inject` |
| 多组件共享、页面级甚至全局状态 | Pinia |
4. 原理解释
4.1 `computed` 为什么比函数更适合派生值
因为它有缓存。
只要依赖没变,`computed` 不会重复计算。
4.2 `watch` 为什么容易被滥用
因为很多人把"派生值"也写成 `watch`。
结果是本来可以通过公式推导的关系,被写成了同步脚本。
4.3 生命周期为什么存在
因为组件不是永远静止的,它有自己的运行过程:
-
创建
-
渲染
-
挂载到 DOM
-
更新
-
卸载
5. 示例
5.1 最小可运行示例
```vue
<template>
<div>
<h2>商品搜索</h2>
<input v-model="keyword" placeholder="输入关键词" />
<p>命中数量:{{ matchedCount }}</p>
<ul>
<li v-for="item in filteredProducts" :key="item.id">
{{ item.name }} - {{ item.price }} 元
</li>
</ul>
</div>
</template>
<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue'
const keyword = ref('')
const state = reactive({
products: []
})
onMounted(() => {
state.products = [
{ id: 1, name: 'Vue 实战课程', price: 99 },
{ id: 2, name: 'JavaScript 手册', price: 59 },
{ id: 3, name: 'Vue Router 指南', price: 39 }
]
})
const filteredProducts = computed(() =>
state.products.filter(item => item.name.includes(keyword.value))
)
const matchedCount = computed(() => filteredProducts.value.length)
watch(keyword, (newValue) => {
localStorage.setItem('last-keyword', newValue)
})
</script>
```
6. 工程实践
6.1 实战中的选择原则
-
页面展示用到的原始值,放 `ref` 或 `reactive`。
-
所有"由已有值推出来的新值",优先考虑 `computed`。
-
所有"监听变化后要去做外部动作"的逻辑,才考虑 `watch`。
-
接口首屏加载常放在 `onMounted`。
-
定时器、订阅、全局事件监听,在 `onUnmounted` 里清理。
6.2 一个真实工程场景
做"订单列表页"时常见状态有:
-
查询条件
-
当前页码
-
订单列表
-
加载中状态
-
总数
7. 常见误区
-
**用 `watch` 代替 `computed`**
-
**所有对象都用 `reactive`,所有值都混着写**
-
**忘记清理副作用**
-
**任何共享数据都塞进全局 store**
-
**误以为 `watchEffect` 是更高级的 `watch`**
8. 面试题
-
`ref` 和 `reactive` 有什么区别?
-
`computed` 和 `watch` 的区别是什么?
-
什么时候用 `watchEffect`?
-
Vue 生命周期最常用的是哪些?分别适合做什么?
-
如果多个组件都依赖同一份状态,你会怎么设计?
9. 自测题
-
你能举出三个必须用 `computed` 而不该用 `watch` 的场景吗?
-
你能解释为什么"搜索结果数量"适合 `computed` 吗?
-
你能说出 `onMounted` 和 `onUnmounted` 各自处理哪类逻辑吗?
-
你能给一个"局部状态不该放 Pinia"的例子吗?
-
你能不用资料写出一个 `watch` 监听输入框并同步本地存储的例子吗?
10. 学完标志
学完这一阶段后,你应该能做到:
-
正确区分原始状态、派生状态、副作用。
-
正确使用 `ref`、`reactive`、`computed`、`watch`。
-
知道请求、DOM 操作、清理逻辑该放在哪个生命周期。
-
能为父子通信、跨层通信、共享状态选择合理方案。
第四阶段:底层原理,理解 Vue 为什么这样设计
1. 学什么
这一阶段是从"会用"走向"能解释"的关键层,重点包括:
-
响应式原理:`Proxy`、依赖收集、触发更新
-
`effect`、`track`、`trigger`
-
调度更新与批量刷新
-
`nextTick`
-
虚拟 DOM
-
Diff 与 `key`
-
模板编译流程
-
为什么 Vue 3 比 Vue 2 在响应式层更现代
2. 为什么重要
中级工程师和只会写页面的区别,很大一部分就在这里:
-
你能不能解释"为什么 `key` 重要"
-
你能不能解释"为什么 DOM 更新不是同步立刻发生"
-
你能不能解释"为什么 `computed` 有缓存"
-
你能不能解释"为什么模板能转换成渲染函数"
3. 核心概念
3.1 响应式主链路
`读取响应式数据 -> 收集依赖 -> 数据变化 -> 触发副作用 -> 调度更新 -> Patch DOM`
3.2 关键术语
| 术语 | 含义 |
| --- | --- |
| `Proxy` | 对对象访问进行拦截,Vue 3 用它做响应式代理 |
| `track` | 在读取数据时记录"谁依赖了我" |
| `trigger` | 在修改数据时通知依赖重新执行 |
| `effect` | 依赖响应式数据的执行函数 |
| Scheduler | 控制更新时机,做批量合并 |
| Virtual DOM | 用 JS 对象描述 UI 结构 |
| Patch | 比较新旧节点后,最小化更新真实 DOM |
3.3 Vue 运行流程图
```mermaid
graph TD
A["响应式数据被读取"] --> B["track: 收集依赖"]
B --> C["数据发生变化"]
C --> D["trigger: 通知依赖"]
D --> E["调度器合并更新"]
E --> F["重新生成虚拟 DOM"]
F --> G["Diff 比较新旧节点"]
G --> H["Patch 到真实 DOM"]
```
4. 原理解释
4.1 为什么 Vue 3 用 `Proxy`
因为 `Proxy` 可以拦截对象的更多操作,能力更完整。
相比 Vue 2 基于 `Object.defineProperty` 的方案,Vue 3 在对象新增属性、数组处理等方面更自然。
4.2 为什么更新不是立刻同步打到 DOM
如果你一段逻辑里连续改三次状态,Vue 不会更新三次 DOM。
它会先把更新放进队列,再统一刷新。
4.3 `nextTick` 为什么存在
因为你有时需要在"DOM 已经完成这轮更新之后"再去拿真实元素。
4.4 模板编译链路
模板并不是直接在浏览器里"神奇运行"的,它大致会经历:
-
Template
-
解析成 AST
-
AST 转换优化
-
生成 render 函数
-
render 函数生成虚拟 DOM
-
runtime 负责 patch 到真实 DOM
5. 示例
5.1 `nextTick` 最小示例
```vue
<template>
<div>
<button @click="openInput">显示输入框并聚焦</button>
<input v-if="visible" ref="inputRef" />
</div>
</template>
<script setup>
import { nextTick, ref } from 'vue'
const visible = ref(false)
const inputRef = ref(null)
const openInput = async () => {
visible.value = true
await nextTick()
inputRef.value.focus()
}
</script>
```
6. 工程实践
6.1 一个真实工程场景
做"可编辑表格"时,如果列表 `key` 写成索引,你经常会遇到:
-
删除某行后,输入框内容串位
-
某行的编辑状态跑到别的行
6.2 企业里真正常用到原理理解的地方
-
列表为什么用唯一主键。
-
为什么有些场景要用 `nextTick`。
-
为什么某些 `computed` 很省性能。
-
为什么组件重渲染不等于整页重画。
7. 常见误区
-
**以为 Vue 更新一定是同步的**
-
**把虚拟 DOM 理解成"更快的 DOM"**
-
**觉得 `key` 只是为了消除警告**
-
**学原理只背名词**
-
**把所有性能问题都归因于 Vue**
8. 面试题
-
Vue 3 的响应式是怎么实现的?
-
`track` 和 `trigger` 分别做什么?
-
为什么 Vue 的 DOM 更新是异步批量的?
-
`nextTick` 的使用场景是什么?
-
为什么 `key` 在 Diff 中很重要?
-
模板从书写到页面渲染,中间大致经历了哪些步骤?
9. 自测题
-
你能把 Vue 的更新主链路完整说出来吗?
-
你能解释为什么连续修改状态时 Vue 不会立刻更新三次 DOM 吗?
-
你能举出一个必须依赖 `nextTick` 的场景吗?
-
你能解释"虚拟 DOM + Diff + Patch"之间的关系吗?
-
你能说明为什么模板其实最终会变成渲染函数吗?
10. 学完标志
学完这一阶段后,你应该能做到:
-
从原理层解释响应式和更新流程。
-
说清楚 `key`、`nextTick`、`computed` 缓存的设计原因。
-
面试时不再只会背 API 名字,而是能讲运行机制。
-
对 Vue 的更新和性能有基本判断能力。
第五阶段:工程实践,真正按企业方式组织 Vue 项目
1. 学什么
这一阶段进入完整工程层,重点掌握:
-
`Vite` 工程结构
-
`Vue Router`
-
`Pinia`
-
请求封装与接口层设计
-
`composables` 复用逻辑
-
目录结构设计
-
环境变量与构建配置
-
组件规范、页面规范、状态规范
-
常见 UI 库接入
-
构建、部署与基本测试思维
2. 为什么重要
企业里最看重的,不只是你会写按钮和列表,而是:
-
你会不会搭项目结构
-
你会不会拆页面、路由、状态、接口
-
你会不会控制代码耦合
-
你会不会写出别人能接手的代码
3. 核心概念
3.1 推荐目录结构
```text
src/
├─ api/ # 接口层
├─ assets/ # 静态资源
├─ components/ # 通用组件
├─ composables/ # 可复用组合函数
├─ router/ # 路由
├─ stores/ # Pinia 状态管理
├─ utils/ # 工具函数
├─ views/ # 页面组件
├─ App.vue
└─ main.js
```
3.2 路由、Store、Composables 各管什么
| 模块 | 职责 |
| --- | --- |
| Router | 页面导航、权限守卫、参数切换 |
| Pinia | 多组件共享状态、会话状态、缓存状态 |
| Composables | 提取可复用逻辑,如分页、请求、表单校验 |
| API 层 | 和后端交互,统一请求封装 |
3.3 什么状态该进 Pinia
适合进 Pinia 的:
-
登录用户信息
-
token
-
菜单权限
-
全局主题
-
多页面共享筛选条件或缓存数据
不一定要进 Pinia 的:
-
某个弹窗的显示状态
-
某个局部表单的临时输入
-
单个组件内部只自己用的值
4. 原理解释
4.1 为什么工程里要分层
因为真实项目的复杂度,主要不是一两个组件,而是:
-
页面很多
-
数据来源很多
-
组件复用很多
-
人很多
-
需求经常变
所以工程分层的本质,是**控制复杂度和边界**。
4.2 为什么逻辑要抽到 `composables`
组合式 API 的一个核心优势,就是可以把"成套逻辑"抽成函数复用。
比如:
-
列表分页逻辑
-
请求状态逻辑
-
表单校验逻辑
-
防抖搜索逻辑
4.3 为什么接口要做统一封装
如果请求散落在页面里,后面会很难处理:
-
token
-
错误提示
-
loading
-
重试
-
统一 baseURL
5. 示例
5.1 最小工程片段
`src/router/index.js`
```js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import UserView from '../views/UserView.vue'
const routes = [
{ path: '/', component: HomeView },
{ path: '/user', component: UserView }
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
```
`src/stores/user.js`
```js
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useUserStore = defineStore('user', () => {
const userInfo = ref(null)
const setUserInfo = (value) => {
userInfo.value = value
}
return {
userInfo,
setUserInfo
}
})
```
`src/main.js`
```js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
```
6. 工程实践
6.1 一个中小型项目的推荐落地步骤
-
用 `Vite` 初始化项目。
-
配好路由和基础布局。
-
按页面和通用组件拆目录。
-
抽 API 层,统一请求工具。
-
接入 Pinia 管理共享状态。
-
抽复用逻辑到 `composables`。
-
增加 loading、错误态、空态。
-
统一命名、代码风格、提交规范。
6.2 一个真实工程场景
做"后台管理系统"时,通常会有这些模块:
-
登录页
-
首页仪表盘
-
用户管理
-
角色权限
-
商品管理
-
订单管理
7. 常见误区
-
**把 Pinia 当作"任何状态都该放进去的仓库"**
-
**不抽 composables,复制业务逻辑**
-
**接口层和页面层不分**
-
**目录结构只模仿别人,不按业务边界设计**
-
**只管功能跑通,不管错误态和空态**
8. 面试题
-
Vue 项目目录一般怎么设计?
-
Router、Pinia、Composables 分别适合管理什么?
-
什么时候该把状态放进 Pinia?
-
为什么请求要统一封装?
-
你会如何设计一个 Vue 后台管理系统的前端结构?
9. 自测题
-
你能独立搭一个含 Router 和 Pinia 的 Vue 项目骨架吗?
-
你能说清楚为什么局部弹窗状态通常不放全局 store 吗?
-
你能举出两个适合抽成 `composables` 的逻辑吗?
-
你能设计一个 `api/`、`views/`、`components/` 分层明确的目录结构吗?
-
你能说明 loading、空态、错误态为什么属于工程基本功吗?
10. 学完标志
学完这一阶段后,你应该能做到:
-
搭建一个 Vue 真实项目骨架。
-
合理使用 Router、Pinia、API 层、Composables。
-
按业务边界组织代码,而不是只把功能塞进组件。
-
具备中小型项目开发的基础工程视角。
第六阶段:常见问题与排错,形成稳定的调试能力
1. 学什么
这一阶段重点学习:
-
Vue 页面不更新的常见原因
-
`props` 修改警告排查
-
`key` 错误导致的列表问题
-
`reactive` 解构导致响应式丢失
-
`watch` 死循环
-
`nextTick` 时机问题
-
路由参数变化但页面逻辑未更新
-
异步请求竞态
-
样式作用域与样式污染
-
DevTools 和日志调试思路
2. 为什么重要
企业里真正拉开差距的,往往不是"能不能写一个功能",而是:
-
功能出了问题你能不能快速定位
-
线上问题你能不能稳定修
-
你能不能把 bug 归因到状态、模板、生命周期、异步还是工程结构
3. 核心概念
3.1 常见症状与原因对照表
| 症状 | 常见原因 | 第一检查点 |
| --- | --- | --- |
| 数据变了但页面不更新 | 响应式丢失、直接改了非响应式值 | 是否用了 `ref` / `reactive` |
| 列表删除后输入框串位 | `key` 用错 | 是否用了稳定唯一 id |
| 子组件报 `props` 修改警告 | 直接改了父传入值 | 是否应该 `emit` 回父组件 |
| DOM 取不到最新元素 | 更新还没完成 | 是否需要 `nextTick` |
| 搜索结果错乱 | 异步竞态 | 是否取消旧请求或比对请求序号 |
| 页面切路由参数后没刷新 | 组件复用导致逻辑未重新触发 | 是否监听路由参数变化 |
3.2 一个排错主线
-
状态有没有变
-
变的是不是响应式状态
-
模板有没有依赖这个状态
-
组件有没有被复用或缓存
-
更新时机是不是还没到
-
是否被异步请求覆盖
4. 原理解释
4.1 为什么会出现"数据变了页面不变"
最常见不是 Vue 不工作,而是:
-
你改的不是响应式数据
-
你把 `reactive` 对象错误解构后失去追踪
-
模板根本没依赖这个值
4.2 为什么异步请求会造成显示错乱
比如你快速输入搜索词:
-
先发请求 A
-
再发请求 B
-
B 先回来
-
A 后回来覆盖了 B 的结果
4.3 为什么路由切了参数,组件却不重新创建
因为很多时候路由是复用同一个组件实例,只是参数变了。
所以如果你的逻辑只写在 `onMounted`,参数变了也不会自动再跑。
5. 示例
5.1 响应式丢失示例
错误写法:
```js
import { reactive } from 'vue'
const state = reactive({
count: 0
})
const { count } = state
count++
```
更合理的写法:
```js
import { reactive, toRefs } from 'vue'
const state = reactive({
count: 0
})
const { count } = toRefs(state)
count.value++
```
6. 工程实践
6.1 通用排错步骤
-
打日志看数据是否变化。
-
用 Vue DevTools 看组件状态。
-
确认模板是否真的消费了该状态。
-
检查 `key`、生命周期、路由参数、缓存组件。
-
检查异步请求顺序和覆盖关系。
-
最后再怀疑框架或库本身。
6.2 一个真实工程场景
做"用户搜索页"时,输入框快速输入会导致结果闪烁或回退。
解决思路通常是:
-
做防抖
-
记录最新请求编号
-
或取消旧请求
7. 常见误区
-
**页面没更新就先怀疑 Vue**
-
**一出 bug 就到处加 `nextTick`**
-
**日志只看接口返回,不看状态流转**
-
**不复盘 bug 根因**
-
**把排错当经验主义**
8. 面试题
-
Vue 中"数据更新了但页面没更新"可能有哪些原因?
-
为什么不推荐解构 `reactive` 对象后直接使用?
-
列表为什么不建议用索引做 `key`?
-
`nextTick` 常见误用有哪些?
-
路由参数变化但组件不重新请求数据,你会怎么排查?
9. 自测题
-
你能给出一个响应式丢失的例子并修复吗?
-
你能描述一个列表错位 bug 的根因吗?
-
你能说明为什么某些路由切换后页面没有重新请求吗?
-
你能给出一个避免异步竞态的策略吗?
-
你能写出自己的 Vue 排错步骤清单吗?
10. 学完标志
学完这一阶段后,你应该能做到:
-
独立排查大多数基础到中级 Vue 问题。
-
知道 bug 是状态问题、时机问题、通信问题还是异步问题。
-
面试中能回答"怎么排错",不只是"怎么用"。
第七阶段:面试与评估,把知识变成可表达、可回答、可证明的能力
1. 学什么
这一阶段重点学习:
-
Vue 高频面试题分类
-
面试回答结构
-
概念题、原理题、工程题、排错题的答法
-
如何讲自己的 Vue 项目
-
如何把"会用"升级成"会解释"
2. 为什么重要
面试不是背书比赛,而是在判断你是否真正理解、是否做过、是否能在团队里承担工作。
面试官尤其关注三点:
-
你能否讲清楚因果关系。
-
你能否把原理落到代码和项目。
-
你是否有稳定的工程判断,而不是只会背八股。
3. 核心概念
3.1 四类问题怎么区分
| 类型 | 面试官想看什么 | 回答重点 |
| --- | --- | --- |
| 概念题 | 你是否知道基础定义 | 先定义,再场景 |
| 原理题 | 你是否理解底层机制 | 先流程,再设计原因 |
| 工程题 | 你是否做过真实项目 | 先场景,再架构与权衡 |
| 排错题 | 你是否能解决问题 | 先定位思路,再给方案 |
3.2 一个通用回答模板
-
先给一句定义
-
说它解决什么问题
-
说核心机制
-
说典型场景
-
说常见坑或设计权衡
3.3 容易混淆的高频对比
| 对比项 | 关键区别 |
| --- | --- |
| `computed` vs `watch` | 一个算派生值,一个做副作用 |
| `ref` vs `reactive` | 一个包单值,一个代理对象 |
| `v-if` vs `v-show` | 一个控制创建销毁,一个控制显示隐藏 |
| `props` vs Pinia | 一个是近距离通信,一个是共享状态管理 |
| `watch` vs `watchEffect` | 一个显式监听源,一个自动收集依赖 |
4. 原理解释
4.1 为什么面试官喜欢追问"为什么"
因为"怎么用"可以靠记忆,"为什么这样设计"更能体现:
-
你是否真正理解
-
你是否有迁移能力
-
你能否在新场景中做判断
4.2 一个标准答案应该长什么样
以"`computed` 和 `watch` 区别"为例:
-
`computed` 用于根据已有响应式数据推导新值,带缓存,适合展示层派生状态。
-
`watch` 用于监听某个值变化后执行副作用,比如发请求、同步本地存储。
-
如果本质是公式关系,用 `computed`;如果本质是变化触发外部动作,用 `watch`。
5. 示例
5.1 一个高频面试题示范回答
题目:Vue 为什么要使用 `key`?
参考答法:
> `key` 的核心作用是给虚拟 DOM 中的节点提供稳定身份,方便 Diff 过程正确复用和移动节点。
> 如果没有稳定 `key`,或者直接用索引,当列表发生插入、删除、重排时,Vue 可能会错误复用 DOM,导致输入框串位、本地状态错乱等问题。
> 所以在动态列表里,应该优先使用业务稳定唯一 id 作为 `key`。
6. 工程实践
6.1 如何讲项目
讲 Vue 项目时,不要只说"我做了登录页和列表页",而要按下面顺序:
-
项目是做什么的
-
技术栈是什么
-
你负责的模块是什么
-
页面和状态是怎么组织的
-
遇到过什么问题
-
你怎么优化或排错的
6.2 一个真实工程场景
比如你做了"后台管理系统",可以这样讲:
-
我用 `Vue 3 + Vite + Vue Router + Pinia` 搭建前端项目。
-
负责了用户管理、角色权限、订单列表模块。
-
页面层和通用组件层做了拆分,接口层做了统一封装。
-
对搜索列表做了防抖和请求竞态控制。
-
对表单弹窗用 `props / emit` 管理局部状态,全局用户信息放 Pinia。
7. 常见误区
-
**只背定义,不会讲场景**
-
**只讲"我做了什么",不讲"为什么这样设计"**
-
**只讲 happy path,不讲问题和权衡**
-
**面试题回答过短**
-
**面试题回答过散**
8. 面试题
-
Vue 3 和 Vue 2 在响应式实现上有什么差异?
-
`computed` 和 `watch` 的区别是什么?
-
`nextTick` 的作用和场景是什么?
-
你会如何设计一个 Vue 后台管理项目的结构?
-
Pinia 和组件局部状态应该怎么划分边界?
9. 自测题
-
你能在 3 分钟内解释清楚 Vue 响应式原理吗?
-
你能在 2 分钟内解释清楚 `computed` 和 `watch` 的区别吗?
-
你能用项目场景说明什么时候要用 Pinia 吗?
-
你能讲出一个列表 `key` 用错导致的 bug 吗?
-
你能把一个项目经验讲成"场景 -> 设计 -> 问题 -> 解决"的结构吗?
10. 学完标志
学完这一阶段后,你应该能做到:
-
系统回答 Vue 基础到中级面试题。
-
用原理、场景、权衡三个层次组织答案。
-
把项目经验讲得具体、可信、可追问。
第八阶段:学习总结与知识闭环,从会写到持续进阶
1. 学什么
这一阶段的重点不再是新 API,而是:
-
如何把 Vue 知识串成体系
-
如何通过项目闭环巩固能力
-
如何继续进阶到中级甚至更高
-
如何建立长期学习方法
2. 为什么重要
很多人学到这里会出现两个问题:
-
学了很多点,但串不起来
-
会做练习题,但做项目容易散架
3. 核心概念
3.1 Vue 的知识主干
你现在应该把 Vue 理解成下面这棵树:
-
最上层是页面与业务需求。
-
第二层是组件化和状态管理。
-
第三层是响应式、生命周期、通信机制。
-
第四层是编译、调度、虚拟 DOM、Diff 等底层原理。
-
外围是 Router、Pinia、请求层、构建、测试、部署等工程体系。
3.2 学习本质
Vue 学习不是"背多少 API",而是:
-
能不能把页面拆成组件
-
能不能把业务拆成状态
-
能不能把状态变化映射为界面变化
-
能不能把项目组织成可维护工程
-
能不能排错和解释
3.3 下一步进阶方向
| 方向 | 为什么值得继续学 |
| --- | --- |
| TypeScript | 企业 Vue 项目中非常常见 |
| Nuxt | SSR、SEO、全栈能力 |
| VueUse | 提高组合式逻辑复用效率 |
| 测试 | 单元测试、组件测试、端到端测试 |
| 性能优化 | 大列表、懒加载、缓存、渲染边界 |
| 源码 | 从会用走向深入理解框架设计 |
4. 原理解释
4.1 为什么项目是最好的复习方式
因为项目会逼你把分散知识点串起来:
-
模板语法
-
响应式
-
路由
-
状态管理
-
请求
-
错误处理
-
组件复用
-
排错
4.2 正确的复习路径
-
回顾阶段 2 和阶段 3,确保 API 和心智模型稳定。
-
回顾阶段 4,确保能解释关键原理。
-
用阶段 5 的工程方式做项目。
-
用阶段 6 的排错方法复盘问题。
-
用阶段 7 的答题方法做口头表达训练。
5. 示例
5.1 一个完整项目闭环示例
建议你做一个"任务管理系统",至少包含:
-
登录页
-
任务列表页
-
任务筛选和搜索
-
新增 / 编辑 / 删除任务
-
任务状态切换
-
路由切换
-
Pinia 管理用户信息
-
接口层封装或本地 mock
6. 工程实践
6.1 推荐的 4 周推进法
-
第 1 周:完成阶段 1 到阶段 3 的示例和练习。
-
第 2 周:补完阶段 4,开始写小项目。
-
第 3 周:按阶段 5 的方式把小项目工程化。
-
第 4 周:做排错复盘和模拟面试。
6.2 企业里继续深入会学什么
-
TypeScript + Vue 3
-
权限系统与动态路由
-
组件库封装
-
大列表性能优化
-
单元测试与 E2E 测试
-
SSR / Nuxt
7. 常见误区
-
**教程看很多,项目做很少**
-
**写完项目不复盘**
-
**只学功能,不学排错**
-
**只学 Vue,不补 JavaScript 和工程基础**
8. 面试题
-
学完 Vue 核心后,你下一步会深入什么,为什么?
-
如果让你从零搭一个 Vue 项目,你会按什么顺序做?
-
你如何判断自己从初学者进入了初级 / 中级水平?
-
Vue 项目里你最常见的 bug 类型是什么?你如何建立预防机制?
9. 自测题
-
你能把 Vue 的知识主干画出来吗?
-
你能给自己设计一个 4 周 Vue 学习计划吗?
-
你能用一个项目串起模板、响应式、路由、Pinia、请求封装吗?
-
你能清楚说出自己目前最薄弱的是语法、原理、工程还是排错吗?
10. 学完标志
学完这一阶段后,你应该能做到:
-
把 Vue 核心知识讲成一个完整体系。
-
用项目把知识点串起来,而不是零散记忆。
-
明确自己下一步该补什么。
-
形成持续迭代、自测、复盘的学习闭环。
评估体系
1. 入门达标标准
达到入门,至少应满足:
-
知道 Vue 是什么,能解释"状态驱动 UI"。
-
会创建并运行一个 Vue 项目。
-
会写 `ref`、事件绑定、条件渲染、列表渲染。
-
能完成一个计数器或待办列表。
2. 初级达标标准
达到初级,至少应满足:
-
会写组件,能用 `props / emit` 通信。
-
能正确使用 `computed`、`watch`、生命周期。
-
会使用 Vue Router 和 Pinia 做基础项目。
-
能完成一个中小型页面模块。
-
能解决常见基础 bug。
3. 中级达标标准
达到中级,至少应满足:
-
能解释响应式、调度、虚拟 DOM、Diff 的主链路。
-
能按工程方式组织项目目录、接口层、状态层、路由层。
-
能处理常见异步竞态、列表 key、响应式丢失、生命周期时机问题。
-
能讲清楚项目设计选择和取舍。
-
能比较稳定地应对基础到中级 Vue 面试。
4. 一套自测题
-
Vue 为什么说是"声明式 UI 框架"?
-
`ref` 和 `reactive` 有什么区别?
-
`computed` 和 `watch` 的区别是什么?
-
`v-if` 和 `v-show` 分别适合什么场景?
-
为什么 `v-for` 需要 `key`?
-
子组件为什么不应该直接修改 `props`?
-
`onMounted` 和 `onUnmounted` 常用于做什么?
-
`nextTick` 的作用是什么?
-
Pinia 适合管理什么状态?
-
Vue 中"数据变了页面不更新"你会如何排查?
-
路由参数变化但页面不更新,你会怎么处理?
-
Vue 模板最终为什么能变成页面?
5. 一套面试题
-
Vue 3 响应式原理是怎样的?
-
`computed` 为什么有缓存?和方法调用有什么区别?
-
说说你对 `watch`、`watchEffect` 的理解。
-
为什么 Vue 的 DOM 更新通常不是同步立即执行的?
-
`nextTick` 的底层价值是什么?
-
虚拟 DOM 的意义是什么?
-
`key` 在 Diff 中扮演什么角色?
-
你会如何拆分一个复杂页面的组件?
-
你会如何设计一个 Vue 后台管理系统?
-
什么时候用 `props / emit`,什么时候用 Pinia?
-
你在 Vue 项目里遇到过什么典型 bug?如何定位?
-
Vue 3 相比 Vue 2,你觉得最重要的变化是什么?
6. 一套实战任务
实战任务用于验证"会写页面 + 会组织状态":
-
实现一个待办事项应用,支持增删改查、状态筛选、关键字搜索。
-
用组件拆分成输入区、列表区、筛选区。
-
使用 `computed` 实现筛选结果。
-
使用 `watch` 把搜索词同步到本地存储。
-
给动态列表使用稳定 `key`。
-
页面加入空态提示和删除确认。
7. 一套项目任务
项目名称:任务管理后台系统
最低要求:
-
使用 `Vue 3 + Vite + Vue Router + Pinia`。
-
包含登录页、任务列表页、任务详情页。
-
支持筛选、分页、搜索、新增、编辑、删除。
-
有统一 API 层或 mock 数据层。
-
有 loading、错误态、空态。
-
路由和页面结构清晰。
-
能讲清楚状态边界、组件拆分和请求流程。
加分项:
-
使用 TypeScript。
-
使用 composables 抽分页或请求逻辑。
-
处理请求竞态。
-
做基础权限控制。
-
写一部分测试。
8. 对你回答的评分标准
总分 100,建议按下面维度评分:
| 维度 | 分值 | 评分标准 |
| --- | --- | --- |
| 基础概念 | 20 | 是否能清楚解释核心术语 |
| 代码能力 | 25 | 是否能独立写出常用页面和组件 |
| 原理理解 | 20 | 是否能解释响应式、更新、Diff 等主链路 |
| 工程实践 | 15 | 是否会用 Router、Pinia、API 分层 |
| 排错能力 | 10 | 是否有清晰定位步骤 |
| 面试表达 | 10 | 是否能讲清楚定义、场景、原理、权衡 |
参考分段:
-
0 到 59:知识零散,项目和面试都不稳定。
-
60 到 74:达到入门,可写简单页面。
-
75 到 84:达到初级,可做中小模块。
-
85 到 100:接近中级,具备解释、工程、排错综合能力。
9. 如何根据错误结果反向补课
| 你错在哪类题 | 说明短板在哪 | 回补阶段 |
| --- | --- | --- |
| 模板语法、组件基础题 | 页面表达能力不足 | 第二阶段 |
| `ref`、`reactive`、`computed`、生命周期题 | 状态和机制没吃透 | 第三阶段 |
| 响应式原理、`nextTick`、`key`、Diff 题 | 原理理解不足 | 第四阶段 |
| Router、Pinia、目录结构、API 分层题 | 工程化能力不足 | 第五阶段 |
| 页面不更新、竞态、路由复用题 | 排错能力不足 | 第六阶段 |
| 项目讲不清、答案发散 | 面试表达不足 | 第七阶段 |
进一步的补课方法:
-
概念不会:回到对应阶段,重写定义并举一个自己的例子。
-
代码不会:重写该阶段最小示例,要求不看资料完成。
-
原理不会:把运行流程画成步骤图,再口头讲一遍。
-
工程不会:按第五阶段重新搭一个最小项目骨架。
-
排错不会:故意制造一个 bug,再按第六阶段流程定位。
-
面试不会:录音回答高频题,听自己是否只会背定义。
10. 最终闭环执行方案
建议你按下面方式执行这份文档:
-
完成第一到第三阶段,建立 Vue 核心使用能力。
-
完成第四阶段,把 API 背后的原理串起来。
-
完成第五阶段,用工程方式做一个项目骨架。
-
完成第六阶段,主动制造并修复几个典型 bug。
-
完成第七阶段,做一次模拟面试。
-
完成第八阶段,交付一个完整项目并复盘。
到这里,你对 Vue 的掌握就不再是"看过教程",而是更接近:
-
能理解
-
能解释
-
能上手
-
能排错
-
能通过基础到中级面试