console
function myVue(options) {
this._init(options);
}
myVue.prototype._init = function (options) {
this.$options = options;
this.$el = document.querySelector(options.el);
this.$data = options.data;
this.$methods = options.methods;
this._binding = {};
this._observe(this.$data);
this._compile(this.$el);
}
myVue.prototype._observe = function (obj) {
var _this = this;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
_this._binding[key] = {
_directives: []
};
var value = obj[key];
if (typeof value === 'object') {
_this._observe(value);
}
var binding = this._binding[key];
Object.defineProperty(_this.$data, key, {
enumerable: true,
configurable: true,
get: function () {
console.log(`获取${value}`);
return value;
},
set: function (newVal) {
console.log(`更新${newVal}`);
if (value !== newVal) {
value = newVal;
binding._directives.forEach(function (item) {
item.update();
})
}
}
})
}
}
}
myVue.prototype._compile = function (root) {
var _this = this;
var nodes = root.children;
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.children.length) {
this._compile(node);
}
if (node.hasAttribute('v-click')) {
node.onclick = (function () {
var attrVal = nodes[i].getAttribute('v-click');
return _this.$methods[attrVal].bind(_this.$data);
})();
}
if (node.hasAttribute('v-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) {
node.addEventListener('input', (function(key) {
var arrtVal = node.getAttribute('v-model');
_this._binding[arrtVal]._directives.push(new Watcher(
'input', node, _this, attrVal, 'value'
))
return function() {
_this.$data[attrVal] = nodes[key].value
}
})(i));
}
if (node.hasAttribute('v-bind')) {
var attrVal = node.getAttribute('v-bind');
_this._binding[attrVal]._directives.push(new Watcher(
'text', node, _this, attrVal, 'innerHTML'
))
}
}
}
function Watcher(name, el, vm, exp, attr) {
this.name = name;
this.el = el;
this.vm = vm;
this.exp = exp;
this.attr = attr;
this.update();
}
Watcher.prototype.update = function() {
this.el[this.attr] = this.vm.$data[this.exp];
}
window.onload = function() {
var app = new myVue({
el: '#app',
data: {
number: 0,
count: 0
},
methods: {
increment: function() {
this.number++;
},
incre: function() {
this.count++;
}
}
})
}
<div id="app">
<form>
<input type="text" v-model="number">
<button type="button" v-click="increment">增加</button>
</form>
<h3 v-bind="number"></h3>
<form>
<input type="text" v-model="count">
<button type="button" v-click="incre">增加</button>
</form>
<h3 v-bind="count"></h3>
</div>