vue2实现响应式原理
时间: 2023-09-11 14:05:01 浏览: 52
Vue2 的响应式原理主要是基于 Object.defineProperty() 函数实现的。
Vue2 通过对数据对象的访问拦截,在访问数据对象的时候自动触发依赖收集和派发更新操作。具体实现步骤如下:
1. 遍历数据对象的所有属性,为每个属性创建一个独立的依赖收集器(Dep)对象。
2. 对访问数据对象的方法进行重写,使其在访问数据对象的属性时,将当前正在执行的 Watcher 对象添加到该属性对应的依赖收集器中。
3. 对修改数据对象的方法进行重写,使其在修改数据对象的属性时,触发该属性对应的依赖收集器对象的派发更新操作,通知所有依赖于该属性的 Watcher 对象更新视图。
具体实现代码如下:
```javascript
function defineReactive(obj, key, val) {
const dep = new Dep(); // 创建依赖收集器对象
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
if (Dep.target) {
dep.depend(); // 将当前 Watcher 对象添加到依赖收集器中
}
return val;
},
set: function reactiveSetter(newVal) {
if (newVal === val) {
return;
}
val = newVal;
dep.notify(); // 触发依赖收集器对象的派发更新操作,通知所有 Watcher 对象更新视图
}
});
}
function observe(obj) {
if (!obj || typeof obj !== 'object') {
return;
}
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key]);
});
}
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
}
get() {
Dep.target = this;
const value = this.getter.call(this.vm, this.vm);
Dep.target = null;
return value;
}
update() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue);
}
}
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
removeSub(sub) {
remove(this.subs, sub);
}
depend() {
if (Dep.target) {
Dep.target.addDep(this);
}
}
notify() {
const subs = this.subs.slice();
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update();
}
}
}
Dep.target = null;
const targetStack = [];
function pushTarget(target) {
targetStack.push(target);
Dep.target = target;
}
function popTarget() {
targetStack.pop();
Dep.target = targetStack[targetStack.length - 1];
}
function parsePath(path) {
const segments = path.split('.');
return function(obj) {
for (let i = 0; i < segments.length; i++) {
if (!obj) {
return;
}
obj = obj[segments[i]];
}
return obj;
};
}
function remove(arr, item) {
if (arr.length) {
const index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1);
}
}
}
class Vue {
constructor(options) {
this._data = options.data;
observe(this._data);
this._watchers = [];
this._initWatchers(options);
}
_initWatchers(options) {
const watchers = options.watch || {};
for (let key in watchers) {
const handler = watchers[key];
this.$watch(key, handler);
}
}
$watch(expOrFn, cb) {
const watcher = new Watcher(this, expOrFn, cb);
this._watchers.push(watcher);
return function unwatch() {
watcher.teardown();
};
}
}
```
上述代码中,defineReactive 函数用于将一个属性变成响应式的,observe 函数用于遍历数据对象的所有属性并调用 defineReactive 函数,Watcher 类用于封装一个 Watcher 对象,Dep 类用于封装一个依赖收集器对象。Vue 类则用于封装一个 Vue 实例,实现了 $watch 方法用于监听数据的变化,并创建 Watcher 对象。在 Watcher 对象的构造函数中,会调用 parsePath 函数将表达式字符串转换成一个函数,然后调用该函数获取数据对象的值,并触发依赖收集。在数据对象的属性被修改时,会触发该属性对应的依赖收集器对象的派发更新操作,通知所有 Watcher 对象更新视图。