html部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="message">{{message}}
<div>{{message}}</div>
</div>
</body>
</html>
响应式原理部分
class Vue {
constructor(options) {
//1.保存数据
this.$options = options;
this.$data = options.data;
this.$el = options.el;
//2.将data添加到响应式系统中
new Observer(this.$data);
//3.代理this.$data的数据
Object.keys(this.$data).forEach(key => {
this._proxy(key);
})
//4.处理el
new Complier(this.$el, this);
}
_proxy(key) {
Object.defineProperty(this, key, {
configurable: true,
enumerable: true,
set(newValue) {
this.$data[key] = newValue;
},
get() {
return this.$data[key];
}
})
}
}
class Observer {
constructor(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(newValue) {
if (newValue === val) {
return;
}
val = newValue;
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 Complier {
constructor(el, vm) {
this.el = document.querySelector(el);
this.vm = vm;
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) {
if (node.nodeType === 1) {
const attrs = node.attributes;
if (attrs.hasOwnProperty('v-model')) {
const name = attrs['v-model'].nodeValue;
node.addEventListener('input', e => {
this.vm[name] = e.target.value;
})
}
}
if (node.nodeType === 3) {
console.log(reg.test(node.nodeValue));
if (reg.test(node.nodeValue)) {
const name = RegExp.$1.trim();
new Watcher(node, name, this.vm)
}
}
}
}
vue实例部分
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
name:'Tom'
}
})