1. Vue 3 的响应式系统
// 1. 响应式核心 - Proxy 实现
function reactive(target) {
// 防止重复代理
if (isProxy(target)) {
return target;
}
const handler = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
// 依赖收集
track(target, key);
// 如果是对象,继续代理
return isObject(result) ? reactive(result) : result;
},
set(target, key, value, receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value, receiver);
// 如果值发生变化,触发更新
if (hasChanged(value, oldValue)) {
trigger(target, key);
}
return result;
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key);
const result = Reflect.deleteProperty(target, key);
if (hadKey && result) {
// 触发更新
trigger(target, key);
}
return result;
}
};
return new Proxy(target, handler);
}
// 2. 依赖收集
const targetMap = new WeakMap();
function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
// 3. 触发更新
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach(effect => {
if (effect.scheduler) {
effect.scheduler();
} else {
effect();
}
});
}
}
// 4. 副作用函数
let activeEffect = null;
function effect(fn, options = {}) {
const effectFn = () => {
try {
activeEffect = effectFn;
return fn();
} finally {
activeEffect = null;
}
};
if (!options.lazy) {
effectFn();
}
if (options.scheduler) {
effectFn.scheduler = options.scheduler;
}
return effectFn;
}
2. ref 的实现
class RefImpl {
private _value: any;
public dep: Set<any>;
public __v_isRef = true;
constructor(value) {
this._value = isObject(value) ? reactive(value) : value;
this.dep = new Set();
}
get value() {
track(this, 'value');
return this._value;
}
set value(newValue) {
if (hasChanged(newValue, this._value)) {
this._value = isObject(newValue) ? reactive(newValue) : newValue;
trigger(this, 'value');
}
}
}
function ref(value) {
return new RefImpl(value);
}
3. computed 的实现
class ComputedRefImpl {
private _getter: () => any;
private _dirty = true;
private _value: any;
private effect: any;
constructor(getter) {
this._getter = getter;
this.effect = effect(getter, {
lazy: true,
scheduler: () => {
if (!this._dirty) {
this._dirty = true;
trigger(this, 'value');
}
}
});
}
get value() {
if (this._dirty) {
this._value = this.effect();
this._dirty = false;
}
track(this, 'value');
return this._value;
}
}
function computed(getter) {
return new ComputedRefImpl(getter);
}
4. 实际应用示例
<template>
<div>
<input v-model="message" />
<p>Message: {{ message }}</p>
<p>Reversed: {{ reversedMessage }}</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
// 响应式数据
const message = ref('Hello Vue!')
// 计算属性
const reversedMessage = computed(() => {
return message.value.split('').reverse().join('')
})
// 监听变化
watch(message, (newValue, oldValue) => {
console.log('Message changed:', newValue)
})
</script>
5. v-model 的实现原理
// 简化版的 v-model 指令实现
const vModelDirective = {
mounted(el, binding, vnode) {
el.addEventListener('input', e => {
binding.value = e.target.value
})
effect(() => {
el.value = binding.value
})
}
}
// 编译后的模板
function render() {
return h('input', {
value: message.value,
onInput: e => (message.value = e.target.value)
})
}
6. 批量更新机制
// 异步更新队列
const queue = new Set()
let isFlushing = false
const p = Promise.resolve()
function queueJob(job) {
queue.add(job)
if (!isFlushing) {
isFlushing = true
p.then(() => {
try {
queue.forEach(job => job())
} finally {
isFlushing = false
queue.clear()
}
})
}
}
// 在 trigger 中使用
function trigger(target, key) {
const deps = getDeps(target, key)
const effects = new Set()
deps.forEach(dep => {
dep.forEach(effect => {
if (effect !== activeEffect) {
effects.add(effect)
}
})
})
effects.forEach(effect => {
if (effect.scheduler) {
effect.scheduler()
} else {
queueJob(effect)
}
})
}
7. 调试和性能优化
// 开发环境的调试辅助
function createReactiveObject(target, handler) {
if (process.env.NODE_ENV !== 'production') {
const proxy = new Proxy(target, {
...handler,
get(target, key, receiver) {
console.log(`Getting property "${key}"`)
return handler.get(target, key, receiver)
},
set(target, key, value, receiver) {
console.log(`Setting property "${key}" = ${value}`)
return handler.set(target, key, value, receiver)
}
})
return proxy
}
return new Proxy(target, handler)
}
// 性能优化:避免不必要的代理
function reactive(target) {
// 基础类型直接返回
if (!isObject(target)) {
return target
}
// 避免重复代理
if (isProxy(target)) {
return target
}
// 缓存已创建的代理
if (reactiveMap.has(target)) {
return reactiveMap.get(target)
}
const proxy = createReactiveObject(target, handler)
reactiveMap.set(target, proxy)
return proxy
}
要点:
- 响应式原理:
-
Vue 3 使用 Proxy 实现数据劫持
-
通过 track 收集依赖
-
通过 trigger 触发更新
-
支持深层响应式
- 依赖收集:
-
使用 WeakMap + Map + Set 的数据结构
-
在 getter 中收集依赖
-
建立数据和副作用的对应关系
- 更新机制:
-
异步批量更新
-
使用微任务队列
-
避免重复更新
- 性能优化:
-
缓存代理对象
-
避免不必要的依赖收集
-
使用 WeakMap 防止内存泄漏
- 实际应用:
-
v-model 的实现
-
computed 的实现
-
watch 的实现