“vue笔记”这四个字,说起来轻松,做起来很容易变成一座垃圾山。我从开始系统学 Vue 到现在,记过的笔记超过一千条,最痛苦的阶段不是看不懂 API,而是要用的时候找不到。想查一条组件通信的写法,翻了半小时;想复盘一个线上 Bug,当时只写了一句“解决了”,三个月后再看完全不知道解决了什么。后来我把笔记当成代码工程来维护,把知识笔记和项目笔记分开,把每条笔记都设计成可检索、可复用的卡片。这篇就分享我的整套 Vue 笔记体系,包括目录怎么设计、核心知识点怎么沉淀、Bug 怎么变成排查手册,以及从私人笔记到团队知识库的迁移方法。适合准备认真学 Vue 的初学者、带项目团队的前端工程师,也适合想把笔记写成技术文章的同学。
1. 第一步:把 Vue 笔记拆成“知识笔记”和“项目笔记”
1.1 为什么千万不能混着记
我见过很多人记 Vue 笔记,路径是“新建一个 md,随手往里面塞”。今天学的v-model原理写在里面,明天项目里遇到的keep-alive缓存问题也写在里面。三个月后打开这份笔记,前五条是基础语法,第六条是“某项目登录状态丢失”,第七条又变成 Vue Router 的路由守卫……这种情况基本等于白记。查找成本高,信息前后逻辑断裂,复习的时候根本没法按主题推进。
更合理的方式是把笔记拆成两套体系。
- 知识笔记,按主题组织,回答的是“这个东西是什么、怎么用、为什么这样设计”,对应 Vue 的基础语法、组件化、路由、状态管理、工程化等持续沉淀的知识。
- 项目笔记,按项目和日期组织,回答的是“在某次实战里遇到了什么问题、怎么排查、怎么修复”,对应 Bug 日志、复盘文档、性能优化记录等带有事件属性的内容。
为什么要拆?因为两者的生命周期完全不同。知识笔记是长期资产,半年后依然适用;项目笔记中很大一部分会随着项目迭代失去价值,只有少数能提炼成通用经验。混在一起后,长期资产会被时效性信息淹没,检索时不知道某条结论到底过没过期。
一套我实际用过的目录结构是这样的:
vue-notes/ ├── README.md ├── 10-basic/ # 基础语法、模板编译、指令 ├── 20-component/ # 组件通信、插槽、生命周期 ├── 30-router/ # 路由配置、守卫、懒加载 ├── 40-state/ # 响应式原理、Pinia、状态设计 ├── 50-engineering/ # Vite、构建、调试、部署 ├── 90-snippets/ # 常用代码片段、速查表 └── project-log/ ├── 2024-06-xx-order-system.md └── 2025-01-xx-admin-panel.md这个目录里10/20/30这种数字前缀特别重要,它让文件夹在编辑器里自动按逻辑顺序排列,而不是按字母顺序把engineering排到最前面。这个看似很小的排序规则,决定了你后期能不能快速定位一整块主题。
1.2 用“三问法”判断一条记录应该放哪里
每次准备记一条内容的时候,先问自己三个问题:
- 这条内容是“怎么用”还是“为什么”?怎么用优先放知识笔记,为什么更值得放知识笔记并补充原理背景。
- 它是不是只属于某个特定项目?如果是特定业务背景下的排查过程,放项目笔记。
- 我三个月后会不会还想查它?如果会,而且它和 Vue 的核心机制相关,放进知识笔记,而不只是在项目里留一句记录。
我举三个实际例子:
| 场景 | 归属 | 理由 |
|---|---|---|
| 自定义组件上使用 v-model 的绑定规则 | 知识笔记 | 通用语法规则,不依赖业务环境 |
| 某项目中订单列表因对象引用变化导致无限重渲染 | 项目笔记 | 与项目数据结构和接口实现强相关,需要在项目上下文里复盘 |
| 从这个问题提炼出的“依赖可变对象时应该如何设计引用更新” | 知识笔记 | 已经从具体问题抽象成了通用设计经验 |
“三问法”最大的价值不是分类,而是强迫你在记录的第一时间做一次思考。思考过的东西哪怕分类不完美,也比随手粘贴强出一个量级。我会在每季度统一调整一次目录归属,把项目笔记里那些逐渐变成“通用经验”的条目,迁移到知识笔记对应主题下面。
2. 知识笔记怎么写才算合格:一张链路 + 一段代码 + 三条提示
2.1 每个大主题开头先画“机制链路”
知识笔记很容易变成文档搬运工。搬官方文档没有错,但搬运的东西不是你的。我的习惯是每个大主题开头先用 3 到 5 个名词,把机制链路写出来,相当于这张主题的地图。
比如 Vue 响应式系统的笔记,开头是这样的:
data -> reactive -> track(依赖收集) -> trigger(触发更新) -> 组件重新渲染不要小看这一行字。它决定了你之后理解问题时,大脑里有一条清晰的路径。很多人看ref和reactive的用法时不知所措,就是因为脑子里没有这条链路:不知道ref在访问时为什么是.value,不知道为什么解构reactive对象会丢失响应式。链路上所有问题都能找到位置。
再比如组件渲染更新相关的笔记,开头可以写成:
初始化实例 -> beforeCreate -> created -> 模板编译/挂载 -> onMounted -> 状态变化 -> 重新渲染 -> onUpdated -> 卸载 -> onUnmounted这条生命周期链路是排查“为什么数据变了但页面没变”时必须复查的底层顺序。标注链路以后,你可以把后续所有相关细节挂在对应节点上。onMounted里有哪些注意事项就挂在“挂载”节点,watch会在哪些时机触发就挂在“状态变化”节点。这样一整理,笔记结构像一棵树,而不会是一堆平铺的段落。
2.2 代码块必须带“关键位置注释”
很多人的笔记里代码块就是整段复制。看起来没问题,但复读一个月以后,自己都不知道核心逻辑在哪一行。我的建议是,笔记里的代码必须留注释,注释不是解释这段代码在干什么,而是解释“这一行为什么这么写”以及“去掉会怎么样”。
举一个响应式ref的实现示例,我会在笔记里这样记:
let value = 0 const effect = () => { console.log(`当前值: ${value}`) } // 关键点:依赖收集发生在 effect 执行阶段 // 如果这里没有触发 getter,后续 value 修改不会通知任何副作用 function track() { activeEffect = effect effect() activeEffect = null } function trigger() { effect() } track() // 第一次执行,收集依赖 value = 1 // 没有 trigger,页面不会自动更新 trigger() // 手动触发,输出 当前值: 1注意我在代码边上标出的两行:依赖收集发生在 effect 执行阶段。如果没有理解这一点,就理解不了为什么watch必须指定依赖、为什么有些响应式变量在模板中没被读取就不会触发更新。代码块带着这类注释,才能变成“可复用的思考片段”,而不是一段无生命的示例。
下面是我记笔记的固定模板,一个主题只占一份文件:
# 主题名 ## 机制链路 一行或几行名词关系 ## 代码示例 带关键注释的示例 ## 易错点 3 条以内 ## 和相邻知识的区别 用表格或要点对比 ## 可能被问到的点 面试官/同事可能会深挖的方向这个模板会让笔记内容均衡,不会只抄代码、丢掉原理。
2.3 固定写三类提示:易错点、对比点、追问点
我建议每条知识笔记末尾固定追加三个小标题,哪怕只写一行。长期坚持,笔记质量会明显提升。
“易错点”记录的是自己或同事真正踩过的坑。比如“onMounted里访问子组件ref,要在nextTick之后才能保证子组件挂载完成”。这类内容官方文档不一定写在显眼位置,但对开发效率影响巨大。
“对比点”记录的是相邻概念的边界。computed与watch的区别,我用一张表来记:
| 维度 | computed | watch |
|---|---|---|
| 触发时机 | 依赖变化时惰性重新计算 | 被侦听的源变化时执行副作用 |
| 是否产生缓存 | 是,依赖不变不会重新计算 | 否,每次触发都执行回调 |
| 典型场景 | 派生状态,如total = price * count | 异步操作,如表单值变化后请求 |
| 注意事项 | 内部不应有副作用 | 默认不触发,需要immediate才立即执行一次 |
这张表除了自测用,还能直接当面试准备的速查卡。很多看似高深的问题,拆成“时机、缓存、场景、注意事项”四个维度之后,记忆负担会小很多。
“追问点”记录的是别人可能继续深入的问题。比如笔记里写了“reactive深层对象是响应式的”,那追问题就是“Proxy 的 get 拦截在什么时候触发依赖收集”。写追问点不是为了自虐,而是让笔记具备扩展能力:将来看到新资料,直接补到追问点下面。我的很多深入理解,就是被这些追问题一步步逼出来的。
3. 沉淀哪些 Vue 核心知识点最划算
3.1 响应式原理:用最小实现理解现代前端框架的基石
响应式是 Vue 最核心的引擎,不理解它,后面所有“为什么”都解释不清楚。在我笔记的“40-state”目录里,第一份文件就是响应式原理,记录了从 Vue 2 到 Vue 3 的变化。
Vue 2 使用Object.defineProperty拦截对象属性,它的限制很多:新增属性不会自动变成响应式,数组的下标操作没法直接拦截。Vue 3 改用Proxy代理对象,可以拦截属性读取、写入、删除、遍历等操作。但这不是全部,笔记里还要记清楚一个关键点:Proxy的代理对象和目标对象之间不是等价的。
我曾在笔记里写了一个最小响应式模型,大约 40 行:
const deps = new Set() let activeEffect = null function reactive(obj) { return new Proxy(obj, { get(target, key, receiver) { // 收集依赖:读取属性时把当前副作用函数加入集合 if (activeEffect) deps.add(activeEffect) return Reflect.get(target, key, receiver) }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver) // 触发更新:写入属性后执行所有依赖的副作用 deps.forEach(fn => fn()) return result } }) } function effect(fn) { activeEffect = fn fn() activeEffect = null } const state = reactive({ count: 0 }) effect(() => console.log('count changed:', state.count)) state.count++ // 输出 count changed: 1这段代码省略了不同属性各自维护依赖集合等细节,但足够用来理解依赖收集的核心。笔记里我特别注明:真实框架的track会按 key 维护依赖,每个属性一个 Set,而不是全局只有一个 Set。不写清楚这一点,以后看源码时会把“依赖集合”的概念搞混。
3.2 组件通信:七种方式各自的边界
组件通信是 Vue 面试高频区,也是实际项目里最容易被乱用导致返工的地方。我的笔记给每种通信方式都建立了一页,旁边写着“什么时候别用它”。
props + emit:父子组件最基础的方式。注意点:props 只读,子组件不能直接赋值修改;事件名推荐写update:前缀以便配合 v-model。v-model:本质是:model-value加@update:model-value的语法糖。自定义组件上使用多个 v-model 需要指定不同的 prop 名。provide / inject:适合跨层级注入,但要谨慎用。它是响应式的,可注入的引用修改后很难追踪来源。ref获取子组件实例:适合命令式调用,比如操作表单组件暴露的校验方法。必须在onMounted之后访问。- 事件总线:适合极小项目或临时方案。Vue 3 一般用
mitt实现,大量使用时状态会变得不可预测,我基本只在非核心模块里用它。 Pinia:全局状态的默认答案。适合多个非父子组件共享状态,有完整的 devtools 支持。- 插槽:适合组件复用时的结构分发。作用域插槽可以把子组件的数据暴露给父组件使用。
笔记里我用表格做了个“选型速查”:
| 场景 | 推荐方式 | 不推荐的方式 |
|---|---|---|
| 父组件渲染子组件,需要反馈事件 | props + emit / v-model | provide/inject |
| 深层嵌套,祖先组件提供配置 | provide/inject | 逐层透传 props |
| 多个页面共享登录状态/购物车 | Pinia | 事件总线 |
| 子组件要把渲染结构交还父组件控制 | 插槽 | 用 props 传模板字符串 |
通信方式没有绝对的好坏,只有边界。笔记的重点是记清“为什么这个场景不推荐另一种方式”。
3.3 生命周期与异步时序
生命周期相关的坑,几乎都是异步时序造成的。我的笔记单独开了一页,专门写常见场景。
第一,onMounted和异步请求。在onMounted里发请求本身没问题,但如果在组件卸载后请求才返回,再去更新状态,控制台会有警告,严重时导致内存泄漏。解决方法是记录一个卸载标记,或者在请求返回处判断组件实例是否已卸载。
第二,watch的时序问题。watch默认在状态变化后异步执行(确切地说是渲染前后按照配置执行),如果你需要在 DOM 更新后读取最新 DOM,要用flush: 'post'。这条很容易被忽略,因为在模板里直接显示数据看不出问题,一操作 DOM 才发现拿到的还是旧值。
第三,nextTick的作用。数据变化后 DOM 不会立即更新,nextTick的回调会等这次更新完成后执行。我在笔记里用一行话总结:数据变了不代表 DOM 变了,想要拿到新 DOM,排队等下一个 tick。
3.4 路由与状态管理:不是靠背 API,而是靠应用约束
路由笔记里我不会背每个配置项,而是记两条约束:一是所有页面级组件都要用懒加载,二是路由守卫里不要写太重的前置逻辑。常见错误是每个页面进入时都去请求用户信息,结果把鉴权请求打爆。更合理的做法是把用户信息放在 Pinia 仓库中统一管理,在全局前置守卫里判断是否存在,不存在才拉取。
状态管理笔记的要点是“状态的更新路径要单一”。Pinia 的 store 里,state是数据,getters是派生数据,actions是修改入口。组件里尽量不直接修改深层 state,而是通过 action 走一遍。这样的好处是将来出现“某个状态怎么变的”这类问题,可以直接在 action 里定位。
这些内容是知识笔记中的骨架。我的笔记中每一条都附有代码块和追问,但不需要把官方文档全部抄进来,只需要把“最容易出问题的细节”和“框架设计背后的取舍”记清楚。
4. 项目笔记:把 Bug 变成排查手册
4.1 用固定模板记录每条 Bug
项目笔记最难的不是记录,而是记录得可复盘。我用的模板固定为七个字段:
日期 / 模块 / 问题现象 / 复现步骤 / 根因 / 修复方案 / 回归验证看起来很死板,但这个模板帮我避开了大量“记了等于没记”的情况。比如早期我的 Bug 记录经常只写“修复了列表闪烁问题”,三个月后复盘时根本想不起来原因是异步竞态还是数据引用问题。现在模板强制我写根因和验证方式,即使当时只花一分钟,长期收益也非常明显。
有一个细节值得提醒:问题现象和根因要分开写。现象是用户视角的描述,比如“切换筛选条件后列表短暂显示上一次的数据”;根因是技术层面的解释,比如“请求竞态:先发出去的后返回,覆盖了最新结果”。分开写能避免你以后只记得现象、想不起原因。
4.2 几个高频疑难问题排查实录
我在过去一年的项目笔记里整理过三类最高频的问题,几乎每个 Vue 开发者都会遇到。
第一个问题是列表更新了,DOM 没有同步。排查步骤是:先在vue-devtools里看组件状态是否真的更新了,如果状态没更新,去看数据源;如果状态更新了但 DOM 没变,重点检查key。用数组index作为key时,在列表头部插入或删除元素,Vue 的 diff 会错误地复用 DOM,导致某些子组件的内部状态残留。修复方式是使用业务唯一 ID 作为 key。
第二个问题是组件卸载后还在执行定时器导致的警告。根因是setInterval或请求回调没有清理。修复方式是在onUnmounted里clearInterval,并设置“已卸载”标记,在异步回调里先判断标记再更新状态。
第三个问题是“毛刺”一样的响应式丢失。常见于在setup中直接解构reactive对象,然后把基础类型的变量传给模板使用。解构之后变量已经脱离了 Proxy 的访问路径,相当于复制了一份普通值。修复方式是使用toRefs或者在模板中通过状态对象访问属性。
每一条 Bug 记录我都会在最后加上“关联知识点”,把这三种问题分别关联到 diff 算法、生命周期清理、响应式原理。这样项目笔记能反向帮助知识笔记查漏补缺。
4.3 从日志到复盘的小习惯
项目笔记只记录日志还不够,我每个迭代结束会抽一个下午做一次复盘。复盘不是流水账,而是围绕三个问题展开:
- 这个迭代最浪费时间的 Bug 是什么?
- 它反映的是知识不足、流程缺失,还是工具不顺手?
- 下一次做什么可以避免同类问题?
比如某次我做一个管理后台,发现大量时间花在“改完接口字段就报错”上。复盘之后发现,是因为团队没有把接口响应的字段类型集中管理。于是我在项目笔记里记了一条改进项:给所有接口响应定义类型,而不是在组件里到处猜测字段。这类从日志里抽象出来的结论,比记一百条“今天改了什么”更有价值。
5. 让 Vue 笔记能长期用:存储、检索与发布
5.1 笔记管理的本地方案
对我来说,工具不是越复杂越好,稳定、可检索、可版本回滚是关键。我用的方案是:
- 写作:本地 Markdown 文件。
- 版本管理:Git 仓库,按周提交一次,短期分支可以用于大改版。
- 检索:编辑器全文搜索 + 文件名数字前缀。
- 检索增强:每份文件顶部维护 tags 字段,用
#组件#响应式这类标签做主题串联。
在笔记仓库根目录我会放一个 README,把最新导航写清楚。每次新建文件都带数字前缀,保证排序不再依赖修改时间。一个常用的片段库也很有用,比如把“防抖函数”“深拷贝”“日期格式化”这类工具代码放在90-snippets,需要时直接通过全文搜索找到。
5.2 安全检查与清理流程
几个月后笔记数量变多,检索会开始变慢。我会做两类清理。
物理清理:删掉已经不再适用的旧示例代码、过期的项目日志。方法是一年内没有打开过、且主题已经被其他文件覆盖的笔记,移动到一个archive/目录,不立即删除,防止误删。
逻辑清理:把分散在多个文件里重复记录的知识点合并到一份源文件,然后在其他文件中留一个“见 XX 文件”的链接。合并之后,笔记系统会自动形成“主页 - 主题页 - 细节页”的层级。这个结构比单纯的文件夹嵌套更容易保持一致性。
5.3 从私人笔记到团队知识库的升级
私人笔记和团队知识库的写法完全不同,但没有必要另起炉灶。我的做法是选择一两个核心主题,比如“组件通信与状态管理最佳实践”,先用两周时间把个人笔记里的相关内容整理成团队文档:
- 去掉个人口吻和临时性标记录,只保留结论和依据。
- 补上前置知识说明,默认读者是有一定基础但没踩过坑的成员。
- 每条结论都配最小可运行示例,而不是大段代码。
- 增加“常见问题”板块,把项目日志里三个高频 Bug 按照“症状 — 排查路径 — 修复方式”的格式写进去。
整理过程中会发现个人笔记缺少上下文,这时候回到源码和官方文档补充,不该凭记忆口胡。团队文档沉淀到一定量之后,还可以把其中的通用部分优化成博客文章,或者做成内部分享稿。这一步让笔记从个人资产变成组织资产,价值翻倍。
6. 我对 Vue 笔记的几条实操心得
关于“怎么坚持记录”这件事,我的经验是不要给自己设定过高的目标。每天记五条、每条都长篇大论,根本坚持不了一周。我现在的习惯是“最小记录法”:遇到问题先写一句话现象,修完再补根因和解决。哪怕只写三五行,也比不写强。不要等到周末再来补,因为到周末你早就忘了当时的上下文。
关于“查不到笔记”的问题,我的对策是维护一个小词表,所有笔记标题统一写成“动词 + 名词”的形式。比如“解决 index key 导致状态残留”,而不是“列表 bug 2”。统一命名风格之后,全文搜索的命中率会高很多。搜“组件通信”会得到一页,搜“列表”可能命中多个文件,很不精准。
关于“笔记和博客”的关系:笔记是素材库,不是成品。很多人一上来就想写技术博客,结果连思路都理不清楚。相反,如果先把笔记写成有结构的小卡片,等到卡片数量够了,再做一次串联,文章自然就出来了。我发布的很多内容,初稿其实都是这份笔记体系里某几个主题的组合。
最后,如果你还没有开始维护自己的 Vue 笔记,我建议从今晚开始做一件事:新建一个文件,只写“机制链路”一行,然后把你最近一次遇到的前端问题挂到对应节点上。先让笔记动起来,后面的分类、清理、发布,都会慢慢长出来。笔记的价值不在于保存了多少字,而在于当你需要解决下一个问题时,能否在第一分钟就找到答案。