vue底成实现
Vue 底层实现原理
Vue 的底层实现主要基于响应式系统、虚拟 DOM 和模板编译。以下是核心机制的详细说明:
响应式系统
Vue 使用 Object.defineProperty(Vue 2)或 Proxy(Vue 3)实现数据劫持。当数据被访问或修改时,依赖收集和派发更新机制会自动触发视图重新渲染。
-
依赖收集:
通过Dep类和Watcher类管理依赖关系。每个响应式属性有一个Dep实例,用于存储依赖它的Watcher(即视图更新函数)。// 简化版 Dep 类 class Dep { constructor() { this.subscribers = []; } depend() { if (target && !this.subscribers.includes(target)) { this.subscribers.push(target); } } notify() { this.subscribers.forEach(sub => sub()); } } -
数据劫持:
Vue 2 通过递归遍历对象的属性,将其转换为getter/setter:function defineReactive(obj, key, val) { const dep = new Dep(); Object.defineProperty(obj, key, { get() { dep.depend(); // 收集依赖 return val; }, set(newVal) { if (newVal === val) return; val = newVal; dep.notify(); // 触发更新 } }); }
虚拟 DOM 与 Diff 算法
Vue 通过虚拟 DOM 减少直接操作真实 DOM 的开销。当数据变化时,生成新的虚拟 DOM 树,与旧树通过 Diff 算法比对,计算出最小更新路径。
-
虚拟 DOM 结构:
虚拟节点(VNode)是一个普通对象,描述 DOM 结构:{ tag: 'div', props: { class: 'container' }, children: [ { tag: 'span', text: 'Hello' } ] } -
Diff 算法优化:
Vue 采用同层比较策略,通过双端对比(头尾指针)高效更新子节点。核心逻辑包括:- 同级节点比较,跳过跨层比对。
- 通过
key标识复用相同节点。
模板编译
Vue 的模板会被编译为渲染函数(render 函数),这个过程分为三个阶段:
-
解析(Parse):
将模板字符串转换为抽象语法树(AST),例如:<div>{{ message }}</div>转换为 AST:
{ type: 1, tag: 'div', children: [{ type: 2, expression: '_s(message)', text: '{{ message }}' }] } -
优化(Optimize):
标记静态节点(如纯文本),避免 Diff 时重复处理。 -
生成(Generate):
将 AST 转换为渲染函数代码:with(this) { return _c('div', [_v(_s(message))]) }
组件化机制
Vue 组件本质是一个带有预定义选项的构造函数。组件实例化时:
- 合并选项(
mixins、extends)。 - 初始化生命周期、事件、渲染函数。
- 挂载到 DOM 后触发
mounted钩子。
异步更新队列
Vue 通过 nextTick 实现异步批量更新。数据变化后,更新任务会被推入队列,在下一个事件循环中统一执行,避免频繁重复渲染。
// 简化版 nextTick 实现
let callbacks = [];
function nextTick(cb) {
callbacks.push(cb);
if (!pending) {
pending = true;
Promise.resolve().then(flushCallbacks);
}
}
function flushCallbacks() {
callbacks.forEach(cb => cb());
callbacks = [];
pending = false;
}
关键源码模块
- 响应式:
core/observer/ - 虚拟 DOM:
core/vdom/ - 模板编译:
compiler/ - 组件系统:
core/instance/
通过以上机制,Vue 实现了高效的数据驱动视图更新,同时保持开发体验的简洁性。







