Recent studies of the underlying principles of the Vue, wrote a simplified version of the Vue, you can run in support IE6, IE7, IE8 and other low-end browsers. Due to the low-end browser does not support the definition of object properties, so set the property does not support direct assignment, you need to call set methods virtual machine instance. Currently only implements a method based on follow-up continue to improve!
index.html
<!DOCTYPE html> <html> <head> <title>简化版Vue</title> <script> window.onerror=function(){ return true; } </script> </head> <body> <hr /> <div id="simpleVue"> <button v-on:click="copy">戳我</button> <div> <textarea v-model="name"></textarea> <div v-text="name"></div> </div> <div> <select v-model="name"> <option value="name1" selected>name1</option> <option value="name2">name2</option> <option value="name3">name3</option> </select> </div> <hr> <button v-on:click="show">显示/隐藏</button> <div v-if="isShow"> <input type="text" style="width: 300px" v-model="webSite"> <div v-text="webSite"></div> </div> </div> <script src="vmm.js"></script> <script> var vm = new VMM({ el: '#simpleVue', data: { name: '测试', webSite: 'https://github.com/steezer', isShow: true }, methods: { copy: function(){ vm.set('name', this.name +'测试'); }, show: function(){ vm.set('isShow', !this.isShow); } } }); </script> </body> </html>
vmm.js
function the VMM (Options) { / * * Change * subscriber related data attribute values configured to receive a notification to update the view * * @param {Object} VM virtual machine object * @param {HTMLElement} el Node Node * @param {String} attr attribute name * @param {Object} val attribute value * / function Watcher (VM, EL, attr, Val) { the this .vm = VM; the this .el = EL; the this .attr = attr; the this .val = Val; / * * * the new data received in the view update * / the this .Update = function () { IF ( the this .vm $ Data [. the this .val] === to true ) { the this .el.style.display = 'Block' ; } the else IF ( the this .vm $ Data [. the this .val] === to false ) { this .el.style.display = 'none' ; } the else { this .el [ this .attr] = this .vm $ Data [. this .val]; } } // update the subscriber at the time of initialization view this.update(); } /** * 获取对象 * * @param {Object|String} id * @returns Object */ function getElem(id){ if(typeof(id)=='object'){ return id; } var target=id+'', prefix=target.substr(0,1), target=target.substr(1); if(prefix=='#'){ return document.getElementById(target); } if(prefix=='.'){ return document.getElementsByClassName(target); } return document.getElementsByTagName(target); } function getAttr(elem, name) { var node = elem.getAttributeNode(name); if (node && node.specified) { return node.nodeValue; } else { return undefined; } } function addEvent(node, type, handle){ if(document.addEventListener){ node.addEventListener(type, handle, false); }else{ node.attachEvent('on'+type, function(){ handle.call(node, arguments); }); }; } this.$el = getElem(options.el); this.$data = options.data; this.$methods = options.methods; this.oWatcherObj = {}; // 获取属性 this.get=function(key){ return this.$data[key]; } // 设置属性 this.set=function(key, newVal){ var value=this.$data[key]; if (newVal !== value) { this.$data[key] = newVal; if(typeof(this.oWatcherObj[key])!="undefined"){ var watchers=this.oWatcherObj[key]; for(var i=0; i< watchers.length; i++){ watchers[i].update(); } } } } /** * 节点DOM解析器 */ this.compile=function(el) { var nodes = el.children, $this=this, addWatcher=function(node, attr, val){ if(typeof($this.oWatcherObj[val])=='undefined'){ $this.oWatcherObj[val]=[]; } $this.oWatcherObj[val].push(new Watcher($this, node, attr, val)); }; // iteration all sibling nodes var values = []; for ( var K in EL) { values.push (K) } for ( var I = 0; I <nodes.length; I ++ ) { var Node = Nodes [I], Val; IF (node.children.length> 0 ) { the this .compile (node); // recursive all child nodes } // click event Val = getAttr (node, 'V-ON: the click' ); IF (Val) { IF(typeof($this.$methods[val])=="function"){ addEvent(node, 'click', (function(val){ return function(e){ $this.$methods[val].call($this.$data, e); } })(val)); } } // IF指令 val=getAttr(node, 'v-if'); if (val) { addWatcher(node, "", val); } // Model val=getAttr(node, 'v-model'); if (val) { var event=node.tagName.match(/select/i) ? 'change' : ('oninput' in node ? 'input' : 'propertychange'); addWatcher(node, "value", val); addEvent(node, event, (function(i, val){ return function(e){ $this.set(val, nodes[i].value); } })(i, val)); } // Text val=getAttr(node, 'v-text'); if (val) { addWatcher(node, "innerText", val); } // Html val=getAttr(node, 'v-html'); if (val) { addWatcher(node, "innerHTML", val); } } } // 节点解析 this.compile(this.$el); }