class Vue {
constructor(options) {
this.$data = options.data;
// 进行数据劫持
this.Observe(options.data);
// 编译模版
this.Compile(options.el);
}
Observe(data) {
if (!data || typeof data !== 'object') {
return;
}
const dep = new Dep();
Object.keys(data).forEach(key => {
let _that = this;
let value = data[key];
this.Observe(value);
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
// 收集依赖
Dep.target && dep.addSub(Dep.target);
return value;
},
set(newVal) {
value = newVal;
_that.Observe(newVal);
dep.notify();
}
});
})
}
Compile(el) {
// const vm = this.$el;
this.$el = document.querySelector(el);
const fragment = document.createDocumentFragment();
let childNode;
while (childNode = this.$el.firstChild) {
fragment.appendChild(childNode);
}
this.replace(fragment);
this.$el.appendChild(fragment);
}
replace(node) {
// 进行替换了
const regMustache = /\{\{\s*(\S+)\s*\}\}/;
// 文本子节点, 就是最里层了
if (node.nodeType === 3) {
const text = node.textContent;
// console.log(text);
const execResult = regMustache.exec(text);
console.log(execResult);
if (execResult) {
const value = execResult[1].split('.').reduce((newObj, key) => newObj[key], this.$data);
node.textContent = text.replace(regMustache, value);
// 创建 watcher 实例
console.log(1111);
new Watcher(this, execResult[1], (newValue) => {
node.textContent = text.replace(regMustache, newValue);
});
}
return;
}
if (node.nodeType === 1 && node.tagName.toUpperCase() == 'INPUT') {
const attrs = Array.from(node.attributes);
const findResult = attrs.find(attr => attr.name === 'v-model');
if (findResult) {
const expStr = findResult.value;
const value = expStr.split('.').reduce((newObj, key) => newObj[key], this.$data);
node.value = value;
// 创建 watcher 实例
new Watcher(this, expStr, (newValue) => {
node.value = newValue;
})
node.addEventListener('input', (e) => {
const keyArr = expStr.split('.');
const obj = keyArr.splice(0, keyArr.length - 1).reduce((newObj, key) => newObj[key], this.$data);
obj[keyArr[keyArr.length - 1]] = e.target.value;
})
}
}
// console.dir(node)
node.childNodes.forEach(child => this.replace(child));
}
}
class Dep {
constructor() {
this.subs = [];
}
// 收集依赖
addSub(watcher) {
this.subs.push(watcher);
}
// 通知
notify() {
this.subs.forEach(watcher => watcher.update());
}
}
class Watcher {
constructor(vm, key, callback) {
this.vm = vm;
this.key = key;
this.callback = callback;
Dep.target = this;
key.split('.').reduce((newObj, key) => newObj[key], vm.$data);
Dep.target = null;
}
update() {
const value = this.key.split('.').reduce((newObj, k) => newObj[k], this.vm.$data);
this.callback(value);
}
}
|