1. 内容整体设计与思路拆解
1.1 这份“vue笔记”到底在记什么
先说结论:所谓“vue笔记”,不是把官方文档抄一遍,也不是把某本书的目录誊到笔记软件里。我自己的这份vue笔记,核心目标只有一个——当同事问我“Vue里某个功能怎么做”的时候,我能在十秒内翻到对应页面,并且看到当初踩坑的原始记录和最终的解决方案。它是一份带着体温的“工作手账”,而不是教程的搬运工。
我会在笔记里记录三类东西:第一类是核心知识点,拆成响应式原理、组件通信、生命周期这些模块,每个模块下只写“需要背下来的结论”和“为什么是这个结论”这两层,不写长篇大论的原理引用。第二类是实战中遇到的坑,比如“为什么props里传了对象,子组件修改后父组件也变了”“为什么路由切换后组件数据没刷新”这种,每条坑都配了复现代码和当时的思考过程。第三类是项目脚手架和工具链的配置备忘,比如Vite别名怎么配、ESLint规则怎么调、环境变量怎么管理——这些东西一次配好之后真的记不住,不写下来下次还得翻半天博客。
1.2 选型依据:Vue2还是Vue3,笔记要不要二选一
如果你现在才开始学Vue,我建议直接学Vue3 + 组合式API,因为Vue3已经是绝对主力,Vue2已经进入维护尾声。但我的笔记里两个版本都有,原因是接手的老项目大概率还有Vue2代码,你至少要能看懂、能改、能迁移。我笔记的组织方式是在每个主题下分两个小节,先写Vue3的现行做法,再写Vue2时代的写法用于对照。
比如“组件通信”这个主题,Vue3中用defineProps和defineEmits,Vue2中用props选项和$emit;Vue3中用provide/inject,Vue2中也有,但用法细节略有差异。把两套并列记录,不是为了凑字数,而是当你从老项目往新项目迁移时,能一眼看出差异点:哪里语法变了,哪里行为没变,从而快速评估改造工作量。
组合式API与选项式API的选择同理。我的笔记以组合式API为主,因为逻辑复用确实更优雅,但也在笔记里留了一页“选项式API速查对照表”,对应关系列清楚,比如data对应ref/reactive,computed对应computed,mounted对应onMounted。这样遇到老代码,扫一眼就能翻译成新写法。
1.3 笔记组织架构:按知识域分文件夹,而不是按时间线堆
我的vue笔记使用本地Markdown文件管理,按知识域拆成几个大类,每个大类下面再细分。这样做的原因是:笔记是用来查的,不是用来读的,所以索引和检索是第一位。
当前我保持的目录结构大概是这样的:
- 01-核心基础:包含模板语法、指令、计算属性、侦听器、样式绑定。
- 02-组件化:包含组件通信、插槽、动态组件、异步组件、组件命名规范。
- 03-响应式原理:包含Vue2的Object.defineProperty、Vue3的Proxy、依赖收集与触发、常见响应式丢失场景。
- 04-路由与状态管理:包含Vue Router 4基础与进阶、Pinia与Vuex对比、持久化方案。
- 05-工程化与工具链:包含Vite配置、ESLint/Prettier、环境变量、打包优化、组件库接入。
- 06-实战问题归档:按“问题描述-复现代码-排查过程-最终解法”的模板记录。
这里我要特别强调一个观点:笔记的根目录建议用数字前缀强制排序,不要用文件夹名称的字母序。因为我发现字母序会把“实战问题归档”排在最前面,而它本该在最后。用数字前缀之后,新笔记会按主题自动落到对应的数字区间,不会打乱整体结构。这个习惯我从整理第一份笔记时就养成了,后来遇到再复杂的技术栈,都沿用这套方法。
2. 核心细节解析与实操要点
2.1 模板语法与指令:不只是v-if和v-for
很多人学Vue时觉得模板语法简单,不就是插值表达式加几个指令吗?但实际写起来,有几个细节非常容易出问题,我的笔记里专门给它们开了“高危区”。
第一个是v-for的:key。官方文档强调key要唯一且稳定,但到底怎么选key,很多人在实战中会犯迷糊。我的经验是:如果列表数据来自后端,优先用后端的业务主键id;如果只是前端临时生成的列表,且没有唯一标识,可以用index,但你要明白用index做key会导致什么后果——当列表顺序发生变化(比如排序、筛选、插入)时,Vue的虚拟DOM diff会错乱,因为index是跟着数组位置走的,复用的组件实例可能拿到旧的状态。所以在笔记里我记录了一条规则:能用业务标识就不用index,实在没有业务标识时宁可自己生成一个临时唯一key。
第二个是v-model的修饰符。.sync修饰符虽然官方文档说它是事件绑定的语法糖,但在Vue3中已经被移除了,统一用v-model:参数名来实现双向绑定。我的笔记里特别记了Vue3中多个v-model的写法,因为这在封装表单组件时非常常用。
第三个是动态绑定中容易忽略的布尔运算问题。:disabled="someFlag"这种写法很常见,但如果你忘写了冒号,写成disabled="someFlag",你会发现组件永远处于禁用状态,因为字符串"someFlag"本身是真值。这种低级错误在代码走查时特别容易漏掉,但运行时表现又很明显,我在笔记里把它列为新手的头号排查点。
2.2 响应式原理:从Object.defineProperty到Proxy
响应式原理是Vue的核心,但我的笔记里只记了四个层级:它是什么、它是怎么实现的、为什么会有坑、怎么避开坑。不深入源码细节,因为绝大多数业务开发用不到源码那一层,但你必须理解“依赖收集”和“触发更新”这个模型,否则遇到数据不更新的问题会完全没头绪。
Vue2的响应式用的是Object.defineProperty,它只能拦截对象属性的读写,所以数组的变化检测必须额外劫持push、pop等七个方法。这个机制的直接后果就是:给对象新增属性、删除属性、通过arr[index] = value修改数组元素,都不会触发视图更新。这些坑在Vue2时代非常经典,几乎每个开发者都踩过。我的笔记里记录了标准的解决方案——用Vue.set/this.$set,但更重要的是记录了为什么这样能解决:因为$set本质上是手动触发了依赖的更新。
Vue3改用Proxy,可以拦截整个对象的读写,所以新增属性、删除属性都没有问题,数组索引修改也能被拦截。但这不代表Vue3没有响应式坑。最大的坑是响应式数据解构后丢失响应性,比如从reactive对象里取出一个属性赋给本地变量,修改这个本地变量不会更新视图。我的笔记里明确写了两条经验:第一,尽量用ref声明基础类型;第二,如果确实需要解构reactive对象,使用toRefs把每个属性转成独立响应式引用再解构。
响应式损失还有一种隐蔽的场景,就是在setTimeout或异步回调中赋值。这个问题往往跟响应式原理本身无关,而是因为你在实例销毁之后还做了赋值操作,或者赋值给了一个没有被响应式代理的普通变量。笔记里的建议是:遇到视图不更新,先检查数据源是不是响应式对象本身,再检查赋值时机,最后看有没有在异步里拿到了一份“非响应式副本”。
2.3 生命周期与执行时机:挂载、更新、销毁,顺序决定一切
生命周期是初学者最容易背了又忘的内容,原因是他们只记钩子名称,不记钩子之间的约束关系。我会在笔记里画了一张时序表,但这里没有图表,我用文字描述一遍关键顺序:setup最先执行,接着是onBeforeMount,然后模板编译并挂载真实DOM,onMounted触发,之后当响应式数据变化时,onBeforeUpdate和onUpdated成对出现,最后组件销毁时onBeforeUnmount先执行,onUnmounted再执行。
笔记里我专门标注了三个容易出错的行为:
- 第一,
onMounted里获取DOM一定没问题,但如果你在setup里直接写document.getElementById,此时模板还没挂载,会拿到null。所以不要在setup同步代码里操作DOM。 - 第二,
onUpdated不推荐用来监听数据变化,因为任何响应式数据的变化都会触发它,你需要在回调里做前后对比才能判断“是谁变了”。更合理的方式是把数据变化逻辑放在watch或computed中。 - 第三,
onBeforeUnmount是清理定时器、取消事件监听的最后时机。我在多个项目里都遇到过一个bug:组件销毁后定时器还在跑,因为开发者只记得在mounted里setInterval,但忘了在销毁前clearInterval。Vue虽然会在垃圾回收时处理失联的定时器,但你挂载到全局事件总线上的监听器不会自动解除,最终导致内存泄漏和重复触发。
关于生命周期,我还记了一个最佳实践:需要触发异步请求时,放在onMounted里而不是setup里。虽然两者都能发起请求,但setup执行时组件还没有“完成挂载”,某些依赖DOM初始化才能取到的参数可能是空的。虽然可以用nextTick解决,但不必要的复杂度能免则免。
2.4 组件通信:从props到跨层级状态
组件通信是vue笔记里篇幅最大的部分,因为它是组件化开发中高频碰到的主题。我的笔记按通信双方的层级关系整理了六种方式:
- 父传子:
props。注意是单向数据流,子组件不能修改props。 - 子传父:自定义事件
emit。Vue3中用defineEmits声明,Vue2中用$emit。 - 兄弟组件:通过共同的父组件中转,父组件持有状态,通过props下发,通过emit回传。
- 跨层级祖先与后代:
provide/inject。适合像主题切换、用户信息这种全局但不需要响应式工具链的场景。 - 全局共享:Pinia(Vuex)。适合复杂跨页面状态。
- 组件实例引用:
ref和$refs。适合父组件直接调用子组件暴露的方法。
这里我想重点说说provide/inject,因为它看起来很爽,但很容易被滥用。我的笔记里写了一条提醒:provide的数据如果是普通对象,它不会自动响应式,后代组件拿到的是第一次注入时的快照。要让注入值具备响应性,你需要在provide时用ref或reactive包装。还有一个经验是:尽量不要用provide/inject代替Pinia,因为它没有调试工具、没有时间旅行、也没有明确的变更记录,一旦项目复杂起来,你根本不知道某个值是从哪个祖先组件传出来的。
插槽是另一块容易混淆的知识点。默认插槽、具名插槽、作用域插槽三者的区别,我用一句话总结:默认插槽是放一个坑,具名插槽是多个标记好的坑,作用域插槽是父组件给坑位的同时,子组件还能往坑里递数据。在封装通用列表、弹窗、表格这种组件时,作用域插槽几乎是必需品,因为它把“渲染什么”的控制权交还给了父组件,同时又能拿到子组件内部的状态。
3. 实操过程与核心环节实现
3.1 从零初始化一个基于Vue3的项目:Vite是默认选择
我的笔记里记录的第一条实操是“怎么起一个新项目”。现在团队新项目基本都用Vite,而不是Vue CLI。核心原因不是Vite快,而是Vite的开发服务器基于原生ESM,冷启动和热更新都远快于Webpack打包的开发服务器。加上Vite官方就是Vue团队在维护,和Vue3的配合是天然完整的。
初始化命令如下:
npm create vite@latest my-vue-app -- --template vue注意这里用了--传递模板参数,如果你用npm create vue@latest则是走官方配套脚手架,它还会让你选择是否安装Router、Pinia、ESLint等插件。我个人更喜欢后者,因为它能直接生成带路由和状态管理的标准目录。实际执行时它会询问几个问题,全部选Yes就行。
项目初始化之后,第一件事是配置路径别名,因为模块引用会经常用到。在vite.config.js中增加:
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': path.resolve(__dirname, 'src') } } })同时需要在jsconfig.json或tsconfig.json中补充路径映射,编辑器才能识别@/开头导入。这个问题我踩过,配置完别名后代码能跑,但编辑器报红色波浪线,就是因为没同步配置paths字段。笔记里特别记了这一点,提醒自己不要漏。
3.2 组件封装实战:做一个可配置的弹窗组件
组件封装是vue笔记里最重要的实战案例,因为几乎每个项目都会遇到。我拿一个弹窗组件来示范,因为弹窗涉及的状态逻辑点比较全:可见性控制、外部点击关闭、插槽内容渲染、事件回调。
先看组件骨架。在Vue3组合式API下,我会用v-model来控制弹窗的可见性:
<script setup> defineProps({ title: { type: String, default: '' }, width: { type: String, default: '480px' } }) const visible = defineModel('visible', { type: Boolean }) function handleClose() { visible.value = false emit('close') } </script> <template> <Teleport to="body"> <div v-if="visible" class="modal-mask" @click.self="handleClose"> <div class="modal-panel" :style="{ width }"> <header class="modal-header"> <slot name="header">{{ title }}</slot> </header> <main class="modal-body"> <slot></slot> </main> <footer class="modal-footer"> <slot name="footer"></slot> </footer> </div> </div> </Teleport> </template>这个组件里用了三个我笔记里重点标记的技术点:
第一个是Teleport。它的作用是把弹窗的DOM挂载到body下,避免被父组件的overflow: hidden或transform属性影响。这个坑特别经典——如果你直接在组件内部渲染弹窗,父容器设置了overflow: hidden,弹窗就会被裁剪掉,必须用Teleport解决。
第二个是defineModel。这是Vue3.4引入的宏,专门用来实现v-model双向绑定,省去了手动defineProps+defineEmits再分别同步的繁琐写法。它本质上是语法糖,但你用起来会少写很多样板代码。如果是Vue3.4之前的版本,你需要用props和emit分开写,逻辑会更绕。
第三个是事件修饰符@click.self。用它来监听遮罩层自身的点击,这样点击遮罩内部时不会误触发关闭。很多初写弹窗的人会把@click直接写在遮罩层上,结果发现点击弹窗内容也会把弹窗关掉,原因就是事件冒泡触发了遮罩层的点击。这里用.self修饰符是对事件冒泡机制的一次熟练应用。
父组件使用这个弹窗时也很简单:
<template> <button @click="open = true">打开弹窗</button> <Modal v-model="open" title="提示" @close="onClose"> <p>这里是弹窗内容</p> </Modal> </template> <script setup> import { ref } from 'vue' import Modal from './components/Modal.vue' const open = ref(false) function onClose() { console.log('弹窗已关闭') } </script>一个值得注意的细节:当使用v-model="open"时,open必须是ref变量,如果你写成一个普通常量,子组件修改visible时父组件的值不会变化,弹窗永远打不开。这个问题在代码审查时很容易被忽略,但表现出来就是一个诡异的现象:子组件状态变了,父组件感知不到。
3.3 路由配置与懒加载:按需加载不是一个可选项
在SPA应用中,路由懒加载几乎是必配项。如果不做懒加载,首屏会把所有页面的JS都下载下来,包体积大不说,首屏白屏时间也会显著增加。我的笔记里记录了Vue Router 4下的标准写法:
import { createRouter, createWebHistory } from 'vue-router' const routes = [ { path: '/', component: () => import('@/views/Home.vue') }, { path: '/user/:id', component: () => import('@/views/UserDetail.vue'), children: [ { path: 'profile', component: () => import('@/views/UserProfile.vue') } ] } ] const router = createRouter({ history: createWebHistory(), routes }) export default router这里用了动态import()语法,Webpack或Vite在打包时会自动把每个import()对应的文件拆成一个独立的chunk。路由切换时,只有访问到对应路径,浏览器才会下载这个chunk。我记了一条经验:不要为了懒加载而滥用import(),如果一个路由组件只被另一个路由组件引用,且两者几乎总是一起出现,那把它们合并到同一个chunk反而能减少HTTP请求。Vite支持通过注释指定chunk名称,比如:
component: () => import(/* webpackChunkName: "user" */ '@/views/UserDetail.vue')不过在纯Vite项目中,注释名要写成/* @vite-ignore */或使用import.meta.glob动态批量导入,实际项目里我更常用的是不写注释,让Vite自动按内容hash拆包,配合manualChunks做全局拆分。这些细节笔记里都记了,因为每次配置都要翻官网不如看自己笔记来得快。
3.4 状态管理:Pinia的实战配置
状态管理这块,我的笔记现在的结论是:新项目直接用Pinia,别用Vuex。不是Vuex不好,而是Pinia更符合组合式API的心智模型,TypeScript支持也更好,而且去掉了Mutations的概念,直接在Actions里改状态,减少了一层样板代码。
创建一个简单的store:
import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => ({ token: '', userInfo: null }), actions: { setLogin(payload) { this.token = payload.token this.userInfo = payload.userInfo // 同时可以写入本地缓存 localStorage.setItem('token', payload.token) }, logout() { this.token = '' this.userInfo = null localStorage.removeItem('token') } }, getters: { isLoggedIn: (state) => !!state.token } })有两点经验补充:
第一,Pinia的state必须是一个箭头函数返回的新对象,这样才能保证每个使用这个store的组件拿到的是同一个实例,同时也避免服务端渲染时的数据污染。如果你写成state: { token: '' }这种普通对象,在SSR场景下就会出问题,因为多个请求会共享一份状态。
第二,别把异步请求逻辑全压在组件里。更好的模式是在store的action中发起请求,成功后更新state,组件只负责调用action并读取state。这样当两个页面都需要同一份用户数据时,避免了重复请求。我的笔记里专门记录了这个“请求去重”的思路:在action里加一层缓存,如果userInfo已经存在,直接返回,不重复发请求。
3.5 调试技巧:Vue Devtools之外的排查手段
Vue Devtools是调试Vue应用的标配,但我笔记里还会记录一些命令行和代码层面的调试技巧,因为有时Devtools不一定能定位问题。
第一个技巧是利用vm.$options查看组件配置。在Vue2中,你在控制台拿到一个组件实例后,输入$vm.$data可以查看数据,输入$vm.$props可以查看props。Vue3中类似的命令是proxy.$或通过getCurrentInstance()访问。
第二个技巧是使用Vue的customRef来做防抖调试。customRef允许你自定义跟踪和触发响应性的时机,可以在写入时加一个延时。调试一个输入框引发的频繁请求时,用customRef做防抖是比监听器更优雅的方案。
第三个技巧是注意浏览器的网络面板和性能面板。很多Vue问题表面上是“视图不更新”,实际上是接口没返回数据,或者返回了错误格式。我遇到过最蠢的一次问题:接口返回的list字段是字符串"null",不是数组,导致页面渲染时一直报错。这种问题用Devtools看响应式状态看不出来,必须看网络响应才能发现。所以我的笔记里有一条铁律:遇到视图不更新,先看网络,再看响应式,最后看渲染模板。
4. 常见问题与排查技巧实录
4.1 经典问题速查表
把笔记里高频问题整理成表格,放在显眼位置,给自己当速查手册。下面这张是我自己的vue笔记里最常用的几行:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 修改数组/对象,视图不变 | Vue2响应式限制 / Vue3解构丢失响应性 | 用$set或toRefs,避免直接解构 |
| 异步回调中赋值,视图不变 | 赋值对象不是响应式代理 | 确认数据源是ref/reactive包装后的引用 |
| 列表渲染后DOM错乱 | :key不稳定或用index | 换用业务唯一ID |
| 路由切换后组件数据不刷新 | 复用了同一个组件实例,created未再次触发 | 在watch中监听路由参数,重新拉取数据 |
| 页面初始化时获取不到DOM | 在setup里同步操作DOM | 放到onMounted |
| 组件销毁后定时器还在跑 | 忘记清理定时器或事件监听 | 在onBeforeUnmount中清除 |
provide/inject传值后,子组件不更新 | 注入值是普通对象,不具备响应式 | 用ref或reactive包装后再provide |
这张表其实是从我近一年的实战问题归档里总结出来的。我每遇到一个坑,就按“现象-原因-方案”填进表格,每过几个星期就会扫一遍,把重复出现的问题标记为“高危”,然后去编辑对应的原理笔记,把根因写得更详细。这个“问题驱动笔记更新”的循环,是我觉得保持笔记长期有用的关键。
4.2 排查思路:三步定位一个“视图不更新”
视图不更新是最容易让人抓狂的问题,我单独把排查路径写出来:
第一步,先确认你的赋值语句执行了没有。在赋值语句后面加一行console.log,打印赋值后的目标数据。如果打印出来是预期值,说明数据源没问题,问题在模板或渲染层;如果打印出来不是预期值,说明你赋值给了错误的对象,或者赋值时机在异步回调中被覆盖了。
第二步,确认数据源是否具备响应性。怎么判断?在模板里临时渲染一个{{ data }},如果模板中显示的正是你赋值的值,但页面没有更新,那几乎可以肯定你持有的是一个非响应式的副本。最典型的就是从reactive对象里解构属性,解构后得到的是一个普通字符串或对象,对它的修改不会触发任何更新。
第三步,检查组件实例是否是同一个。当你用v-if控制组件的挂载/卸载时,要注意每次v-if为真时组件都是重新创建的。如果你依赖了缓存或外部事件来初始化数据,这些初始化逻辑只在setup里执行一次,第二次挂载时就会拿到旧状态。遇到这种情况,要么在onUnmounted里重置状态,要么把状态提升到父组件或store中。
4.3 路由传参的细节与坑
路由传参也是高频踩坑点。我的笔记里记录了三种传参方式及使用建议:
- 路径参数:
/user/:id,适合唯一标识,刷新后参数还在URL里,可分享。 - 查询参数:
/user?id=1,适合可选参数,通过route.query访问。 - 状态传参:通过
history.state或Pinia存储,适合敏感或复杂数据,但刷新后丢失。
一个比较容易踩的坑是:query参数变化时,同一个路由组件会复用,setup不会重新执行,如果你在setup里根据route.query.id请求数据,第一次进入没问题,但在同一页面内通过router.push({ query: { id: 2 } })切换时,数据不会更新。解决方案是使用watch监听route.query.id,在回调中重新请求。同理,路径参数变化也需要这样处理。
我笔记里还记录了一条“传参之前做校验”的经验。有次排查一个页面报错,原因是路由跳转时,参数在传之前就被截断了,传过去的id是undefined。最后发现是router.push中对象写漏了一个字段。所以无论哪条路径传参,在接收页面都建议用Number(route.params.id)或String(route.query.id)做一次显式转换,不要直接用原始值参与计算,避免类型不一致引发的潜在问题。
4.4 性能优化:长列表和大对象的使用误区
性能优化这块,我的笔记记录了三个真实项目里踩过的坑。
第一个是长列表渲染。在Vue2中,如果要渲染几千行表格,需要做分页或虚拟滚动,但Vue3的响应式开销已经小了很多。不过如果你把一个大对象放进了reactive,即使只渲染它的一部分属性,Vue也会在对象任意属性变化时重新计算依赖该对象的组件。所以合理的方式是拆分粒度:用ref保存基本类型,用computed筛选出真正需要渲染的部分。
第二个是v-if与v-show的选择。很多教程说“频繁切换用v-show,不频繁用v-if”,这个结论基本正确,但原因在于:v-show只是切换display属性,组件保持挂载状态,因此初始开销大但切换开销小;v-if则是真正的创建和销毁,初始为假时不渲染,切换时有销毁和创建成本。在我的实际经验中,如果切换频率超过每秒一次,强烈建议用v-show,否则你可能会在切换动画里看到明显的卡顿。
第三个是computed和watch的正确取舍。computed是声明式的,适合根据已有响应式数据派生新数据,它有缓存,只有依赖变了才会重新计算;watch是命令式的,适合在数据变化时执行副作用操作,比如请求、日志、DOM操作。我见过很多人在不需要副作用的地方用watch去赋值给另一个ref,这等于自己实现了一个computed,还要手动处理依赖和时序。笔记里我的建议是:能写computed就不要用watch,因为computed的缓存特性和自动依赖追踪能去掉大量状态同步代码。
4.5 代码风格与团队协作:让笔记成为团队公约
最后提一个很实际的经验:vue笔记不只是我自己的私人手册,我还会把其中一部分整理成团队内的最佳实践文档,尤其是命名规范、组件目录结构、状态管理使用原则这三类。举个例子,我笔记里明确写了组件文件的命名约定:组件文件名用PascalCase(大驼峰),比如UserCard.vue;普通工具文件用camelCase,比如useUserStore.js。这个约定不是Vue官方的强制要求,但它能让你在大型项目中快速分辨哪个文件是组件、哪个文件是普通模块。
此外,我还会在笔记里沉淀“代码评审时的Vue检查清单”,包括:props是否声明了类型和默认值;事件名是否使用kebab-case;v-for是否写了key;组件是否超过两层的嵌套props透传;有没有不必要的watch;定时器和事件监听是否在销毁前清理。每次MR提交前,我会自己先过一遍这份清单,至少能挡掉一半的返工。
技术栈可以变,团队可以换,但一套好的笔记系统能让你的经验持续累积。我在实际使用中最大的体会是:笔记不在于多,而在于“可检索、可验证、可更新”。每次遇到新问题,我第一反应不是去查官方文档,而是先翻自己的笔记,看有没有相似的记录;如果没有,解决完就把完整过程补进去。这样坚持一年攒下来的东西,比任何现成的教程都更能贴合你实际接触的项目。
5. 结尾
我的vue笔记现在已经积累了几百篇,包含知识点、坑位、代码片段和项目配置备忘。回头看,最有价值的并不是那些从文档里抄来的规范定义,而是每一条“我在什么场景下遇到了什么错误,最后怎么解决”的现场记录。
给刚开始写vue笔记的朋友一个建议:从今天起,给每一条笔记都加上“版本”和“场景”两个字段。版本指你当时用的是Vue2还是Vue3,场景指你是在哪个类型的功能开发中遇到的问题。这两个字段能让你在几个月后翻旧笔记时快速判断:这条经验现在还适用吗?如果有新的Vue3版本或新工具链出现,会不会推翻当时的结论?
最后再分享一个我自己的小习惯:每周末花十分钟,把本周新增的笔记条目扫一遍,把重复出现的错误提炼成更通用的原则,顺便删除已经过时的内容。这个过程就像整理工作台,桌面干净了,找东西自然就快。Vue这块技术栈还在快速迭代,但只要你持续用这种“记录-复盘-更新”的方式维护自己的笔记,不管框架换成什么,你都能保持住属于自己的技术判断力。