回顾下双向绑定的原理~,此段代码仅为复习笔记.简书不倒,知识永存!
<div id="app">
<input type="text" v-model="message" />
{{message}}
</div>
<script>
class ThunderVue {
constructor(options) {
//保存数据
this.$options = options;
this.$data = options.data;
this.$el = options.el;
//将data添加到响应式系统当中
new Observer(this.$data);
//代理this.$data中的数据
Object.keys(this.$data).forEach((key) => {
this._proxy(key);
});
//处理el
new Compiler(this.$el, this);
}
_proxy(key) {
Object.defineProperty(this, key, {
configurable: true,
enumerable: true,
set(nv) {
this.$data[key] = nv;
},
get() {
return this.$data[key];
},
});
}
}
class Observer {
//观察者
constructor(data) {
if (
!data ||
!Object.prototype.toString.call(data).indexOf('Object')
) {
throw new Error('data错误');
}
this.data = data;
Object.keys(data).forEach((key) => {
this.defineReactive(this.data, key, data[key]);
});
}
defineReactive(data, key, val) {
const dep = new Dep();
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
if (Dep.target) {
dep.addSub(Dep.target);
}
return val;
},
set(nv) {
if (nv === val) {
return;
}
console.log(nv, val);
val = nv;
dep.notify();
},
});
}
}
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach((sub) => {
sub.update();
});
}
}
class Watcher {
constructor(node, name, vm) {
this.node = node;
this.name = name;
this.vm = vm;
Dep.target = this;
this.update();
Dep.target = null;
}
update() {
this.node.nodeValue = this.vm[this.name];
}
}
const reg = /\{\{(.+)\}\}/;
class Compiler {
constructor(el, vm) {
this.el = document.querySelector(el);
this.vm = vm; //指的是Vue实例
this.frag = this._createFragment();
this.el.appendChild(this.frag);
}
_createFragment() {
const frag = document.createDocumentFragment();
let child;
while ((child = this.el.firstChild)) {
this._compile(child);
frag.appendChild(child);
}
return frag;
}
_compile(node) {
console.log(node);
if (node.nodeType === 1) {
//标签节点
const attrs = node.attributes; //
if (attrs.hasOwnProperty('v-model')) {
const name = attrs['v-model'].nodeValue;
console.log(name);
node.addEventListener('input', (e) => {
this.vm[name] = e.target.value;
});
}
}
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
console.log(RegExp.$1);
const name = RegExp.$1.trim();
new Watcher(node, name, this.vm);
}
}
}
}
</script>
<script>
const app = new ThunderVue({
el: '#app',
data: {
message: 'thunder',
},
});
</script>
图解:
师承coderwhy,预想善其事,必先利其器;了解真相才是获取真正的自由;