1.响应式
通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者(watcher),触发相应的监听回调来更新DOM;
无法监听 对象新增的属性, 数组下标,长度修改 也无法监听
需要通过Vue.set / this.$set() 进行监听
2.解决数组响应式问题
Vue.set(); 其实就是内部就是调用来splice方法
3.Vue 渲染过程
- 模板编译生成 render 函数:
模板解析: 解析成AST抽象语法树
优化AST: 遍历AST,标记静态节点(如纯文本、无动态绑定的元素),后续 diff 时跳过,提升性能
生成渲染函数: 把优化后的 AST 转化为render函数
- 执行 render 生成虚拟 DOM
- VNode → 真实 DOM: diff 双端比较,生成真实DOM
4.Diff算法
同层比较的 Virtual DOM 算法,通过 key + 双端指针
定义了4个指针旧头、旧尾、新头、新尾; 从两端向中间逼近;
5.生命周期
beforeCreate:执行一些初始化任务,此时获取不到 props 或者 data 中的数据
created:组件初始化完毕,可以访问各种数据,获取接口数据等
beforeMount:此时开始创建 VDOM
mounted:dom已创建渲染,可用于获取访问数据和dom元素;访问子组件等。
beforeUpdate:此时view层还未更新,可用于获取更新前各种状态
updated:完成view层的更新,更新后,所有状态已是最新
beforeDestroy:实例被销毁前调用,可用于一些定时器或订阅的取消
destroyed:销毁一个实例。可清理它与其它实例的连接,解绑它的全部指令及事件监听器
keep-alive 独有的生命周期,分别为 activated 和 deactivated。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 actived 钩子函数。
6.Computed 和 Watch
computed 用来“算值”,watch 用来“做事”。
computed 关注结果,watch 关注过程和副作用。
核心区别:computed是 “带缓存的纯数据计算”,watch是 “无缓存的副作用执行”;
computed 使用场景:需基于已有数据生成新值、希望缓存结果、无副作用操作的场景(如数据拼接、格式化、筛选);
watch 使用场景:数据变化后需执行副作用操作的场景(如请求接口、操作 DOM / 本地存储、监听复杂数据类型变化)。
7.keep-alive
用来缓存组件实例,避免组件在切换时被销毁和重新创建
解决组件频繁切换时重复创建、状态丢失和性能浪费的问题。
使用 keep-alive 后,组件不会被销毁,而是在激活和缓存之间切换,通过 activated 和 deactivated 控制逻辑。
可以通过include / exclude 来判断缓存控制,哪些要缓存哪些不要缓存
实现原理: 拦截子组件的渲染流程,将组件的 VNode(虚拟节点)和实例缓存到内存中,当组件再次被渲染时,直接复用缓存的实例和 VNode,而非重新创建,同时重写组件的生命周期触发逻辑
简单来说,keep-alive 并没有改变组件的本质,只是「接管」了它的创建、渲染和销毁过程,把「销毁组件」替换成了「缓存组件」,把「重新创建组件」替换成了「复用缓存组件」
include : 只有名称匹配的组件会被缓存 exclude: 名称匹配的组件都不会被缓存
8.nextTick
DOM更新后,渲染前执行; 等 DOM 更新完之后,再执行nextTick的回调
基于JavaScript 事件循环机制, 把回调丢到“DOM 更新完成后”的微任务里
Vue 更新 DOM 的操作是异步执行的,并非数据一变 DOM 就立刻更新。nextTick的核心作用是:将回调函数延迟到下一个 DOM 更新周期(异步更新队列)执行,确保你在回调中能获取到更新后的 DOM。
Vue 的更新机制是异步批量更新机制。
当响应式数据发生变化时,不会立即更新 DOM,而是通知依赖并将相关 watcher 放入更新队列中进行去重和合并。
在当前事件循环结束后,统一执行更新队列,重新渲染组件生成新的虚拟 DOM,通过 diff 算法对比新旧节点并最小化 patch 到真实 DOM。
DOM 更新完成后,再执行 nextTick 回调。
9.Vue 的异步更新策略原理
把多次数据变更合并到一次 DOM 更新中,通过任务队列批量刷新,提升性能
数据变化时,不立即更新 DOM,而是把更新操作 “攒” 起来,等当前同步代码执行完,再一次性批量更新 DOM
当响应式数据发生变化时,Vue 并不会立即更新 DOM,而是将更新任务放入队列中进行去重和合并。
等当前同步任务执行完成后,Vue 会统一执行这些更新任务,通过 diff 算法最小化 DOM 操作,最后更新真实 DOM,并在更新完成后执行 nextTick 回调。
数据修改 → 触发响应式通知 → 加入更新队列(去重)→ 微任务调度 → 批量执行更新 → 生成新 VDOM → Diff+Patch 更新 DOM → 执行用户 nextTick
10.组件通信:
父组件 → 子组件: props
子组件 → 父组件: $emit 触发自定义事件
兄弟组件通信: 1. 父组件中转; 2. EventBus
跨层级 (祖孙组件): Provide & Inject; 父组件通过 provide 提供数据,所有子组件(无论层级)都能通过 inject 接收
ref访问子组件实例: 父组件可通过 ref 获取子组件的 DOM / 方法
全局共享: Pinia(Vue 3)/ Vuex(Vue 2)
11.Vue 组件的 data 为什么必须是函数
Vue 组件的 data 必须是函数,是因为组件可以被复用。
如果 data 是对象,多个组件实例会共享同一份数据,导致状态污染。
使用函数返回对象,可以保证每次组件实例化时都生成一份独立的数据副本
13. Vue 的 computed 的实现原理
核心特点是缓存 + 依赖收集。computed 在 Vue 中是通过创建一个带 lazy 属性的 Watcher 实现的。
初始化时收集计算属性依赖的响应式数据,依赖变化时仅标记缓存失效,不立即计算;
只有当计算属性被使用(比如页面渲染、其他逻辑调用)时,才会检查缓存状态,按需重新计算并更新缓存,这也是它比 methods 更高效的核心原因。