vue源码实现分析
Vue 源码实现分析
Vue.js 是一个渐进式 JavaScript 框架,其源码设计精巧,模块化清晰。以下从核心模块、响应式系统、虚拟 DOM 和编译器等角度分析其实现原理。
响应式系统
Vue 的响应式系统基于 Object.defineProperty(Vue 2)或 Proxy(Vue 3)实现数据劫持。通过劫持数据的读取和修改,触发依赖收集和派发更新。
-
依赖收集:
在getter中调用dep.depend(),将当前 Watcher 添加到依赖列表。
每个响应式数据关联一个Dep实例,用于管理依赖。 -
派发更新:
在setter中调用dep.notify(),通知所有依赖的 Watcher 执行更新。
Watcher 通过调度队列(如queueWatcher)实现异步批量更新。
示例代码(Vue 2 响应式核心):
function defineReactive(obj, key) {
const dep = new Dep();
let val = obj[key];
Object.defineProperty(obj, key, {
get() {
if (Dep.target) dep.depend();
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify();
}
});
}
虚拟 DOM 与 Diff 算法
Vue 通过虚拟 DOM 优化渲染性能,核心流程包括:
-
虚拟节点(VNode):
用 JavaScript 对象描述 DOM 节点,包含标签名、属性、子节点等信息。 -
Diff 算法:
对比新旧 VNode 树,最小化 DOM 操作。
采用同层比较策略,通过patch函数递归处理节点更新。
对子节点列表采用“双端比较”算法(Vue 2)或“快速路径”优化(Vue 3)。
示例 Diff 核心逻辑:

function updateChildren(parentElm, oldCh, newCh) {
let oldStartIdx = 0, newStartIdx = 0;
let oldEndIdx = oldCh.length - 1, newEndIdx = newCh.length - 1;
// 双指针比较逻辑...
}
模板编译
Vue 将模板编译为渲染函数,流程分为三步:
-
解析(Parse):
将模板字符串转换为 AST(抽象语法树),处理指令、插值等语法。 -
优化(Optimize):
标记静态节点,减少 Diff 过程中的比较开销。 -
生成(Generate):
将 AST 转换为可执行的渲染函数代码字符串。
示例编译输出:

// 模板: <div>{{ message }}</div>
function render() {
return _c('div', [_v(_s(message))]);
}
组件系统
Vue 组件基于原型继承实现,核心机制包括:
-
组件定义:
通过Vue.extend或options对象定义组件配置(如data、methods)。 -
生命周期管理:
在特定阶段(如created、mounted)触发钩子函数,由callHook方法调用。 -
父子通信:
props通过响应式代理实现父到子数据传递;$emit通过事件中心($on/$off)实现子到父通信。
异步更新队列
Vue 通过 nextTick 实现异步批量更新,优化性能:
- 使用微任务(如
Promise.then)或宏任务(如setTimeout)调度更新。 - 通过
queueWatcher将同一事件循环内的 Watcher 去重后批量执行。
示例 nextTick 实现:
let callbacks = [];
function nextTick(cb) {
callbacks.push(cb);
if (!pending) {
pending = true;
Promise.resolve().then(flushCallbacks);
}
}
function flushCallbacks() {
callbacks.forEach(cb => cb());
}
关键设计模式
- 观察者模式:Watcher 订阅 Dep,数据变化时触发更新。
- 发布-订阅模式:事件总线(
$emit/$on)处理组件通信。 - 工厂模式:
createElement动态生成 VNode。
通过以上分析,Vue 源码的实现充分体现了高效、可扩展的设计理念,其模块化架构和算法优化值得深入学习。






