// 观察者
class Watcher {
constructor(obj, key, cb) {
this.obj = obj;
this.key = key;
this.cb = cb;
Dep.target = this;
this.value = obj[key]; // 触发 getter
Dep.target = null;
}
update() {
const newValue = this.obj[this.key];
if (newValue !== this.value) {
this.value = newValue;
this.cb(newValue);
}
}
}
// 依赖
class Dep {
constructor() {
this.subscribers = [];
}
addSub(sub) {
this.subscribers.push(sub);
}
notify() {
this.subscribers.forEach(sub => sub.update());
}
}
// 数据劫持 + 收集依赖
function defineReactive(obj, key) {
let value = obj[key];
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.addSub(Dep.target);
console.log(2);
}
return value;
},
set(newValue) {
value = newValue;
dep.notify();
}
});
}
// 数据劫持
function observe(obj) {
if (!obj || typeof obj !== 'object') {
return;
}
Object.keys(obj).forEach(key => {
defineReactive(obj, key);
});
}
// Vue 实现
class Vue {
constructor(options) {
this.$data = options.data;
observe(this.$data);
// 模拟编译和挂载
const input = document.getElementById('input');
const text = document.getElementById('text');
new Watcher(this.$data, 'message', (value) => {
text.textContent = value;
console.log(1);
});
input.addEventListener('input', (event) => {
this.$data.message = event.target.value;
});
input.value = this.$data.message;
text.textContent = this.$data.message;
}
}
// 使用
new Vue({
data: {
message: ''
}
});