function Vue(options = {}) {
this.$options = options;
let data = this._data = this.$options.data;
observe(data);
for (let key in data) {
Object.defineProperty(this, key, {
configurable: true,
get() {
return this._data[key];
},
set(newVal) {
this._data[key] = newVal;
}
});
}
initComputed.call(this);
new Compile(options.el, this);
options.mounted.call(this);
}
function initComputed() {
let vm = this;
let computed = this.$options.computed;
Object.keys(computed).forEach(key => {
Object.defineProperty(vm, key, {
get: typeof computed[key] === 'function' ? computed[key] : computed[key].get,
set() {
}
});
});
}
function Observe(data) {
let dep = new Dep();
for (let key in data) {
let val = data[key];
observe(val);
Object.defineProperty(data, key, {
enumerable: true,
get() {
Dep.target && dep.addSub(Dep.target);
return val;
},
set(newVal) {
if (val === newVal) {
return;
}
val = newVal;
observe(newVal);
dep.notify();
}
});
}
}
function observe(data) {
if (!data || typeof data !== 'object') {
return;
}
return new Observe(data);
}
function Compile(el, vm) {
vm.$el = document.querySelector(el);
let fragment = document.createDocumentFragment();
while (child = vm.$el.firstChild) {
fragment.appendChild(child);
}
replace(fragment);
function replace(frag) {
Array.from(frag.childNodes).forEach(function (node) {
let txt = node.textContent;
let reg = /\{\{(.*?)\}\}/g;
if (node.nodeType === 3 && reg.test(txt)) {
const replaceTxt = () => {
node.textContent = txt.replace(reg, (matched, placeholder) => {
return placeholder.split('.').reduce((val, key) => {
return val[key];
}, vm);
});
}
replaceTxt();
txt.replace(reg, (matched, placeholder) => {
new Watcher(vm, placeholder, replaceTxt);
})
}
if (node.nodeType === 1) {
let nodeAttr = node.attributes;
Array.from(nodeAttr).forEach(attr => {
let name = attr.name;
let exp = attr.value;
if (name.includes('v-')) {
node.value = vm[exp];
}
new Watcher(vm, exp, function (newVal) {
node.value = newVal;
});
node.addEventListener('input', function (e) {
let newVal = e.target.value;
console.log(newVal);
vm[exp] = newVal;
});
});
}
if (node.childNodes && node.childNodes.length) {
replace(node);
}
});
}
vm.$el.appendChild(fragment);
}
function Dep() {
this.subs = [];
}
Dep.prototype.addSub = function (sub) {
this.subs.push(sub);
};
Dep.prototype.notify = function () {
this.subs.forEach(sub => sub.update());
};
function Watcher(vm, exp, fn) {
this.fn = fn;
this.vm = vm;
this.exp = exp;
Dep.target = this;
let val = vm;
let arr = exp.split('.');
arr.forEach(key => {
val = val[key];
});
Dep.target = null;
}
Watcher.prototype.update = function () {
let val = this.vm;
let arr = this.exp.split('.');
arr.forEach(key => {
val = val[key];
});
this.fn(val);
};