// html <body> <div id="app">
<input type="text" v-model="number">
<input type="text" v-model="num">
<input type="button" v-click="increment" value="加1">
<input type="button" v-click="increment" value="加2">
<h3 v-bind="number"></h3>
<h3 v-bind="num"></h3>
</div> </body>
// Instance of js vue window.onload = function () { var app = new Vue({ el: ' #app ' , data: { number: 0, num: 5 , }, methods: { increment: function () { this.number++; this.num++; }, } }) }
// constructor of vue function Vue(options) { this._init(options); } Vue.prototype._init = function (options) { this.$options = options; this.$el = document.querySelector(options.el); this.$data = options.data; this.$methods = options.methods; this._binding = {}; this._obverse(this.$data); this._complie(this.$el); } Vue.prototype._obverse = function (obj) { var _this = this for (let key in obj) { if (obj.hasOwnProperty(key)) { this._binding[key] = { _directives: [] }; let value = obj[key]; if (typeof value === 'object') { this._obverse(value); } let binding = this._binding[key]; Object.defineProperty(this.$data, key, { enumerable: true , // Whether the target property can be enumerated. true | false configurable: true , // Whether the target property can be deleted or whether the property can be modified again true | false get : function () { return value; }, set: function (newVal) { if (value !== newVal) { value = newVal; binding._directives.forEach(function (item) { item.update(); }) } } }) } } } Vue.prototype._complie = function (root) { var _this = this; var nodes = root.children; for (let i = 0; i < nodes.length; i++) { let node = nodes[i]; if (node.children.length) { _this._complie(node); } if (node.hasAttribute('v-click')) { node.onclick = (function () { var attrVal = nodes[i].getAttribute('v-click'); return _this.$methods[attrVal].bind(_this.$data); })(i); } if (node.hasAttribute('v-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) { node.addEventListener('input', (function() { var attrVal = node.getAttribute('v-model'); _this._binding[attrVal]._directives.push(new Watcher( 'input', node, _this, attrVal, 'value' )) return function () { _this.$data[attrVal] = nodes[key].value; } })()); } 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; // Instruction name, such as text node, the value is set to "text" this .el = el; // The DOM element corresponding to the instruction this .vm = vm; // The myVue instance to which the instruction belongs this .exp = exp; // The value corresponding to the instruction, this example is "number" this .attr = attr; // The bound attribute value, this example is "innerHTML" this.update(); } Watcher.prototype.update = function () { this.el[this.attr] = this.vm.$data[this.exp]; }